Skip to content

form-draft

Per-user, per-tenant working copy of an in-progress form, saved BEFORE the real domain entity exists. Owns one event-sourced entity, form-draft (read_form_drafts), keyed by a caller-assigned draftKey (typically screenId + optional hostEntityId), unique per (tenant, owner, draftKey). save upserts the draft blob ({ values, stepIndex, savedAt } — savedAt stamped server-side), discard deletes it (called once the real submit succeeds), get resumes it, list finds a user’s open drafts for a given screenId (draftKey prefix match) — the fallback when a client-generated draftId is lost. Ownership is enforced by a per-row owner filter in every handler, not by roles — a foreign user’s save/discard/get/list for someone else’s draftKey never sees or touches that row. Never holds anything that already lives in a domain stream; the consuming app is responsible for discarding once the domain write succeeds. A daily cron job hard-deletes drafts past a configurable retention window (form-draft:config:retention-days, SystemAdmin-writable, default 30 days).

What this feature can use (optional, top) and the write commands this feature provides (Provides, bottom).

flowchart TB
  n_form_draft["form-draft"]
  subgraph how_reqs["Requires / optional"]
    n_config["config"]
  end
  subgraph how_provides["Provides"]
    n_cmd_form_draft_write_discard(["discard"])
    n_cmd_form_draft_write_save(["save"])
  end
  n_config -.->|optional| n_form_draft
  n_form_draft --> n_cmd_form_draft_write_discard
  n_form_draft --> n_cmd_form_draft_write_save

Provides — write commands this feature registers (dispatch them through the command bus):

  • Requires: none
  • Optional: config
  • Activation: always on (not toggleable)

Per-tenant config keys, set via the tenant-admin UI or a seed. 🔒 = encrypted at rest.

KeyTypeDefaultScopeWho can writeWho can read
retention-daysnumber (≥ 1)30systemSystemAdminTenantAdmin, Admin, SystemAdmin