@molecule/api-resource-status-page

API resource · status-page · API (Node) · v1.0.5 · Apache-2.0

Status page resource with service monitoring, incidents, and uptime

npm install @molecule/api-resource-status-page

npm · Source on GitHub

How it works

@molecule/api-resource-status-page is an API resource: the routes, validation and storage for status-page, built on the database and auth cores so it runs on whichever providers your app has bonded.

import { createRequestHandler } from '@molecule/api-resource'
import { createRequestHandlerMap, routes } from '@molecule/api-resource-status-page'

// The handler map is a FACTORY (like api-resource-device) — build it with
// the createRequestHandler from @molecule/api-resource (mlcl inject does this):
const requestHandlerMap = createRequestHandlerMap(createRequestHandler)

// Public reads: GET /status, GET /status/services, GET /status/services/:id,
//               GET /status/incidents, GET /status/uptime
// Admin-only:   POST/PATCH/DELETE /status/services(/:id),
//               POST/PATCH /status/incidents(/:id)

Works with: @molecule/api-bond, @molecule/api-database, @molecule/api-i18n, @molecule/api-locales-status-page, @molecule/api-resource

Live demos

Running apps built with Molecule that install this package — open the app or study the template.

Reference

Status page resource for molecule.dev.

Public status-page backend: monitored services, incidents with lifecycle updates, health-check history, and uptime windows. The read endpoints power a public status page; the mutation endpoints are for operators.

Tables this package owns: four. services is the parent; checks, incidents and uptimeWindows each join to it on their own serviceId = services.id (a declared FK, ON DELETE CASCADE) — that serviceId is the column every per-service query filters on.

handlers.* return { statusCode, headers?, body } and never write to res — not through res.json, not through res.send, not through res.end. The mounted routes apply that object for you (createRequestHandler does res.set(headers), res.status(statusCode), res.send(body)); calling a handler directly is only correct if you apply the result yourself:

const { statusCode, headers, body } = await handlers.getStatus(resource)(req, res)
if (headers) res.set(headers)
res.status(statusCode).send(body)

Monkey-patching res.json to re-shape a handler's answer intercepts nothing the handler produces, so the request it was meant to answer is left unanswered and hangs.

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Quick Start

import { createRequestHandler } from '@molecule/api-resource'
import { createRequestHandlerMap, routes } from '@molecule/api-resource-status-page'

// The handler map is a FACTORY (like api-resource-device) — build it with
// the createRequestHandler from @molecule/api-resource (mlcl inject does this):
const requestHandlerMap = createRequestHandlerMap(createRequestHandler)

// Public reads: GET /status, GET /status/services, GET /status/services/:id,
//               GET /status/incidents, GET /status/uptime
// Admin-only:   POST/PATCH/DELETE /status/services(/:id),
//               POST/PATCH /status/incidents(/:id)

Type

resource

Installation

npm install @molecule/api-resource-status-page @molecule/api-bond @molecule/api-database @molecule/api-i18n @molecule/api-locales-status-page @molecule/api-monitoring @molecule/api-notifications @molecule/api-permissions @molecule/api-resource @molecule/api-scheduler zod

API

Types

ServiceProps

Full service record properties.

type ServiceProps = z.infer<typeof servicePropsSchema>

CreateServiceProps

Fields accepted when creating a new service.

type CreateServiceProps = z.infer<typeof createServicePropsSchema>

UpdateServiceProps

Updatable service fields.

type UpdateServiceProps = z.infer<typeof updateServicePropsSchema>

CheckProps

Health check result properties.

type CheckProps = z.infer<typeof checkPropsSchema>

IncidentProps

Full incident record properties.

type IncidentProps = z.infer<typeof incidentPropsSchema>

CreateIncidentProps

Fields accepted when creating a new incident.

type CreateIncidentProps = z.infer<typeof createIncidentPropsSchema>

UpdateIncidentProps

Updatable incident fields.

type UpdateIncidentProps = z.infer<typeof updateIncidentPropsSchema>

UptimeWindowProps

Uptime window statistics properties.

type UptimeWindowProps = z.infer<typeof uptimeWindowPropsSchema>

Functions

isStatusAdmin(res)

Resolves whether the current request's session belongs to an actor authorized to administer the status page (create/update/delete services + incidents). Fail-closed: returns false when there is no authenticated session, and otherwise only true when the session carries an admin claim or a bonded permissions provider grants the manage status permission.

Use this for in-handler defense-in-depth (it does not depend on the route middleware being preserved by the injector).

function isStatusAdmin(res: MoleculeResponse): Promise<boolean>
  • res — The response whose locals.session is inspected.

Returns: true when the session is an authorized status page admin.

requireAdmin()

Route middleware that gates the admin-only status page mutation routes. Calls next() only for an authenticated status page admin; otherwise forwards an error to the framework error handler — Unauthorized when no session is present, Forbidden when the session is authenticated but not authorized to manage the status page.

Exposed as a request-handler-map key so the injector's route scanner keeps it (unlike the inert global 'auth' string, which is dropped).

function requireAdmin(): MoleculeRequestHandler

Returns: An Express-compatible middleware function.

createRequestHandlerMap(createRequestHandler)

Creates the full request handler map for the Status resource. Maps handler names (matching route definitions) to Express middleware via createRequestHandler.

requireAdmin is the status-management authorizer middleware referenced by the mutating routes (createService/updateService/deleteService/createIncident/ updateIncident). It must live here as a real handler-map key so the mlcl injector's route scanner preserves it — a bare middleware string that isn't a handler-map key is silently dropped (which is why the previous 'auth' gate was inert and the mutating routes shipped public). It is already an Express middleware, so it is NOT wrapped in createRequestHandler.

function createRequestHandlerMap(
  createRequestHandler: (
    handler: Handler,
  ) => (req: MoleculeRequest, res: MoleculeResponse, next: MoleculeNextFunction) => Promise<void>,
): Record<string, MoleculeRequestHandler>
  • createRequestHandler — Factory from @molecule/api-resource that wraps handler configs into Express middleware.

Returns: A record mapping handler names to Express middleware functions.

createResource()

Creates a new status resource definition.

function createResource(): types.Resource<unknown>

Returns: The status resource descriptor with name, tableName, and schema.

Constants

STATUS_PERMISSION_ACTION

Permission action checked against @molecule/api-permissions for status page administration.

const STATUS_PERMISSION_ACTION: 'manage'

STATUS_PERMISSION_RESOURCE

Permission resource checked against @molecule/api-permissions for status page administration.

const STATUS_PERMISSION_RESOURCE: 'status'

STATUS_ADMIN_PERMISSION

Session-claim permission string ('status:manage') that, when present in a session's permissions array, grants status page administration without a bonded permissions provider.

const STATUS_ADMIN_PERMISSION: 'status:manage'

i18nNamespace

The i18n namespace for the status resource.

const i18nNamespace: 'status'

i18nRegistered

The i18n registered.

const i18nRegistered: true

resource

The status resource definition.

const resource: types.Resource<unknown>

routes

Route array for status page endpoints: public read routes and admin-gated mutation routes.

const routes: (
  | { method: 'get'; path: string; middlewares: never[]; handler: string }
  | { method: 'post'; path: string; middlewares: string[]; handler: string }
  | { method: 'patch'; path: string; middlewares: string[]; handler: string }
  | { method: 'delete'; path: string; middlewares: string[]; handler: string }
)[]

servicePropsSchema

Full schema for a monitored service.

const servicePropsSchema: z.ZodObject<
  {
    id: z.ZodString
    createdAt: z.ZodString
    updatedAt: z.ZodString
    name: z.ZodString
    url: z.ZodString
    method: z.ZodDefault<z.ZodEnum<{ GET: 'GET'; HEAD: 'HEAD'; POST: 'POST' }>>
    expectedStatus: z.ZodDefault<z.ZodNumber>
    timeoutMs: z.ZodDefault<z.ZodNumber>
    intervalMs: z.ZodDefault<z.ZodNumber>
    groupName: z.ZodOptional<z.ZodString>
    enabled: z.ZodDefault<z.ZodBoolean>
  },
  z.core.$strip
>

createServicePropsSchema

Schema for creating a new service.

const createServicePropsSchema: z.ZodObject<
  {
    name: z.ZodString
    url: z.ZodString
    method: z.ZodDefault<z.ZodEnum<{ GET: 'GET'; HEAD: 'HEAD'; POST: 'POST' }>>
    expectedStatus: z.ZodDefault<z.ZodNumber>
    timeoutMs: z.ZodDefault<z.ZodNumber>
    intervalMs: z.ZodDefault<z.ZodNumber>
    groupName: z.ZodOptional<z.ZodString>
    enabled: z.ZodDefault<z.ZodBoolean>
  },
  z.core.$strip
>

updateServicePropsSchema

Schema for updating an existing service (all fields optional).

const updateServicePropsSchema: z.ZodObject<
  {
    name: z.ZodOptional<z.ZodString>
    url: z.ZodOptional<z.ZodString>
    method: z.ZodOptional<z.ZodDefault<z.ZodEnum<{ GET: 'GET'; HEAD: 'HEAD'; POST: 'POST' }>>>
    expectedStatus: z.ZodOptional<z.ZodDefault<z.ZodNumber>>
    timeoutMs: z.ZodOptional<z.ZodDefault<z.ZodNumber>>
    intervalMs: z.ZodOptional<z.ZodDefault<z.ZodNumber>>
    groupName: z.ZodOptional<z.ZodOptional<z.ZodString>>
    enabled: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>
  },
  z.core.$strip
>

checkPropsSchema

Schema for a single health check result.

const checkPropsSchema: z.ZodObject<
  {
    id: z.ZodString
    serviceId: z.ZodString
    status: z.ZodEnum<{ up: 'up'; down: 'down'; degraded: 'degraded' }>
    httpStatus: z.ZodOptional<z.ZodNumber>
    latencyMs: z.ZodOptional<z.ZodNumber>
    error: z.ZodOptional<z.ZodString>
    checkedAt: z.ZodString
  },
  z.core.$strip
>

incidentPropsSchema

Full schema for a service incident.

const incidentPropsSchema: z.ZodObject<
  {
    id: z.ZodString
    createdAt: z.ZodString
    updatedAt: z.ZodString
    serviceId: z.ZodString
    title: z.ZodString
    description: z.ZodOptional<z.ZodString>
    severity: z.ZodEnum<{ minor: 'minor'; major: 'major'; critical: 'critical' }>
    status: z.ZodEnum<{
      investigating: 'investigating'
      identified: 'identified'
      monitoring: 'monitoring'
      resolved: 'resolved'
    }>
    autoDetected: z.ZodDefault<z.ZodBoolean>
    startedAt: z.ZodString
    resolvedAt: z.ZodOptional<z.ZodString>
  },
  z.core.$strip
>

createIncidentPropsSchema

Schema for creating a new incident.

const createIncidentPropsSchema: z.ZodObject<
  {
    serviceId: z.ZodString
    title: z.ZodString
    description: z.ZodOptional<z.ZodString>
    severity: z.ZodEnum<{ minor: 'minor'; major: 'major'; critical: 'critical' }>
    status: z.ZodEnum<{
      investigating: 'investigating'
      identified: 'identified'
      monitoring: 'monitoring'
      resolved: 'resolved'
    }>
    autoDetected: z.ZodDefault<z.ZodBoolean>
    startedAt: z.ZodString
  },
  z.core.$strip
>

updateIncidentPropsSchema

Schema for updating an existing incident (all fields optional).

const updateIncidentPropsSchema: z.ZodObject<
  {
    title: z.ZodOptional<z.ZodString>
    description: z.ZodOptional<z.ZodOptional<z.ZodString>>
    severity: z.ZodOptional<z.ZodEnum<{ minor: 'minor'; major: 'major'; critical: 'critical' }>>
    status: z.ZodOptional<
      z.ZodEnum<{
        investigating: 'investigating'
        identified: 'identified'
        monitoring: 'monitoring'
        resolved: 'resolved'
      }>
    >
    resolvedAt: z.ZodOptional<z.ZodOptional<z.ZodString>>
  },
  z.core.$strip
>

uptimeWindowPropsSchema

Schema for a pre-computed uptime statistics window.

const uptimeWindowPropsSchema: z.ZodObject<
  {
    id: z.ZodString
    serviceId: z.ZodString
    window: z.ZodEnum<{ '1h': '1h'; '24h': '24h'; '7d': '7d'; '30d': '30d'; '90d': '90d' }>
    uptimePct: z.ZodNumber
    totalChecks: z.ZodNumber
    upChecks: z.ZodNumber
    avgLatencyMs: z.ZodNumber
  },
  z.core.$strip
>

Namespaces

z

Re-exports the zod module — z.<name> is exactly zod.<name>, documented by that package (installed at node_modules/zod).

handlers

Re-exported as a namespace — reach every member below through it (e.g. handlers.<name>).

handlers.createIncident(_resource)

Creates a new incident record. Validates the request body against the create incident schema before inserting.

function createIncident({ tableName: _tableName }: { tableName: string }): (
  req: MoleculeRequest,
  res: MoleculeResponse,
) => Promise<
  | { statusCode: number; body: { error: string; errorKey: string; props?: undefined } }
  | {
      statusCode: number
      body: {
        props: {
          id: string
          createdAt: string
          updatedAt: string
          serviceId: string
          title: string
          severity: 'minor' | 'major' | 'critical'
          status: 'investigating' | 'identified' | 'monitoring' | 'resolved'
          autoDetected: boolean
          startedAt: string
          description?: string | undefined
          resolvedAt?: string | undefined
        } | null
        error?: undefined
        errorKey?: undefined
      }
    }
>
  • _resource — The service resource configuration (unused).
  • _resource.tableName — The database table name for services.

Returns: A request handler that creates an incident and responds with the created record.

handlers.createService(resource)

Creates a new monitored service. Validates the request body against the create service schema before inserting into the database.

function createService({ tableName }: { tableName: string }): (
  req: MoleculeRequest,
  res: MoleculeResponse,
) => Promise<
  | { statusCode: number; body: { error: string; errorKey: string; props?: undefined } }
  | {
      statusCode: number
      body: {
        props: {
          id: string
          createdAt: string
          updatedAt: string
          name: string
          url: string
          method: 'GET' | 'HEAD' | 'POST'
          expectedStatus: number
          timeoutMs: number
          intervalMs: number
          enabled: boolean
          groupName?: string | undefined
        } | null
        error?: undefined
        errorKey?: undefined
      }
    }
>
  • resource — The service resource configuration.
  • resource.tableName — The database table name for services.

Returns: A request handler that creates a service and responds with the created record.

handlers.deleteService(resource)

Deletes a monitored service by ID. Returns 404 if the service does not exist. Associated checks, incidents, and uptime windows are removed via CASCADE.

function deleteService({
  tableName,
}: {
  tableName: string
}): (
  req: MoleculeRequest,
  res: MoleculeResponse,
) => Promise<
  | { statusCode: number; body: { error: string; errorKey: string; props?: undefined } }
  | { statusCode: number; body: { props: { id: string }; error?: undefined; errorKey?: undefined } }
>
  • resource — The service resource configuration.
  • resource.tableName — The database table name for services.

Returns: A request handler that deletes a service and responds with 204 on success.

handlers.getService(resource)

Returns a single service by ID along with the last 50 check results.

function getService({ tableName }: { tableName: string }): (req: MoleculeRequest) => Promise<
  | { statusCode: number; body: { error: string; errorKey: string; props?: undefined } }
  | {
      statusCode: number
      body: {
        props: {
          recentChecks: {
            id: string
            serviceId: string
            status: 'up' | 'down' | 'degraded'
            checkedAt: string
            httpStatus?: number | undefined
            latencyMs?: number | undefined
            error?: string | undefined
          }[]
          id: string
          createdAt: string
          updatedAt: string
          name: string
          url: string
          method: 'GET' | 'HEAD' | 'POST'
          expectedStatus: number
          timeoutMs: number
          intervalMs: number
          enabled: boolean
          groupName?: string | undefined
        }
        error?: undefined
        errorKey?: undefined
      }
    }
>
  • resource — The service resource configuration.
  • resource.tableName — The database table name for services.

Returns: A request handler that responds with a service and its recent checks.

handlers.getStatus(resource)

Returns the aggregated system health status.

Finds all enabled services, fetches the latest check for each, and computes an overall status: operational, degraded, or down.

function getStatus({ tableName }: { tableName: string }): (_req: MoleculeRequest) => Promise<
  | {
      statusCode: number
      body: {
        status: 'down' | 'degraded' | 'operational'
        services: { id: string; name: string; status: string; latencyMs: number | null }[]
        checkedAt: string
        error?: undefined
        errorKey?: undefined
      }
    }
  | {
      statusCode: number
      body: {
        error: string
        errorKey: string
        status?: undefined
        services?: undefined
        checkedAt?: undefined
      }
    }
>
  • resource — The service resource configuration.
  • resource.tableName — The database table name for services.

Returns: A request handler that responds with overall system status.

handlers.getUptime(_resource)

Returns uptime window statistics for all services, or filtered by ?serviceId= query parameter for a specific service.

function getUptime({ tableName: _tableName }: { tableName: string }): (
  req: MoleculeRequest,
) => Promise<
  | {
      statusCode: number
      body: {
        id: string
        serviceId: string
        window: '1h' | '24h' | '7d' | '30d' | '90d'
        uptimePct: number
        totalChecks: number
        upChecks: number
        avgLatencyMs: number
      }[]
    }
  | { statusCode: number; body: { error: string; errorKey: string } }
>
  • _resource — The service resource configuration (unused).
  • _resource.tableName — The database table name for services.

Returns: A request handler that responds with uptime window records.

handlers.listIncidents(_resource)

Lists incidents with support for ?status= filtering and pagination via ?limit= and ?offset= query parameters.

function listIncidents({ tableName: _tableName }: { tableName: string }): (
  req: MoleculeRequest,
) => Promise<
  | {
      statusCode: number
      body: {
        id: string
        createdAt: string
        updatedAt: string
        serviceId: string
        title: string
        severity: 'minor' | 'major' | 'critical'
        status: 'investigating' | 'identified' | 'monitoring' | 'resolved'
        autoDetected: boolean
        startedAt: string
        description?: string | undefined
        resolvedAt?: string | undefined
      }[]
    }
  | { statusCode: number; body: { error: string; errorKey: string } }
>
  • _resource — The service resource configuration (unused).
  • _resource.tableName — The database table name for services.

Returns: A request handler that responds with a paginated array of incidents.

handlers.listServices(resource)

Lists all services along with each service's latest check result.

function listServices({ tableName }: { tableName: string }): (_req: MoleculeRequest) => Promise<
  | {
      statusCode: number
      body: {
        latestCheck: {
          id: string
          serviceId: string
          status: 'up' | 'down' | 'degraded'
          checkedAt: string
          httpStatus?: number | undefined
          latencyMs?: number | undefined
          error?: string | undefined
        }
        id: string
        createdAt: string
        updatedAt: string
        name: string
        url: string
        method: 'GET' | 'HEAD' | 'POST'
        expectedStatus: number
        timeoutMs: number
        intervalMs: number
        enabled: boolean
        groupName?: string | undefined
      }[]
    }
  | { statusCode: number; body: { error: string; errorKey: string } }
>
  • resource — The service resource configuration.
  • resource.tableName — The database table name for services.

Returns: A request handler that responds with an array of services and their latest check.

handlers.updateIncident(_resource)

Updates an existing incident by ID. Validates the request body against the update incident schema (all fields optional) before patching.

function updateIncident({ tableName: _tableName }: { tableName: string }): (
  req: MoleculeRequest,
  res: MoleculeResponse,
) => Promise<
  | { statusCode: number; body: { error: string; errorKey: string; props?: undefined } }
  | {
      statusCode: number
      body: {
        props: {
          id: string
          createdAt: string
          updatedAt: string
          serviceId: string
          title: string
          severity: 'minor' | 'major' | 'critical'
          status: 'investigating' | 'identified' | 'monitoring' | 'resolved'
          autoDetected: boolean
          startedAt: string
          description?: string | undefined
          resolvedAt?: string | undefined
        } | null
        error?: undefined
        errorKey?: undefined
      }
    }
>
  • _resource — The service resource configuration (unused).
  • _resource.tableName — The database table name for services.

Returns: A request handler that updates an incident and responds with the updated record.

handlers.updateService(resource)

Updates an existing monitored service by ID. Validates the request body against the update service schema (all fields optional) before patching.

function updateService({ tableName }: { tableName: string }): (
  req: MoleculeRequest,
  res: MoleculeResponse,
) => Promise<
  | { statusCode: number; body: { error: string; errorKey: string; props?: undefined } }
  | {
      statusCode: number
      body: {
        props: {
          id: string
          createdAt: string
          updatedAt: string
          name: string
          url: string
          method: 'GET' | 'HEAD' | 'POST'
          expectedStatus: number
          timeoutMs: number
          intervalMs: number
          enabled: boolean
          groupName?: string | undefined
        } | null
        error?: undefined
        errorKey?: undefined
      }
    }
>
  • resource — The service resource configuration.
  • resource.tableName — The database table name for services.

Returns: A request handler that updates a service and responds with the updated record.

types

Re-exported as a namespace — reach every member below through it (e.g. types.<name>).

types.ServiceProps

Full service record properties.

type ServiceProps = z.infer<typeof servicePropsSchema>
types.CreateServiceProps

Fields accepted when creating a new service.

type CreateServiceProps = z.infer<typeof createServicePropsSchema>
types.UpdateServiceProps

Updatable service fields.

type UpdateServiceProps = z.infer<typeof updateServicePropsSchema>
types.CheckProps

Health check result properties.

type CheckProps = z.infer<typeof checkPropsSchema>
types.IncidentProps

Full incident record properties.

type IncidentProps = z.infer<typeof incidentPropsSchema>
types.CreateIncidentProps

Fields accepted when creating a new incident.

type CreateIncidentProps = z.infer<typeof createIncidentPropsSchema>
types.UpdateIncidentProps

Updatable incident fields.

type UpdateIncidentProps = z.infer<typeof updateIncidentPropsSchema>
types.UptimeWindowProps

Uptime window statistics properties.

type UptimeWindowProps = z.infer<typeof uptimeWindowPropsSchema>
types.Resource

An object describing the status resource.

type Resource<T = unknown> = resourceTypes.Resource<T>

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-bond ^1.0.1
  • @molecule/api-database ^1.0.1
  • @molecule/api-i18n ^1.0.1
  • @molecule/api-monitoring ^1.0.1
  • @molecule/api-notifications ^1.0.1
  • @molecule/api-permissions ^1.0.1
  • @molecule/api-resource ^1.0.1
  • @molecule/api-scheduler ^1.0.1
  • @molecule/api-locales-status-page ^1.0.1

Runtime Dependencies

  • @molecule/api-bond
  • @molecule/api-database
  • @molecule/api-i18n
  • @molecule/api-locales-status-page
  • @molecule/api-monitoring
  • @molecule/api-notifications
  • @molecule/api-permissions
  • @molecule/api-resource
  • @molecule/api-scheduler
  • zod

The GET routes are PUBLIC by design — a status page is a public surface; do not put them behind auth. The mutating routes are ADMIN-ONLY and DENY by default: they are gated by the requireAdmin middleware AND re-checked inside every mutation handler via isStatusAdmin — fail-closed defense-in-depth that holds even if a route scanner drops the middleware. "Admin" resolves as: an admin session claim (isAdmin: true, role: 'admin', roles containing 'admin', or a 'status:manage' / 'admin' entry in session.permissions) OR a bonded @molecule/api-permissions grant of manage on status. Until the app grants one of those, every mutation is denied — grant the claim/permission at startup, do NOT strip the gate: an open mutation surface lets any caller deface the public status page (fabricate outages, delete services).

Handler text flows through t() with English defaults; the companion locale bond @molecule/api-locales-status-page provides translations.

Tables: src/__setup__/*.sql creates services, incidents, checks, and uptimeWindows. An mlcl-scaffolded API replays these setup files automatically on migrate; anywhere else run them once — nothing at runtime creates them.

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual status-page screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip. Verify BEHAVIOR and the public/admin split, not just that CRUD compiles:

  • The PUBLIC status page renders every monitored service (component) with its current status and an OVERALL banner that is DERIVED, never hardcoded: GET /status returns operational when no enabled service's latest check is down or degraded ("All systems operational"), down if ANY latest check is down, else degraded if any is degraded — the banner reflects the WORST service, and a service with no check reads unknown (which never turns the banner red). GET /status/services lists each service with its latest check.
  • An admin creating an INCIDENT (POST /status/incidents with serviceId, title, severity minor|major|critical, status investigating, startedAt) persists it and it shows on the public GET /status/incidents. The affected service reads down/degraded on the page because its latest check says so (checks are monitor-written, never typed in), so the overall banner goes non-green while the incident is open.
  • Updating the incident (PATCH /status/incidents/:id) advances its timeline through the real lifecycle investigating -> identified -> monitoring -> resolved (bumping updatedAt), and each stage shows on the public page. Marking it resolved (with resolvedAt) moves it to history — the public list filtered ?status=resolved includes it while the active incidents drop it — and once the affected service's latest check returns to up, GET /status recovers to "All systems operational" (the banner tracks live check state, so a still-down check keeps it red).
  • AUTHORIZATION — reads are PUBLIC: with NO session, every GET (/status, /status/services, /status/services/:id, /status/incidents, /status/uptime) returns 200 — the status page is meant to be seen without signing in.
  • AUTHORIZATION — writes are ADMIN-ONLY, deny by default: every mutation (POST/PATCH/DELETE /status/services(/:id), POST/PATCH /status/incidents(/:id)) is refused for an anonymous caller (401) and for a normal signed-in user with no admin claim / manage status grant (403), and nothing changes — enforced twice (the requireAdmin route middleware AND the in-handler isStatusAdmin re-check). A non-admin has NO path to fabricate an outage, delete a service, or post a fake incident, and no endpoint sets a service up/down at all (that is monitor-written).