ShiftPilotUser Manual
Back to app

Notifications, Audit & Reports

This page covers the four oversight surfaces that sit on top of everything else in ShiftPilot: the notification center and subscription manager (/notifications), the audit trail (/audit), the built-in report catalog (/reports), and the ad-hoc data export / report builder (/data-export). All four are read/reporting surfaces — nothing here edits a schedule, a credential, or a person — but together they're how anyone with oversight responsibility (an admin, a scheduler, an on-call coordinator, or an auditor) answers "what happened, who did it, and how are we doing."

Why these are complete, not best-effort

Two shared library functions sit underneath this whole page, and it's worth understanding them before the UI, because they're the reason the audit log and notifications are trustworthy rather than something every module has to remember to wire up:

  • writeAudit() (src/lib/audit.ts) is the single write path for the audit trail. Every mutation across every module — assignments, credentials, availability, time-off, swaps, punches, on-call, permissions — calls this one function instead of writing to the AuditEntry table directly. That means the audit log is complete by construction: there's no module that could quietly skip logging, because logging isn't optional plumbing bolted onto each feature, it's the same function call everywhere.
  • notifyEvent() (src/lib/notify.ts) is the matching fan-out for notifications. Any code path that fires a domain event (a shortage created, a credential expiring, a swap approved) calls notifyEvent() with an event type and optional scope; it looks up every matching NotificationSubscription, writes a Notification row per recipient/channel, and — for email/push/SMS — hands off to delivery.

Both are described in more detail in Getting Started.

Notifications

/notifications has two tabs: Inbox (your notification history) and Subscriptions (what you get notified about, and how).

Inbox

Notifications inbox showing a credential-expiring alert for the signed-in auditor

Every notification you've received shows up here, newest first, regardless of channel — including ones that were also emailed or pushed. Unread items are highlighted; clicking one marks it read and, if it links to something (an assignment, a shortage, a credential record), navigates you there. Two filters narrow the list: read status (all / unread / read) and event type (the same catalog used by subscriptions, below). A Mark all read button clears the unread count in one action, and the list paginates at 25 rows.

Subscriptions

Notification subscription manager with the new-subscription form and one active subscription for credential expiring, scoped to a facility, delivered as a daily email digest

A subscription is event type × scope × delivery mode × channel:

  • Event type — the subscribable catalog (src/components/notifications/event-catalog.ts), grouped into: schedule changes (assignment added/edited/removed/moved, open shift created/filled), availability added/removed, time-off submitted/approved/denied/canceled, swap submitted/approved/denied/canceled, coverage shortage created/cleared, competency-violation override, credential expiring/expired, on-call gap, on-call swap, attendance exceptions (call-off/late/no-show), and report-ready.
  • Scope — optional. Leave it blank for "every event of this type, org-wide," or set a scope type (FACILITY / DEPARTMENT / STATION) and id to only hear about that part of the org — e.g., "coverage shortages, but only for the ED" rather than every station everywhere.
  • Delivery mode — Immediate (fires as soon as the event happens), Hourly digest, or Daily digest, so high-volume subscriptions don't flood you one notification at a time.
  • Channel — In-app, Email, Push, or SMS. Every channel writes a Notification row (so it always shows up in your inbox and delivery log regardless of channel); Email/Push/SMS additionally attempt outbound delivery.

Admins get an extra control at the top of the page: a user picker that lets them configure subscriptions on behalf of anyone, not just themselves — useful for setting up a facility admin's shortage alerts without asking them to do it themselves. Non-admins only see and manage their own subscriptions.

Deleting a subscription removes it immediately (no confirmation) — the table refreshes to reflect it.

A note on delivery

This is a local-dev app with no real SMTP/SMS/push provider wired in. Email, SMS, and push notifications are simulated: the Notification row is still created (so the inbox, delivery log, and "email me on X" subscriptions all behave correctly end-to-end), but the actual outbound message is logged to the server console ([notify:email] ...) instead of really being sent. This mirrors the same simulated-send pattern used by the weekly digest and clinic-snapshot emails — see Email, Calendar & API for how to point it at a real SMTP server.

Audit Trail

Filtered audit trail table showing timestamp, actor, action badges, target, source, and reason columns, with filter controls and a CSV export button above

/audit is the browsable, filterable view over every row writeAudit() has ever written. Because that's the single write path described above, this page isn't a "sample" of what happened — assignment overrides, credential changes, availability edits, time-off decisions, swap approvals, punch edits, on-call changes, and permission changes are all in the same table, actor-attributed, with a before/after value and a reason where one applies (overrides, call-offs, removals).

Filters, all combinable:

FilterWhat it narrows
SearchFree text against target id, action, and reason
ActorThe user who performed the action (or "System / automated" for entries with no actor)
Target typeThe entity that was mutated — Assignment, StaffCompetency, TimeOffRequest, OnCallAssignment, ApiKey, etc.
ActionThe specific action string, e.g. assignment.override_create, timeoff.approved, oncall.assign
SourceWeb, Mobile, API, Integration, or Automated
From / ToDate range on the entry timestamp

Action badges are colored by category (green for create-like actions, blue for updates, red for delete/override/deny/cancel-like actions) so a scan down the table shows risk at a glance.

Before/after viewer

Expanded before/after dialog for an assignment.override_create audit entry, showing the full JSON snapshot of the staff record on the After side

Click the eye icon on any row to open a dialog with the entry's full detail — actor, timestamp, source, reason, and side-by-side before and after JSON snapshots of the target entity. For a create action (like the assignment.override_create shown above) "before" is empty and "after" is the full new record; for an edit, both sides are populated so you can see exactly what changed.

Export

Export CSV (this page) downloads the currently loaded page of results (up to 50 rows, matching whatever filters are active) as a CSV, including the raw JSON of the before/after values in their own columns. To export a larger or differently-shaped slice of the audit log, use the Audit Log dataset in the Data Export & Report Builder below, which isn't capped to one page.

Reports

/reports is the fixed, pre-built report catalog — the set of standard operational and compliance reports every clinic needs, each with its own date range or mode filter and a one-click CSV export. Contrast this with Data Export & Report Builder, which is ad-hoc and user-configurable; the report catalog is curated and consistent, always showing the same shape of data the same way.

TabWhat it shows
Coverage AttainmentAttainment % and at-target / below-target / below-minimum window counts over a date range, charted by day and broken out by station/service
Staffing HoursShift count, scheduled vs. worked hours, overtime, differential, on-call, and leave hours over a range — with optional estimated labor cost (see below)
Open ShiftsOpen (unfilled) shifts in range
Shortage HistoryEvery coverage-shortage alert raised in range, critical vs. warning, charted by day plus a full alert log
Credentials & LicensureCredentials expiring within 60 days (or expired-only), with a per-staff flagged-credential count
Time & AttendanceScheduled-vs-actual and attendance-exception trends
On-Call EquityCall distribution across providers — the on-call fairness/equity view
AvailabilityAvailability add/remove activity over a date range

Staffing Hours — group a date range by facility, department, staff, or role and see shift count, scheduled vs. worked hours (worked is timecard-derived, with a scheduled-only marker where punches are missing), overtime, differential, on-call, and leave hours. A Show est. cost toggle appears only if you hold the VIEW_LABOR_COST_REPORTS capability — and then adds regular/OT/differential/total cost columns (a per-staff rate column additionally requires VIEW_COMPENSATION). The server decides which columns exist in the response, so nothing cost-related reaches a caller who lacks the capability; accessing cost is audited. See Compensation & Labor Rules for how the numbers are estimated.

Two representative examples:

Coverage Attainment — with six weeks of seeded assignment data carrying deliberate shortages and overstaffed windows, this report renders real gaps: in the run below, attainment sits at 55%, with 37 below-minimum windows concentrated on the two earliest days in range and specific stations (EKG Bay, Front Desk, PFT Room) showing repeat below-minimum counts.

Coverage attainment report with a 55% attainment tile, at-target/below-target/below-minimum counts, a stacked bar chart by day, and a by-station/service breakdown table

Shortage History — the alert log behind those coverage gaps, filterable by the same date range, showing severity, status, and the exact station/service each alert was raised for.

Shortage history report with a critical-vs-warning bar chart and a shortage alert log table showing two alerts for Provider Pod A / Provider Visit

Credentials & Licensure is worth calling out too, since it's the report most directly tied to the eligibility engine described in Getting Started — every expired credential shown here is one the eligibility engine would already be blocking on the schedule grid.

Credentials & Licensure report listing 22 expired-or-expiring credentials with staff name, credential, status, and expiration date, plus a by-staff flagged-credential count panel

Every tab has its own Export CSV button that downloads exactly what's on screen for the current filter/date range.

Data Export & Report Builder

Data export builder with the Staff Directory dataset selected, all 11 columns checked, a facility/active filter, and a live preview table of 63 matching staff rows

/data-export is the opposite of the fixed report catalog above: instead of a curated set of pre-built reports, it's a general-purpose query builder over eight datasets — Staff Directory, Assignments, Time Off Requests, Shift Swaps, On-Call Assignments, Availability, Staff Credentials, and Audit Log. Use it whenever the question you're answering doesn't map to one of the fixed reports, or you need a wider/narrower column set or a one-off filter combination.

The workflow is four steps, all live:

  1. Dataset — pick one of the eight tabs. Each has its own description, column set, and available filters.
  2. Columns — check/uncheck which columns to include (a Staff Directory export doesn't need to carry every field if you only want names and role groups).
  3. Filters — dataset-specific: date range, facility/department/station, status, type, or active/inactive, depending on what the dataset supports.
  4. Preview — a live, debounced table of matching rows (capped for display; the total match count and a "showing first N" note tell you if it's truncated) updates automatically as you change dataset, columns, or filters.

Download CSV exports the full matching result set (not capped like the preview) as a CSV with your chosen columns. Save this report persists the current dataset/columns/filters combination as a named, reusable report — saved reports show up in the sidebar for one-click reload later, and admins can see and load everyone's saved reports, not just their own.

Access is restricted: only System Admin, Enterprise Admin, Facility Admin, Scheduler, On-Call Coordinator, and Auditor roles can reach /data-export — it's an oversight/reporting tool, not a general staff self-service feature, so Provider/Staff and Charge/Lead accounts are redirected away from it.

Where to go next

Delivery channels & mobile

Every subscription can be delivered in-app, by email (immediate or digest), or by SMS (Twilio — see the Email, Calendar & API section). The whole app is mobile-responsive and installable as a PWA, so alerts and approvals are actionable from a phone.