Skip to content

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.
  • StatusDraft or Confirmed. (Locked exists 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:

The demand matrix for plan 46 (Demo Container Terminal, SHT-EVE-16) — headcount by node, skill and day; amber = Draft (6/1), blue = Confirmed (6/8).

Plan status by colour — plan 46 (6/1) is Draft (amber), plan 47 (6/8) is Confirmed (blue); the Draft/Confirmed/Locked legend sits top-right.

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.
  • Locked has 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.)
  • Confirming needs the demand.confirm permission; sending a plan back to Draft needs demand.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 Locked plan 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.