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_atuntilended_at.ended_at = NULLmeans 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/serviceand/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/endcloses the window and writes theoperationalcache 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
setComponentsStatusTxin 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.