Skip to content

AlertStatus

Owner context: alerts | Entity: Alert | Field: status | Values: 2

Status of an operational alert raised against a shift (duplicate detection, unusual conditions, etc.). The simplest state machine in the system: a boolean dressed as an enum.

States

StateTerminalDescriptionEntry condition
openNoAlert raised, not yet resolvedInitial state (Alert.create())
solvedYes (sink)Alert resolved by a user or by the systemAlert.setSolved(userId)

Helpers: isOpen(), isSolved(). No isFinal(), no canTransition(), no transition matrix.

Transitions

Transition Table

FromToTrigger (service)Invariant / guardSide effects
(new) → openAlertCreatorNo pre-existing alert with the same (alertType, shiftId) — deduplicated at creation timeEmits AlertCreatedDomainEvent
open → solvedAlertUpdater via AlertsUpdaterControlleruserId must resolve to an existing user in usersSets solvedBy to the user id; updates updatedAt

Invariants

  1. Initial state is always openAlert.create() hardcodes AlertStatus.OPEN.
  2. Only forward — the only transition is open → solved. There is no reopen, no escalate, no cancel.
  3. solved is a true sink — nothing moves an alert out of solved.
  4. Dedup at creationAlertCreator refuses to insert a second alert with the same (alertType, shiftId) pair. If you see a single alert for a shift, you cannot be sure how many underlying incidents it represents — it was created once and never updated.
  5. solvedBy carries two kinds of value — the entity models Id | null | 'system': a user id, unsolved, or the literal string 'system' for automated resolution. The AlertUpdater service only sets user ids; the 'system' branch is set elsewhere (admin scripts or batch fixes) and should be documented if it starts being used more actively.
  6. No solved event — only AlertCreatedDomainEvent is emitted. Solving an alert mutates the entity without publishing a domain event. If a consumer needs to react to resolutions, it must poll.

Code Pointers

  • Owner context: alerts
  • Resolver context: users (provides the user id that signs the resolution)
  • Subject context: shifts — every alert references a shiftId