think
16px
820px

"Assign number" as a workflow step — design spec

Goal: numbering becomes a first-class step inside a correspondence workflow, assigned to a
registrar (TU), so one chain can carry a letter from draft to sent without the creator manually
bridging between "approved" and "run the seal chain".

The flow question, answered

Recommended order: draft → approve → NUMBER → sign/e-Meterai/e-Stamp → mark sent.

Why this order and not number-first:

  1. Approval before numbering. Numbers are a gapless legal ledger. If drafts are numbered
    before review, every rejected draft burns a number (void rows pollute the register). Standard
    Indonesian tata-naskah practice numbers at the moment of official issuance — after the
    content is approved.
  2. Numbering before sealing — hard technical constraint. The number/date are merge fields
    ({{NOMOR}}, {{TANGGAL}}) rendered INTO the PDF that gets sealed. Sealing first would sign a
    PDF without its number; re-rendering after numbering would break the signatures' ByteRange.
    This is why guardLetterWorkflowStart blocks seal chains on un-numbered letters today.
  3. Send last, explicit (the terminal lock — already shipped).

Today the user must know this order and manually click "Assign number" between two separate
workflows. The guidance strip (shipped) tells them; the number step automates it. Both
orders stay possible for simple letters (a no-approval letter can still be numbered directly
from draft — unchanged).

Design

Engine

  • New step kind number alongside approve/sign/meterai/stamp. Letter subjects only.
  • Assignee: a position or named user — the registrar. Their inbox task reads
    "Assign the official number" with the letter deep-link.
  • Completing the task runs the existing AssignNumber path (allocation + merge-field render +
    status→numbered) with task-holder authorization: holding the pending number task IS the
    authority (a new engine-scoped completion, not the creator-gated public endpoint). The task UI
    reuses the existing AssignNumberModal (scheme picker + live preview).
  • Scheme choice: the definition may pin a scheme_code; if unset, the registrar picks in the
    modal at completion time (default). No new storage beyond the step-config JSON.

Validation (start-time, since definitions are subject-agnostic)

  • A definition containing a number step can only START over a letter subject.
  • Letter already numbered + chain contains number → 409 (remove the step or run seal-only).
  • Chain contains seal steps with NO preceding number step → letter must already be numbered
    (existing guard, unchanged).
  • number step ordering: must come before any seal step in the chain (definition-save check).

Reject / cancel semantics

  • Reject AT the number step → letter stays approved; nothing to void (no number allocated).
  • Reject AFTER numbering (e.g. at a sign step) → seals void as today; the number stays
    numbers are never un-assigned (gapless ledger). The letter remains numbered.

Status reflection

  • Approve steps still flip draft→in_review at start (shipped). The number step's completion
    sets numbered (via AssignNumber). ReflectApprovalState's in_review SQL guard naturally stops
    touching the letter after that. No new reflection logic.

UI

  • Builder palette gains "Assign number" (with a "letters only" hint; start-time validation
    enforces it).
  • Inbox/task row + letter task banner render the number task with an "Assign number" button
    → AssignNumberModal → engine completion endpoint.
  • Preset: ship one built-in definition "Full correspondence flow" (Approve → Assign number →
    Sign) surfaced in the letter Start-workflow picker, so the recommended order is one click.

Out of scope (v1)

  • Un-numbering / renumbering. Number steps for documents. Per-step SLA changes.

Effort

Engine (kind + validation + completion) ~1.5d · FE (palette, task UI, preset) ~1d · e2e ~0.5d.