Demand
What it is
A demand plan states the staffing need for one date, at one terminal, for one shift: how many people, with which skill, at which node. Planners build these plans as a matrix and move them through a short lifecycle from draft to agreed.
Why it exists
Before anyone can be rostered, the need has to be written down precisely and agreed. The demand plan is that statement of need — the target an allocation run fills.
Key concepts & terms
- Demand plan — the need for exactly one (date × terminal × shift) combination; its code is derived from that tuple.
- Demand line — a single row of need within a plan: a node, a skill, a head count, and a reason.
- Head count — how many people that line needs (may be 0; never negative).
- Demand template — a reusable pattern of lines you can apply to create draft plans quickly; template lines reference a node type and expand to a concrete node on apply.
- Status —
DraftorConfirmed. (Lockedexists as a status value but has no current runtime path — nothing moves a plan into it.) - Override reason — the recorded justification required to edit confirmed lines.
How it works
A planner builds a matrix (rows are node × skill, columns are dates), fills in head counts, and walks the plan through its lifecycle:


stateDiagram-v2
[*] --> Draft: create
Draft --> Confirmed: confirm (needs demand.confirm)
Confirmed --> Draft: send back (needs demand.override)
Locked: Locked — defined, but no current action reaches it
- Draft → Confirmed is the planner agreeing the numbers.
Lockedhas no current runtime path. It is a defined status value, but no system action — including publishing or approving a roster — moves a plan into it (Phase-3 runtime, finding F1). The data model anticipates a freeze step that isn't wired today.
Rules & what's enforced
- There is no way to lock a plan today. A planner can't set
Locked(the service rejects it), and no system action reaches it either — publishing/approving a roster leaves the plan at its prior status. - Editing Confirmed lines requires override + reason. On a Confirmed plan you may change lines, but it needs the override permission and a non-empty override reason.
- (The data model also guards a Locked plan against edits with HTTP 409, but since no plan can currently reach
Locked, that guard is latent.)
- (The data model also guards a Locked plan against edits with HTTP 409, but since no plan can currently reach
- Confirming needs the
demand.confirmpermission; sending a plan back to Draft needsdemand.override. - One plan per (date × terminal × shift). Creating a duplicate is refused.
- Only Draft plans can be deleted; head counts must be ≥ 0.
What's live vs planned
- Live: demand-plan create/edit and the matrix, the Draft ↔ Confirmed state machine, cell editing with override gating, demand templates with apply (dry-run preview + commit), and demand reasons.
- Defined but not reachable: the
Lockedplan status — no runtime path moves a plan into it (finding F1).
Do not claim publishing a run locks the demand plan — runtime-verified, it does not. The planner confirms; nothing currently locks the plan.
Related
- Allocation rules — how a confirmed plan's slots are filled.
- Rosters & allocation runs — the run that fills the plan and the separate publish step.
- Shifts & calendars — the shift a plan is built for.