SLA policy & escalation
CondoPulse enforces one promise: reports get acknowledged on a clock. Each severity has a time-to-acknowledge target, and a periodic sweep escalates anything that blows past it - automatically, visibly, and on the record.
The targets
Section titled “The targets”The SLA measures time to acknowledge: from the incident’s creation to its
first transition past open (which stamps acknowledgedAt). It is not a
time-to-fix guarantee - it’s the “someone has seen this” guarantee.
| Severity | Target | Env override |
|---|---|---|
| critical | 4 hours | SLA_HOURS_CRITICAL |
| high | 24 hours | SLA_HOURS_HIGH |
| medium | 72 hours | SLA_HOURS_MEDIUM |
| low | 168 hours (1 week) | SLA_HOURS_LOW |
Override any target by setting the env variable to a number of hours, e.g.
SLA_HOURS_HIGH=12. Defaults apply when unset.
An incident past its target is breached: it shows an SLA breached
badge in lists and on its detail page, sorts to the top of the
/admin → Triage queue, and carries slaBreached: true in API payloads.
What the sweep does
Section titled “What the sweep does”The badge appears as soon as the deadline passes; the sweep is the
enforcement job that acts on breaches. Each run finds every incident that is
still open past its acknowledgement target and, for each one:
- Bumps severity one level - medium → high, high → critical (max
critical). This happens once per incident, ever: the bump is stamped
(
slaBumpedAt), so repeated sweep runs never re-escalate the same incident. - Notifies people - email to board, manager, and admin users (via
SMTP_URL; written to.data/outbox/*.eml.htmlwhen SMTP isn’t configured), and push notifications to the incident’s followers, including the reporter. - Fires webhooks - the
incident.sla_breachedevent goes to every active webhook (see Webhooks & n8n). - Audits - an audit-log entry is recorded with the system actor.
Note the bump applies to open incidents - acknowledging on time is the whole game. Once an incident is acknowledged, the sweep leaves it alone.
Running the sweep
Section titled “Running the sweep”Two equivalent entry points:
- HTTP:
POST /api/cron/sweepwithAuthorization: Bearer ${CRON_SECRET}- for any external scheduler hitting the running server.
- CLI:
npm run sweepfromapps/web- connects to the database directly; the web server doesn’t need to be running.
Crontab
Section titled “Crontab”Hourly is the sensible cadence (the shortest target is 4 hours):
# crontab -e - SLA sweep, hourly on the hour0 * * * * curl -s -X POST -H "Authorization: Bearer dev-cron-secret" http://localhost:3000/api/cron/sweepReplace dev-cron-secret with your real CRON_SECRET and the URL with your
deployment’s base URL.
- Schedule Trigger node - Every Hour.
- HTTP Request node - Method
POST, URLhttps://your-condopulse.example/api/cron/sweep, headerAuthorization: Bearer <CRON_SECRET>.
The endpoint responds when the run completes, so you can chain n8n nodes off the response (e.g. post to the board’s chat when a sweep escalates something).
Verifying it works
Section titled “Verifying it works”Wrong secret → 401. With the seed data loaded there’s an open high-severity
incident already past its 24-hour target: run the sweep and you should see it
bump to critical, an email land in .data/outbox/, and a system-actor entry
appear in /admin → Audit.
What staff should do with breaches
Section titled “What staff should do with breaches”The sweep escalates; humans acknowledge. The working loop:
- Watch the Triage tab -
/admin→ Triage lists SLA-breached (and untriaged) incidents first with inline acknowledge controls. - Acknowledge fast, even without a fix. Acknowledging stops the SLA clock and tells the reporter someone has seen it. “Acknowledged - vendor call booked Thursday” beats silence in every way the system measures.
- Treat the bump as real. A breached-medium is now high on purpose - it sat unseen for three days.
- Review breach counts monthly. The board report
(
/report?month=YYYY-MM) includes the month’s SLA breach count and list; recurring breaches are a staffing or process signal, not a software one.
Tuning the policy
Section titled “Tuning the policy”- The defaults (4/24/72/168) suit a building with a responsive manager.
Tighten
SLA_HOURS_HIGHif elevators dominate your incident mix; loosenSLA_HOURS_LOWif weeds-grade reports are drowning the queue. - Targets are read at sweep time, so changing an env variable affects the next run - no migration needed.
- Don’t disable the sweep to avoid embarrassment. The badge still shows (it’s computed from timestamps, not from the sweep); the sweep is what turns the badge into notifications and escalation.