Incident Reporting
Real-time incident reporting with escalation, ownership, and multi-channel notifications
Overview
The incident reporting system lets you document safety issues, near-misses, maintenance needs, guest complaints, and stockouts the moment they happen. Reports carry severity, type, ownership, visibility, and an audit trail from submission through closure. Notifications fan out to Slack through a deduped notification queue, and an isInventoryAlert flag on stockout incidents bypasses the standard priority gate so they reach managers faster.
The Operations Inbox (/inbox) presents the incident triage panel with summary chips (open · critical/high · aging · unassigned) and a scannable list of incident entries showing severity rail, owner, age, and status. Filter chips (Open, Aging, Critical, Assigned) persist in the URL. The legacy /incidents list path redirects here.
Aging incidents are flagged at 72 hours (amber) and 168 hours (red) without resolution.
Filing a Report
Open Incidents in the sidebar and tap Report Incident. The form is split into four progressive sections — Details, Severity, Description, Contact (optional) — with a section-progress rail at the top so you can see what's left.
- Details — Date, shift (Lunch, Dinner, or Late Night), and type. The date and shift default to today and the current shift, which you can change for retroactive reports.
- Severity — Pick one of
low,medium,high,critical. If you choosecritical, a confirmation dialog appears so you can double-check — most critical reports also fire urgent notifications. - Description — Notes (1–5000 chars, required) and optional photo or video attachments. Attachments use the shared uploader, which auto-converts HEIC photos to JPEG and caps each side at 1920px.
- Contact (optional) — Attach an existing contact from the directory, or capture a new one (name required, plus phone/email/notes as available). Skip this section entirely for incidents that aren't tied to a person.
You can dictate the description with the Dictate button — the browser's voice-to-text fills the notes field as you speak.
Your work autosaves as an identity-safe draft on your device (clearing any client-provided identity fields). A recovery banner offers to restore your draft if you return to a half-finished report. Upon successful submission, saved draft state clears automatically.
Submitting dispatches a notification to the location's configured incidents Slack channel and surfaces the report instantly in the Operations Inbox (/inbox) under Needs Attention and My Work.
Incident Types
| Type | Default severity | Notes |
|---|---|---|
Injury | Critical | Physical harm to a staff member or guest |
Near Miss | Medium | Close call — no actual harm but a hazard was present |
Spill / Slip Hazard | High | Liquids or substances creating a slip risk |
Complaint | Low | Customer or staff feedback worth logging |
Maintenance | Low | Equipment or facility issue needing repair |
Stockout | Low | Out-of-stock item; sets isInventoryAlert = true so notifications bypass the priority gate |
Severity
| Level | Meaning | Default priority |
|---|---|---|
low | Minor, no immediate action | P3 |
medium | Needs attention within 24 hours | P3 |
high | Prompt response, possible safety concern | P2 |
critical | Immediate action, active hazard | P1 |
The priority number (1–3) is auto-derived from severity but admins and managers can override it from the incident detail.
Status Lifecycle
Incidents move through four statuses with explicit transitions:
| From | To | Notes required? |
|---|---|---|
reported | investigating | No |
reported | deferred | Yes — reason for deferral |
investigating | resolved | Yes — resolution notes |
investigating | deferred | Yes — reason |
deferred | investigating | No |
resolved | investigating | Yes — reopen reason; sets reopened = true and notifies involved parties |
Each transition writes an incident.status_changed audit entry and dispatches a notification (if the destination is resolved / deferred / reopened).
Ownership
An incident is ownerless until someone claims it. From the detail page (admin/manager only):
- Claim Owner — assigns the current user as owner.
- Reassign Owner — pick any admin or manager at the location. Owners are auto-assigned when a manager moves the status from
reportedtoinvestigating. - The owner's name appears on the incident card and in the notifications.
Visibility
Every incident is either:
- Manager Only (default) — visible to admins and managers at the location, plus the reporter.
- Employee Visible — also visible to non-management staff at the location. Useful for hazards that the whole team should be aware of.
Toggle visibility from the detail page when you have management access.
Priority
Priority (P1 / P2 / P3) is auto-set from severity. Admins and managers can override it from the detail page. Escalating an incident automatically bumps the priority (P2 → P1, P3 → P2; P1 stays at P1).
Escalation
Escalate from the detail page when an incident needs wider attention. Escalation requires a short note explaining the reason. Each escalation:
- Adds an
incident_escalationsrow with the notes, the escalator, and a timestamp. - Bumps the priority if it isn't already at P1.
- Sends an urgent Slack notification to the team room.
- Marks the incident as "Escalated" in the list and on the detail card.
Resolved incidents cannot be escalated — reopen them first if needed.
Comments
Anyone who can read an incident can comment. Comments are free-form (1–2000 chars), timestamped, and labeled with the author's display name. The list appears on the detail page in chronological order, with the comment form pinned to the bottom for management views.
Source Messages
Incidents can be created from a phone message if a guest call or in-person message escalates into a real issue. The reverse link is preserved: the source message shows up in the incident's "Source Messages" card, and the message detail page lists any incidents created from it. Use this to keep the narrative in one place instead of duplicating it across two records.
Notifications
Every incident event dispatches through the notification_queue worker:
| Event | Slack |
|---|---|
created | Always (location's incidents channel) |
status_changed to resolved / deferred | Yes |
reopened | Yes |
escalated | Always (urgent) |
comment_added | — |
owner_changed / priority_changed / visibility_changed | — |
The Slack template (buildIncidentBlocks) renders Acknowledge, Escalate, and View Details buttons; click Acknowledge to mark the incident as investigating from Slack.
Audit Trail
Every change is written inside the same database transaction as the mutation, so the log never drifts from the data:
incident.createdincident.status_changedincident.escalatedincident.comment_addedincident.owner_changedincident.priority_changedincident.visibility_changed
View the full history per incident from the detail page's Status History section, or browse the team-wide log at Admin → Audit Log.