Spawn a job per submission, then fire a transition that copies the submission into a Patient record.
Promote submissions into entity records
Submissions land in a quarantine zone by design: the
form-scoped tables have no FK path into entity_records, so a
malformed or hostile payload can't corrupt your operational
data. Promotion to an entity is an explicit FSM action —
PROMOTE_FORM_TO_ENTITY — that an operator fires by name. The
audit trail stays clean because every entity write has a
named transition behind it.
1. Create the patient entity kind
From the admin shell, open Entities:
- Type
patientin the "Entity kind" box. - Click Load. The records list is empty — that's exactly what you want. The kind is now registered; the FSM action you'll author below will populate it.
Leave the page. You don't need to seed a record by hand.
2. Design the Patient Intake Flow workflow
Open Workflows → New workflow. The FSM Designer opens as a React Flow canvas.
- Add two states:
receivedandtriaged. Click Set initial on thereceivednode. - Drag a transition from
receivedtotriaged. In the side panel, setevent_type = mark_triaged. No guard needed for the first run. - Name the workflow
Patient Intake Flow.
Don't save yet — the action wiring comes next.
3. Attach the PROMOTE_FORM_TO_ENTITY action
Still on the mark_triaged transition's side panel, click
Add action and pick PROMOTE_FORM_TO_ENTITY from the
catalog. Fill the payload template with:
{ "entity_name": "patient" }
That's the entire payload. When the operator fires
mark_triaged, the action will copy the submission attached
to the job into a fresh patient entity record.
4. Bind the workflow to the patient entity
In the workflow sidebar, find the Entity name field and
type patient. This binding is what lets entity annotations
light up the guard composer later, and it's what tells the
FSM Designer which kind to validate the promote action
against. With the binding in place the action's
entity_name payload is checked at save time, not at fire
time — a typo here surfaces immediately, not on the next
operator click.
5. Save the workflow
Click Save. The schema is written with is_active = true
and Patient Intake Flow shows up in the workflows list. The
mark_triaged transition now carries the
PROMOTE_FORM_TO_ENTITY action; the dry-run panel will let
you preview the entity write against any existing submission
before you fire it for real.
6. Wire Patient Intake to spawn jobs
Open Patient Intake in the Forms list, then open its detail
view. Find the Submit actions panel:
- In the Spawn job in schema dropdown, pick
Patient Intake Flow. - Confirm the Initial state shows
received(it should be the default — that's the state you marked initial above). - Leave the Link submission to job toggle on. This is the
bit that makes the
submission_id-less promote action work; the spawn writes the submission's id onto the new job so the action can resolve it back at fire time. - Save.
Every accepted submission from this point forward spawns a
fresh Patient Intake Flow job in received, with the
submission's processing_state set to attached.
Submissions accepted before this binding existed stay
pending and never auto-spawn — they're available for
manual triage from the submissions list.
┌──────────┐ mark_triaged ┌──────────┐
│ received │ ──────────────▶ │ triaged │
└──────────┘ action: └──────────┘
PROMOTE_FORM_TO_ENTITY
Verify it worked
Open the public URL of Patient Intake in an incognito
window. Fill the demographics, contact, and consent pages
from the earlier tutorials and submit.
Head to /admin/jobs. A new Patient Intake Flow job
appears in received within a second of the submit
returning. Click into it — the side panel shows the linked
submission id and the payload you just entered.
Click Mark triaged. Three things happen in one atomic step:
- The job advances from
receivedtotriaged. - The
PROMOTE_FORM_TO_ENTITYaction copies the submission's payload into a new record onentity_recordswith kindpatient. - The submission's
processing_stateflips fromattachedtopromotedand itsentity_record_idpoints at the new record.
Open Entities, type patient, and click Load. The
submitter's values show up as a fresh row. Discarded
submissions don't land here; every patient record you see
came from a mark_triaged an operator explicitly fired,
and the append-only event_log carries the full audit
trail of who fired which transition against which job.
Next
Continue with Prefill a form from an entity record.