ShiftPilotUser Manual
Back to app

On-Call & Time Tracking

On-call is a parallel scheduling domain — its own tasks, tiers, and contact/escalation flow — that reuses the same staff, eligibility, and audit machinery as the main schedule. Time & Attendance is the operational record of what actually happened against the schedule. This page covers both: /on-call (with sub-tabs Who's On Call, Build & Rotate, Manage, and Reports) and /time (with sub-pages Clock In / Out, Punch Edits, and Timecards).

Both modules are reached from the left sidebar (On-Call, Time & Attendance). The on-call tabs beyond Who's On Call and Reports — Build & Rotate and Manage — are only shown to roles that can edit the schedule (System/Enterprise/Facility Admin, Scheduler, Charge/Lead, On-Call Coordinator); Provider/Staff and Auditor see a read-only view. Same story on the Time side: the Punch Edits tab only appears for those same edit-capable roles.

On-call

Who's On Call Now

This is the default view when you open /on-call, and it answers one question: who is covering this task right now? Each card is one on-call task, showing its Primary (and Secondary/Tertiary, when assigned) coverage tier, the covering provider's name, their shift window, and a one-click Contact action using their preferred channel (mobile, pager, or secure message, in that priority order).

A task with nobody covering it is never a quiet blank cell — it's an unmistakable red state. The whole card gets a destructive-red border, a "No one on call" badge in the header, and the Primary row itself is highlighted with a red background and the bold text "No one on call for this task." The gap counter at the top of the page ("N gaps") totals every task currently uncovered across the visible set.

Who's on call now, showing real coverage gaps from the seed data

Search has two modes, switchable via the tabs at the top of the Search panel:

  • By staff — type a provider's name, pick them from the results, and see their on-call assignments for the next 30 days, with an "Assigned now" badge on anything covering the current moment.
  • By schedule / specialty — type a schedule name or specialty (e.g. "cardio") to find matching on-call schedules, each with a "Who's on now" shortcut that filters the page down to that schedule. Results are capped and can be cleared with the link shown once a filter is active.

Build & Rotate

The Build & Rotate tab (edit roles only) is where providers actually get assigned to tasks. Pick a schedule, a start date, and a range (7/14/28 days), and you get a grid: one row per task, one column per date. Click any empty tier cell to open the assign dialog, which lists only staff who pass the on-call eligibility gate (competency/credential match plus specialty membership) for that schedule. Any task/date with no Primary assignment is flagged red — the same unmistakable-gap treatment as the Who's On Call view, just inline in the grid.

A rotation-template helper below the grid does bulk round-robin assignment: pick a task, a tier, a start/end time, and an ordered list of providers, and it distributes them across every date in the visible range in one action — useful for filling a 1-in-6 style weeknight rotation without clicking through each day.

Daily vs. weekly cadence. Every on-call task has a cadence, set on the Manage tab:

CadenceBehavior
DailyThe original model — a different provider can cover each date. The grid shows one cell per day.
WeeklyOne provider covers the entire Monday–Sunday block. The grid collapses that week into a single spanning cell ("assign whole week"), and removing the assignment removes all 7 days at once.

Internally, a weekly assignment is still 7 individual OnCallAssignment rows (one per date) — but they all share a weekGroupId, which is what lets the UI treat and display them as one unit rather than 7 separate assignments to manage individually. Assign a whole week from either the grid (click the weekly cell's "assign whole week" prompt) or from the assign dialog, which in week mode shows the full Mon–Sun date range and assigns every eligible date in one call.

Build & Rotate board with a WEEKLY-cadence task spanning a full week as one block, next to a DAILY task with per-day cells

Manage

The Manage tab is where on-call schedules and tasks are defined:

  • On-call schedule — name, specialty (free text, used for search — e.g. "Cardiology"), and facility. Think "Cardiology — Night Call" as one schedule that groups related tasks.
  • On-call task — a coverage line within a schedule: name (e.g. "Cardio ED Assigned Call 7a–7a"), an optional static phone number, free-text contact instructions (e.g. "Page via switchboard, then call mobile if no response in 10 min"), optional schedule notes, and the cadence (Daily or Weekly).

Cadence can be changed after creation from the task list's inline selector — useful if a task originally built day-by-day should switch to a standing weekly assignment, or vice versa. Deleting a task also removes its assignments (confirmed before it happens). Schedules can be deactivated (not hard-deleted) once no longer needed; inactive schedules stay visible here, dimmed, for history.

Manage tab: an on-call schedule expanded to show its Daily and Weekly tasks

Contact, dispatch, and escalation

From any covered task on the Who's On Call view, the Contact button opens a dialog pre-filled with a message and the provider's preferred channel/recipient. There's no live paging/SMS integration in this environment — sending is simulated — but every attempt is archived: because there's no dedicated dispatch-log table in the schema, contact attempts are written to the shared audit trail (oncall.dispatch) with the recipient, channel, and message preserved as the audit entry's after-value. That's also what backs the Reports tab's dispatch archive.

Escalation works the same way. From a task with a Primary assignment, the Escalate button logs a manual escalation (Primary → Secondary, or Secondary → Tertiary) with a required reason — "Primary unreachable after repeated contact attempts" is the default, editable. This is explicitly a log entry, not a reassignment: it records that the on-call chain was walked, but does not move the shift to the next tier's provider. Automated, timing-based escalation (e.g. "escalate automatically if unacknowledged after 15 minutes") is out of scope for this build — everything here is manual, triggered by a person deciding Primary isn't responding.

Reports

The Reports tab (/on-call/reports) has three views, filterable by date range:

  • Call-distribution equity — total calls per provider over the range, broken down by Primary count and by weekday/weeknight/weekend load, with a "Highest load" badge flagging whoever's carrying the most. This is the fairness signal for catching an imbalanced rotation before it becomes a burnout problem.
  • Coverage-gap history — every task/date in the range that had no Primary assignment, i.e. the historical record of the same red-gap condition Who's On Call shows in real time.
  • Dispatch & contact archive — every Contact and Escalation action logged in the range, pulled from the audit trail, showing who acted, when, and the detail (who was contacted via which channel, or which tier-to-tier escalation happened and why).

On-call reports: call-distribution equity table

Time & Attendance

Clock in / clock out

/time (Clock In / Out tab) shows today's scheduled assignment(s) for a staff member with a Clock In / Clock Out button per shift, plus the scheduled vs. actual times once a punch exists. This is self-service by default — a Provider/Staff account only sees and acts on their own shifts.

Anyone with schedule-edit rights (Scheduler, Charge/Lead, and the admin roles) additionally gets a "Clock in on behalf of staff" picker at the top of the page, letting them select any staff member and record a clock-in/out for them — useful for staff who forgot to clock in, or who don't have direct system access at the point of care.

Clock In / Out panel for today's shift

The call-off flow

Every shift card also has a Report an issue action covering five attendance-event types: Late arrival, Early release, Absence, No show, and Call-off. The first four just log a typed, reason-tagged AttendanceEvent. Call-off is the one to understand well, because it does more than log an event:

  1. It records the attendance event (type CALL_OFF, with your reason).
  2. It reopens the shift as a coverage gap — the assignment's status is set to OPEN (or HOT if you check "Promote reopened shift to HOT", marking it high-priority and eligible for immediate self-scheduling) rather than being deleted.

That second part is the important one: because the shift is reopened, not removed, the coverage engine picks it up as a real, trackable gap the same way any other uncovered shift is — it shows up in shortage counts, gap alerts, and (if promoted to HOT) the self-scheduling pool. Deleting the assignment instead would silently make the gap invisible to all of that. A reason is required for a call-off (the field is validated before submit); notes are optional additional detail.

Punch corrections

Punch Edits (/time/punches, admin/scheduler roles only) lists time punches across staff for a date range, with scheduled vs. actual start/end and a variance badge per side (green within 5 minutes, amber within 30, red beyond that). Every punch has an Edit action that opens a correction dialog for actual start/end — and a reason is required (minimum 3 characters) before it can be saved. Every correction writes an audit entry capturing the before and after values plus who made the change and why, satisfying the "audit and validate time-punch changes" requirement — nothing about a punch can be silently adjusted.

Timecards

Timecards (/time/timecards) is the scheduled-vs-actual view per staff member and date range, with per-shift and period-total hours plus a variance badge, and a CSV export. Staff see their own timecard by default; schedulers/admins can pick any staff member.

The page carries an explicit callout that this is not payroll: hours and variance are shown purely for scheduling/operational and audit purposes — no pay rates, wage computation, or compensation data are stored or displayed anywhere in this module.

Timecards view with the "not payroll" callout


On-call windows also show up on a provider's My Schedule page and in their calendar export, so a provider doesn't need to check two different places to see their full commitment picture.