Requirements: Direct Email Send (Email Orders)
Purpose
Section titled “Purpose”Functional requirements for the front-end direct-email-send feature (PDEV-969).
These describe observable system behavior once implemented — not tasks,
coding style, or tests (those live in specification.md,
verification.md, and
implementation-changes.md). Rationale and
contract detail are in design.md; the codebase gap is in
ui-implementation-analysis.md.
Requirements
Section titled “Requirements”Capability toggle
Section titled “Capability toggle”- REQ-ES-001 — When the active tenant has an
EmailConfigurationin Operational state whoseidentity.sendingDomainSlugcontains thePROCUREMENT_EMAIL_SLUG_TOKEN("procurement"), the Email Order composer presents the full direct-send form. Otherwise it presents the restricted copy-only form (DQ-001). - REQ-ES-002 — The toggle is resolved on composer open via the BFF
config-statusroute (a quickconfiguration/query); it is not cached for the initial implementation (neither SPA nor BFF). If caching is ever needed it lives in the BFF route, never the SPA (DQ-002, revised). A failed lookup resolves to not enabled (restricted form). - REQ-ES-003 — In the restricted form there is no Send action; Copy to clipboard is the primary action, and the UI explains that direct send is unavailable (provisioning tracked by PDEV-971).
Composition
Section titled “Composition”- REQ-ES-010 — In the full form the user can edit: To, Cc, From recipients (chip fields); Subject; greeting; introduction line; each line item’s quantity, unit price, and per-line Notes (REQ-ES-062); an optional order-wide note; and the sign-off.
- REQ-ES-011 — For V1, To starts empty with a placeholder cue, and Cc is seeded with the logged-in user’s email (self-CC, DQ-012); From defaults to the same address. Pre-population of recipients from supplier data is out of scope (PDEV-977).
- REQ-ES-012 — Subject is editable, defaulting to
Order for {supplier} — {MMM d, yyyy}in theen-USlocale (DQ-003). - REQ-ES-013 — The UI From value is sent as the message Reply-To
(
replyToEmail); the actual From is fixed by the configuration’s sender. The field label remains “From” (DQ-004). - REQ-ES-014 — Revert all restores every field to its default and is shown only when at least one field has diverged. ⌘Z / Ctrl+Z undoes the most recent recipient change.
- REQ-ES-015 — An empty note contributes nothing to the sent or copied output; a non-empty note appears under a “Notes” heading.
- REQ-ES-020 — Send sends the format of the active Body preview (HTML Preview → HTML, Plain Text Preview → plain text); the Send split button’s menu offers Direct Send and Open in email (DQ-013/DQ-014, revising DQ-011). Send is enabled only in a preview mode and fires on ⌘↵ / Ctrl+↵.
- REQ-ES-021 — An HTML send populates
htmlBody(with a plain-texttextBodyalternate); a plain-text send populatestextBodyonly. - REQ-ES-022 — The send is performed server-side via
POST /v1/shop-access/email/jobwith requiredX-Tenant-Id(from the session) and a client-mintedIdempotency-Keythat is stable across retries of one send attempt (DQ-007). The send is idempotent on that key. - REQ-ES-023 — The request carries
configurationEId(from the cached toggle),recipients { to, cc, bcc: [] },subject, the body per the chosen format,replyToEmail, andattachments: [](DQ-009). - REQ-ES-024 — On a successful send the selected order-queue cards are
accepted (the existing
event/accept→markItemStale→ refresh → close flow); on failure no card is accepted and the user sees an actionable error.
Copy (unchanged)
Section titled “Copy (unchanged)”- REQ-ES-030 — Copy to clipboard writes both a rich-HTML
(
text/html) and a plain-text (text/plain) representation of the body to the clipboard, matching today’sEmailPanel(REQ parity, DQ-011).
Validation & security
Section titled “Validation & security”- REQ-ES-040 — Before any send the front-end validates: ≥ 1 To address; all To/Cc/Reply-To addresses RFC-valid; non-empty subject; and no CR/LF or control characters in addresses, subject, or Reply-To. A failure blocks the send and surfaces a specific error (DQ-006).
- REQ-ES-041 — User-entered content is HTML-escaped at compose time, and
composition runs in the BFF via the shared
compose-email-htmlutil (DQ-020): the SPA sends structured content and uses the same util only for live preview; the BFF composes the authoritative body. This keeps the sent body structurally safe (DQ-006). - REQ-ES-042 — The shared BFF send route runs the composed
htmlBodythroughsanitize-html(allow-list: safe formatting tags;http/https/mailtolinks only; no images; no event handlers/<script>/<style>/<iframe>) and sends the sanitized result — defense-in-depth over composition’s escaping; no400-reject (DQ-010, revised R7). Backend-side hardening is tracked by PDEV-976. - REQ-ES-043 — The BFF send/config routes never log recipients or body content (extends the no-header-logging guardrail).
Outcomes
Section titled “Outcomes”- REQ-ES-050 — Send and Copy outcomes are confirmed with a toast; the Send toast names the format (e.g. “Email sent (HTML)”). Backend error states (not-sendable, suppressed recipient, validation) are surfaced as actionable messages rather than failing opaquely.
Composer ergonomics (stakeholder review — Round 5)
Section titled “Composer ergonomics (stakeholder review — Round 5)”- REQ-ES-060 — Reusable shell (DQ-016). The composer is decomposed so the
recipient fields, panel shell, Body view toggle, and send/format/Open-in-email
controls are reusable by other email features (e.g. invitations); the Body
content is the feature-specific slot. Reuse candidates follow the
ui-implementation-analysis.md§3 procedure and the ux-prototype promotion ticket. - REQ-ES-061 — Grid-consistent inline edit (DQ-017). Editable fields use the AG-grid inline-edit pattern (click the value to edit, hover highlight, Enter commit / Esc cancel) — no pencil-badge affordance — matching Items / Vendor / PO-Lite. Per-field revert and global Revert all / ⌘Z are retained.
- REQ-ES-062 — Per-line Notes (DQ-018). The items table has an editable
per-line Notes column for vendor specs, rendered into both the HTML body
(column) and the plain-text body (indented
Note:sub-line). The order-wide global Note field is retained. - REQ-ES-063 — Last format = session default (DQ-019). The chosen send format (HTML vs plain text) persists as the session default: after the first send the composer opens on the last-used preview rather than resetting to Compose. Client-only session state; no backend.
Out of scope
Section titled “Out of scope”- Recipient pre-population from supplier data (separate ticket).
- Authorization/permission gating of the send action (handled separately).
- Per-send From override / multi-From (PDEV-903), attachments and BCC, PO-Line order emails (PDEV-970), and provisioning configurations (PDEV-971).
Copyright: © Arda Systems 2025-2026, All rights reserved