Skip to content

Status model

Components and statuses

A component is a service shown on the status page. Components belong to a group. Each component has one of five statuses:

Status Meaning
operational No active issue
degraded_performance Service works, but slower or partially impaired
partial_outage Part of the service is unavailable
major_outage Service is unavailable
under_maintenance A maintenance window is active

The overall banner is derived from all components: operational, maintenance, degraded, partial_outage or major_outage, depending on the most severe state.

Service lifecycle

Independent of its status, each component has a mode (components.service_status):

Mode Meaning
draft Being prepared, not shown publicly
active_public Active and shown on the public page (default)
active_internal Active, but shown on the status page only to signed-in team members
inactive No longer in service
archived Archived, only visible in service administration and can no longer be renamed

Only active_public is shown publicly. Signed-in users additionally see active_internal on the status page. Status changes, new incidents and maintenance are only possible for the two active modes (lib/domain/service-status.ts).

Windows instead of snapshots

Status history is stored as windows, not as one row per status change. Table: component_status_events.

  • A row says: this status applies from created_at until ended_at. ended_at = NULL means the window is still open.
  • A non-operational status opens a window. "Operational" is never stored as an event. It is the derived state "no open window" (currentStatusFromWindows).
  • When a component returns to operational, all of its open outage and maintenance windows are closed with ended_at = now().

This model makes time-based questions simple: uptime for a day, the outage segments in a 90-day bar, or the availability of a month are all calculated from the list of windows that overlap the period (buildDailyUptime, buildStatusSegments).

The cache column

components.status caches the current status. The invariant is: the cached status equals the most severe status of the open windows, or operational if none is open. The column is only written through setComponentsStatusTx, which updates windows and cache in the same transaction. Configuration changes to the component do not touch it.

One entry point for changes

Status changes go through applyComponentStatusChange in lib/domain/component-status.ts:

  • the status set manually in the admin UI (Service Status)
  • the API routes /api/outage/service and /api/outage/start
  • the uptime-check sweep

The function opens a transaction and reads the previous status with SELECT … FOR UPDATE. This serializes concurrent changes to the same component, so a notification type is never derived from a stale previous status.

There are two documented exceptions:

  • /api/outage/end closes the window and writes the operational cache value in the same transaction, to avoid a race between the two steps (Issue #95).
  • Incidents write the status of the affected components directly through setComponentsStatusTx in their own transaction, and notify through the incident path.

Maintenance does not write a status. under_maintenance is derived from the time window when reading and overlays the stored status (lib/domain/maintenance.ts). Setting under_maintenance manually, on the other hand, creates a regular window.

Backdating and corrections

  • Incidents can be backdated. Their windows start at the occurred time, and later windows that are still open remain untouched.
  • For closed incidents, the exact outage window per component can be corrected (incident_components.outage_start_at / outage_end_at). These corrections replace the original windows authoritatively (applyIncidentOutageCorrections).
  • Maintenance windows are kept in the history as well, but they never count as an active outage (see Incidents & maintenance).

Public Status API

/api/status returns the current statuses and the 90-day uptime per component. It is cached for 30 seconds. The public HTML pages are not cached, so a visitor always sees the current state.