Domain State Machines
Guard duplicated from ARCHITECTURE §11.6 + §15.2 — ARCHITECTURE wins on conflict.
State Machine Guards
Section titled “State Machine Guards”⚠️ SILENT DATA CORRUPTION: writing a status column directly (bypassing the transition check) lets an illegal transition through. State machines here are app-enforced — there is NO DB CHECK constraint backing them. The code is the only guard.
Universal rule
Section titled “Universal rule”- NEVER write a status/state column with a raw
.set({ status }). Go through the transition helper for that machine. - Terminal states are immutable — reject any transition out of a terminal state.
- Adding a state = update (1) the enum, (2) the allowed-transitions map, and
(3) every
switchover the machine. Use exhaustive switches (no silentdefault) so a new state fails to compile until handled.
Sesi — lesson_sessions.status (session_status enum)
Section titled “Sesi — lesson_sessions.status (session_status enum)”REQUESTED → APPROVED → IN_PROGRESS → COMPLETEDREQUESTED → REJECTED (terminal)APPROVED → CANCELLED | RESCHEDULED (terminal)IN_PROGRESS → NO_SHOW_STUDENT | NO_SHOW_TUTOR (terminal)- Initial:
REQUESTED. - Terminal:
COMPLETED,REJECTED,CANCELLED,RESCHEDULED,NO_SHOW_STUDENT,NO_SHOW_TUTOR. REQUESTED → APPROVEDcaptures the pricing snapshot — seedomain-pricing-snapshot.md.→ COMPLETED/→ NO_SHOW_STUDENTauto-creates settlements — seedomain-settlement.md.- Transitions live in the service layer (
@packages/servicesessions ops). Full spec: ARCHITECTURE §15.2.
AccountState — users.account_state
Section titled “AccountState — users.account_state”PENDING_INTERVIEW → APPROVED → ACTIVE → SUSPENDED → ARCHIVED- Allowed transitions are per
user_type— usecanTransition(user_type, from, to)frompackages/auth/src/state-machine.ts; throwInvalidStateTransitionErroron a bad transition. Never assume the DB will catch it. ARCHIVEDis terminal (no data deletion — audit retention).- Iter 1: all users start
ACTIVE;PENDING_INTERVIEW/APPROVEDidle (seeiter-boundaries.md). Full spec: ARCHITECTURE §11.6.
Other status enums (cross-ref)
Section titled “Other status enums (cross-ref)”billing_periods.status:OPEN → CLOSING → CLOSED → LOCKED—LOCKEDimmutable. Seedomain-billing-period.md.schedules.status:ACTIVE | PAUSED | ENDED.