State machines
Every persisted entity in Oversight has a small, explicit state machine. The transitions map directly onto API actions: a PATCH that violates a transition returns 409. UI controls render or hide based on the current state. Every transition writes an audit event.
Principal-compliance surface
Section titled “Principal-compliance surface”The navigation flow for principal-admin and principal-compliance-officer. Authentication is the only state transition that can throw the user back to SignedOut; everything else is navigation between persisted views.
stateDiagram-v2 [*] --> Authenticating Authenticating --> SignedOut: 401 Authenticating --> Dashboard: session ok SignedOut --> Authenticating: submit credentials
Dashboard --> Register Dashboard --> BreachQueue Dashboard --> Reviews Dashboard --> AnnualReviews Dashboard --> AuditLog Dashboard --> TenantSettings: principal-admin only
Register --> ArDetail ArDetail --> Register
BreachQueue --> BreachDetail BreachDetail --> NotifyFcaStepUp: principal-admin only NotifyFcaStepUp --> BreachDetail
Reviews --> ReviewWorkspace ReviewWorkspace --> Reviews
AnnualReviews --> AnnualReviewPacket AnnualReviewPacket --> SignOffStepUp: principal-admin only SignOffStepUp --> AnnualReviewPacket
Dashboard --> SignedOut: log out or expiryNotifyFcaStepUp and SignOffStepUp are short-lived states gated by step-up auth (re-enter password and TOTP). On success the action proceeds; on cancel or fail the user returns to the prior view.
AR-user surface
Section titled “AR-user surface”The navigation flow for ar-user. Scoped to one AR via session.arId. The persona switcher does not exist on this surface in production.
stateDiagram-v2 [*] --> Authenticating Authenticating --> SignedOut: 401 Authenticating --> Home: session ok
Home --> RequiredActions Home --> MIReturns Home --> Breaches Home --> FileReviews Home --> Profile
MIReturns --> MIReturnDraft MIReturnDraft --> MIReturnSubmitted MIReturnSubmitted --> MIReturns
Breaches --> BreachNew BreachNew --> BreachSubmitted BreachSubmitted --> Breaches
FileReviews --> FileReviewDetail FileReviewDetail --> ChallengeDraft: within 10 working days of complete ChallengeDraft --> FileReviewDetail
Home --> SignedOut: log out or expirySubmitted MI returns and breaches are immutable from the AR-user surface; subsequent state transitions happen on the principal-compliance surface.
AR lifecycle
Section titled “AR lifecycle”Triggered when a principal-admin completes the appointment wizard (/demo/principal/register/new). The thirty-day PS22/11 / SUP 12.7 window for FCA objection sits between PendingAppointment and Active; SUP 12.8 termination fires a similar thirty-day window before Terminated.
stateDiagram-v2 [*] --> PendingAppointment: appointment wizard submit PendingAppointment --> Active: PS22/11 30-day window elapsed, no FCA objection PendingAppointment --> Withdrawn: principal withdraws before active date Active --> UnderInvestigation: compliance opens investigation UnderInvestigation --> Active: investigation closes, no action UnderInvestigation --> Suspended: compliance suspends pending review Active --> Suspended: principal-admin suspend (SUP 12.8 notification) Suspended --> Active: principal-admin reinstates Suspended --> Terminated: principal-admin terminates Active --> Terminated: principal-admin terminates (SUP 12.8 30-day window) UnderInvestigation --> Terminated: terminate-for-cause Withdrawn --> [*] Terminated --> [*]Persisted ArStatus values are pending-appointment, active, suspended, under-investigation, terminated. Withdrawn is a transient pre-active state captured by setting deletedAt on the AR row before appointedOn is reached.
Transitions to Suspended and Terminated require step-up auth and write a SUP 12.8 notification audit record. Termination requires the principal-admin to type the AR’s trading name to confirm (the demo enforces this in the UI; production also requires step-up auth).
The pending-appointment → active transition is automatic and runs on a cron job that checks appointedOn <= now() for each pending-appointment record. No FCA-objection callback is automated in v1; the principal-admin is alerted seven days before the active date and can withdraw if a regulator objection arrives.
Breach lifecycle
Section titled “Breach lifecycle”Triggered when an AR-user files a breach via POST /api/breaches. The SUP 15 clock starts at awareAt. Material and significant breaches with customer impact actual-low or actual-high route through NotifiableToFca; the rest go directly into InRemediation.
stateDiagram-v2 [*] --> Reported Reported --> Triaged: principal opens Triaged --> Investigating: compliance assigns Investigating --> AssessingMateriality: facts captured AssessingMateriality --> NotifiableToFca: material or significant + actual customer impact AssessingMateriality --> InRemediation: not notifiable NotifiableToFca --> NotifiedFca: SUP 15 notification recorded (step-up) NotifiedFca --> InRemediation InRemediation --> Resolved Resolved --> Closed Closed --> [*]Persisted BreachStatus values (open, in-remediation, resolved, closed) are coarser than the diagram’s lifecycle states; the finer states (Triaged, Investigating, AssessingMateriality, NotifiableToFca, NotifiedFca) are derived from notifiedFcaAt, presence of an assignee, presence of a materiality assessment, and severity.
The deadline alerter cron job runs hourly and pages the principal-admin when a NotifiableToFca breach has fewer than 24 hours of notifyByAt remaining, with escalation to email and SMS. Past-due deadlines do not block notification submission; the audit chain captures the late status.
File-review lifecycle
Section titled “File-review lifecycle”A scheduled review against the AR’s vertical rubric (MCOB, ICOBS, or CONC). Created by compliance, scored against the rubric, completed (terminal for the principal side), optionally challenged by the AR within 10 working days.
stateDiagram-v2 [*] --> Scheduled Scheduled --> InProgress: reviewer opens InProgress --> AwaitingEvidence: AR-side evidence requested AwaitingEvidence --> InProgress: evidence provided InProgress --> Complete: complete (locks findings, recomputes AR score) Complete --> Challenged: AR raises within 10 working days Challenged --> InProgress: reviewer reopens Complete --> [*]Complete recomputes the AR’s risk score (see Risk-scoring). Challenged pauses retention; the review remains live until reopened-and-recompleted or the challenge is rejected (returns to Complete with a challenge note).
Annual-review lifecycle
Section titled “Annual-review lifecycle”The PS22/11 annual packet for one AR. Aggregates risk trajectory, breach summaries, file-review summaries, MI returns, conduct events. Sign-off is terminal and requires step-up auth.
stateDiagram-v2 [*] --> Draft Draft --> InReview: compliance submits for review InReview --> ChangesRequested: principal-admin requests edits ChangesRequested --> InReview: compliance resubmits InReview --> SignedOff: principal-admin signs (step-up) InReview --> Rejected: principal-admin rejects with notes Rejected --> Draft: compliance redrafts SignedOff --> [*]The cycleYear field anchors the packet to a calendar year. A new Draft is auto-created for each AR each year on a configurable date (default 1 January). SignedOff is immutable; corrections after sign-off go into the next year’s packet with a cross-reference.
Transition enforcement
Section titled “Transition enforcement”Every transition is enforced server-side. The handler:
- Loads the row inside the tenant-scoped transaction (RLS filters).
- Validates the requested transition against a
STATE_MACHINEconstant (a map offrom-> allowedto). - Validates any preconditions (e.g. step-up token present and unexpired for
notify-fca). - Updates the row with optimistic concurrency (
If-MatchonupdatedAt). - Writes an
AuditEventwith the action name (e.g."breach.notify-fca"). - Triggers any side effects (risk recompute, deadline alerter, FCA bundle generation).
Disallowed transitions return 409 with the current state in error.details.currentStatus. The UI mirrors the same STATE_MACHINE constant to render or hide controls; the server is the source of truth.