Hospital Scheduling https://getshiftd.com
  • TypeScript 70.9%
  • Kotlin 16%
  • Swift 10.9%
  • HTML 0.8%
  • JavaScript 0.6%
  • Other 0.7%
Find a file
Alberto Hernandez cfeb1c6031
Some checks are pending
Android / Android Validation (push) Has started running
Release Artifacts / Build and push Docker release images (push) Blocked by required conditions
Release Artifacts / Validate release candidate (push) Has started running
Release Artifacts / Deploy to staging (push) Blocked by required conditions
Security, Type Check & Runtime / Dependency Audit (push) Waiting to run
Security, Type Check & Runtime / Type Check (push) Waiting to run
Security, Type Check & Runtime / Backend Runtime Smoke (push) Waiting to run
Security, Type Check & Runtime / Migration Guardrails (push) Waiting to run
Code Scanning / Gitleaks secret scan (push) Successful in 7s
Code Scanning / Semgrep OSS source scan (push) Successful in 36s
Merge pull request 'feat(android): surface shift tags on schedule and dashboard' (#332) from android-shift-tags into main
Reviewed-on: #332
2026-06-08 10:44:51 -04:00
.github chore(deps): update renovate/renovate:latest docker digest to b345ab7 2026-06-08 10:27:28 -04:00
apps feat(android): surface shift tags on schedule and dashboard 2026-06-08 10:44:51 -04:00
docs feat(calendar): explicit shift tags in event titles (Slice 5) 2026-06-08 10:42:20 -04:00
packages/shared-types feat(backend): calendar subscription + token-authed ICS feed endpoints 2026-05-28 18:01:56 -04:00
scripts harden(cd): make release retag all-or-nothing across the 3 images 2026-05-30 10:42:37 -04:00
tests test(e2e): Operations Obligation Alerts tab + filter + row-action deep-link 2026-06-05 10:59:35 -04:00
tools ci(openapi): commit lint:openapi tooling the OpenAPI spec-lint job calls 2026-06-05 13:42:34 -04:00
.dockerignore feat(security): enhance Docker security by adding non-root user execution, container hardening, and entrypoint script for Traefik config ownership 2026-05-04 11:00:46 -04:00
.gitignore fix: drop accidental worktrees/ gitlink from tree 2026-06-06 17:27:37 -04:00
.gitleaks.toml security: tune gitleaks fixture allowlist 2026-05-08 14:11:01 -04:00
.node-version chore(deps): update node.js 2026-06-03 20:48:13 -04:00
.npmrc chore: configure EAS Build for TestFlight distribution 2026-03-23 19:53:44 -04:00
.nvmrc chore(deps): update node.js 2026-06-03 20:48:13 -04:00
.osv-scanner.toml ci: add forgejo renovate workflow 2026-05-08 13:39:34 -04:00
AGENTS.md docs: enforce TypeScript checks after every code change 2026-04-10 19:41:16 -04:00
backup.sh feat: deploy production from registry images 2026-05-27 22:54:27 -04:00
bun.lock feat: add SQL script to update engine_mutable status for imported regular schedules 2026-05-15 16:58:37 -04:00
CHANGELOG.md docs: markdown hygiene — archive 30 completed specs/logs, shrink 3 oversized docs 2026-06-01 09:34:00 -04:00
CLAUDE.md docs: reduce default agent context 2026-06-01 12:56:51 -04:00
cliff.toml chore(release): limit changelog to features, fixes, and performance 2026-06-04 20:36:46 -04:00
deploy.sh fix(deploy): prune dangling images and build cache after each deploy 2026-06-02 08:26:27 -04:00
DESIGN.json spec(design-system): introduce formal design system documentation 2026-04-27 23:05:08 -04:00
DESIGN.md feat(ui): integrate shiftd brand wordmark font 2026-04-28 21:37:58 -04:00
docker-compose.prod.yml fix(deps): revert postgres docker tag 18→16; pin major (#273 broke staging deploy) 2026-05-30 07:00:10 -04:00
docker-compose.staging.yml fix(staging): make the first staging deploy actually succeed end-to-end 2026-05-29 10:47:29 -04:00
docker-compose.test.yml fix(deps): revert postgres docker tag 18→16; pin major (#273 broke staging deploy) 2026-05-30 07:00:10 -04:00
docker-compose.yml fix(deps): revert postgres docker tag 18→16; pin major (#273 broke staging deploy) 2026-05-30 07:00:10 -04:00
Dockerfile.backend chore(deps): update dependency node to v24.16.0 2026-06-07 22:47:52 -04:00
Dockerfile.frontend chore(deps): update dependency node to v24.16.0 2026-06-07 22:47:52 -04:00
LICENSE chore: add ascAppId to EAS submit config for iOS 2026-03-27 10:14:42 -04:00
memory-security.md docs(security): close hardening sweep follow-ups 2026-05-25 20:24:01 -04:00
nginx.conf fix(security): harden production containers 2026-05-25 18:26:15 -04:00
nginx.staging.conf fix(staging): make the first staging deploy actually succeed end-to-end 2026-05-29 10:47:29 -04:00
package.json ci(openapi): commit lint:openapi tooling the OpenAPI spec-lint job calls 2026-06-05 13:42:34 -04:00
playwright.config.ts test(e2e): Operations Obligation Alerts tab + filter + row-action deep-link 2026-06-05 10:59:35 -04:00
pnpm-lock.yaml chore(deps): update dependency @hono/node-server to >=2.0.4 2026-06-08 10:24:02 -04:00
pnpm-workspace.yaml chore(deps): update dependency @hono/node-server to >=2.0.4 2026-06-08 10:24:02 -04:00
PRODUCT.md spec(design-system): introduce formal design system documentation 2026-04-27 23:05:08 -04:00
README.md Add safe backend DB test runner 2026-05-21 20:59:27 +00:00
renovate.json fix(renovate): open eligible PRs immediately 2026-06-07 22:05:53 -04:00
rollback.sh harden(rollback): verify image labels on the DEFAULT path too, not just --tag 2026-05-30 05:22:48 -04:00
tsconfig.json fix: source dashboard signup summary from backend 2026-05-10 13:39:27 -04:00

Shiftd — Constraint-Aware Staff Scheduling

A powerful staff scheduling platform that prioritizes coverage visibility, administrative control, and auditability. Built for departments managing complex shift patterns, staffing constraints, and role-based access.


Project Goals

  • Clear visibility into staffing coverage across day, week, month, and coverage views
  • Administrative scheduling workflows that surface constraints rather than hiding them
  • Reduce manual reconciliation of over/understaffed shifts
  • Support complex lifecycle workflows: self-signup windows, admin adjustment phases
  • Role-based access control across staff, schedulers, admins, and department admins
  • Audit trail for every scheduling decision

Tech Stack

Layer Stack
Frontend React 19 · TypeScript · Vite · Tailwind CSS · shadcn/ui · React Query
Backend Express · TypeScript · Drizzle ORM · pg-boss (job scheduling)
Database PostgreSQL 16
Mobile Native iOS (SwiftUI, published) · native Android (Kotlin + Jetpack Compose, planned/in scaffold)
Email Resend · React Email templates
Push Provider-aware push delivery for native mobile clients, including direct APNs for iOS (gated behind PUSH_ENABLED)
Testing Vitest (unit/integration) · Playwright (E2E)
Monorepo pnpm workspaces

Architecture

The system follows a strict UI-as-projection model: the frontend renders engine state but never decides what's allowed. All mutations flow through a backend assignment engine that validates permissions, lifecycle state, and constraints before execution. Every mutation is auditable.

Key architectural layers:

  • Repository — Drizzle ORM data access with optimistic locking (version columns)
  • Assignment Engine — constraint validation, conflict detection, lifecycle enforcement
  • Controllers — HTTP boundary, actor-based authorization via requireRole() middleware
  • Frontend — React Query for server state, context providers for UI state only

Shared runtime + domain types live in packages/shared-types/. Node-targeted runtime consumers must resolve the package's built exports, not raw src/*.ts files.

See docs/ARCHITECTURE.md for the full architectural doctrine.

Mobile Strategy

  • iOS: apps/ios is the published native SwiftUI app.
  • Android: apps/android is the native Kotlin + Jetpack Compose forward path and is currently planned/in scaffold.
  • Retired: the React Native / Expo app formerly under apps/mobile has been removed and is no longer a supported app target.

Key Features

Schedule Lifecycle

Eight-phase extended lifecycle: draft → open_self_signup → admin_adjustment → open_supplemental → open_call → locked → balanced → published. Transitions are engine-validated with rollback support.

Signup Windows

Offset-based window definitions with eligibility rules. Windows are computed at release time into absolute-timestamped instances. Supports manual and scheduled release (via pg-boss).

Assignment Engine & Conflict Detection

Four mutation types (assign, unassign, reassign, move) with conflict detection across: shift overlap, max hours, max consecutive days, capacity, and role mismatch. Each conflict carries error or warning severity.

Changeset / Staging

Bulk edits staged in-memory, previewed before commit. Commit re-validates against fresh DB state. Pure staging engine (structuredClone isolation).

Staff Recurring Patterns

Per-staff patterns (recurring schedules, optional days, fixed schedules) resolved against schedule date ranges. Bulk-apply to draft schedules with conflict reporting.

Broadcasts & Comms

Manager-initiated broadcast messaging with audience targeting (department, role, schedule, individual staff). Read receipts, async email delivery via pg-boss.

Email Notifications

Provider-agnostic notification system with Resend + React Email. Triggers: schedule release, window open, schedule published. Staff opt-in/out per notification type.

Push Notifications (Mobile)

Provider-aware push delivery gated behind PUSH_ENABLED. The native iOS app registers APNs device tokens through the shared backend contract, and native Android will use the same mobile push-token boundary when rebuilt. Legacy Expo token support may remain server-side only until existing token rows and transport code are retired. Triggers: schedule released, signup window opened, broadcast received, schedule change. Per-staff push preference toggles live in the shared notification-preferences system. No-op in development — logs what would be sent for wiring verification.

Requests & Approvals

Time-off requests, shift trades (two-phase: counterpart → admin), and shift giveaways with claim workflow. Admin approval queue, staff My Requests page (web + mobile), assignment engine side effects on approval.

Multi-Admin Awareness

Advisory presence system via SSE — see who else is editing a schedule in real-time. Non-blocking, informational only.

Definition Snapshot Model

Schedule creation freezes all definitions (roles, tiers, scenarios, shift configs) into an immutable snapshot. Runtime reads from snapshot, not live definitions.

Staff Tier Constraints

Define shift count limits per staff tier — weekly and per-period windows with soft/hard enforcement. Pre-screens available shifts to prevent over-assignment.

Coverage Analytics

Visual coverage heatmaps, fill-rate tracking, and unfilled shift reporting. Identify understaffed periods at a glance.


Local Development

Prerequisites

  • Node.js 24 LTS (the supported runtime line for this monorepo)
  • pnpm 10+
  • Docker (for PostgreSQL)

Runtime Contract

  • packages/shared-types must export built artifacts from dist/, never raw src/*.ts runtime entrypoints.
  • apps/backend executes as direct Node ESM, so relative runtime imports must use explicit .js suffixes.
  • pnpm check:runtime-contracts enforces those rules, and pnpm smoke:backend-runtime boots apps/backend/dist/server.js and waits for /api/ready.

Run

docker compose up -d postgres
cd apps/backend && pnpm db:push && pnpm db:seed
cd apps/backend && pnpm dev          # :3002
cd apps/frontend && pnpm dev         # :5173 (proxies /api → :3002)

Testing

pnpm test:backend:db                                # full backend Vitest suite against shiftd_test
cd apps/backend && pnpm tsc --noEmit                # backend TypeScript
cd apps/frontend && pnpm check-types && pnpm lint    # TypeScript + ESLint
pnpm smoke:backend-runtime                           # direct Node 24 backend boot smoke (build + Postgres required)
pnpm test:e2e                                        # Playwright (requires running frontend + backend)
pnpm test:e2e:ui                                     # Playwright visual debugger

Environment Variables

Variable Required Purpose
DATABASE_URL Yes PostgreSQL connection string
JWT_SECRET Yes Auth token signing (min 32 chars in prod)
JWT_REFRESH_SECRET Yes (prod) Refresh token signing
RESEND_API_KEY No Email delivery (logs to console without it)
NOTIFICATION_FROM_EMAIL No Sender address for notifications
APP_BASE_URL No Base URL for email links
APP_BASE_HOST / VITE_APP_BASE_HOST No Overrides the default base host (getshiftd.com) for generated tenant URLs
PUSH_ENABLED No Enable mobile push notifications (true/false)
EXPO_ACCESS_TOKEN No Legacy Expo Push API access token, only while server-side Expo token support remains enabled
APNS_TEAM_ID / APNS_KEY_ID / APNS_BUNDLE_ID / APNS_PRIVATE_KEY No Direct APNs transport for native iOS push delivery

Authorization Model

Role hierarchy: staff < scheduler < admin < department_admin. Permissions augment role defaults (never remove). All API write operations require role-based authorization via requireRole() middleware.

Role Capabilities
staff View schedules, self-signup during open windows, submit requests
scheduler Assign/reassign staff, manage changesets, create broadcasts, apply patterns
admin Override constraints, manage definitions, delete schedules, manage users
department_admin Full department access including user management and bulk operations

Project Structure

apps/frontend/        # React SPA (web)
apps/backend/         # Express API server
apps/ios/             # Published native SwiftUI iOS app
apps/android/         # Native Kotlin + Jetpack Compose Android scaffold
packages/shared-types/ # Built shared runtime + domain types
docs/                 # Architecture doctrine, API spec, security audit
tests/e2e/            # Playwright test suites

Documentation

Topic File
Architecture doctrine docs/ARCHITECTURE.md
Implementation rules apps/backend/CLAUDE.md · apps/frontend/CLAUDE.md · apps/ios/README.md · apps/android/CLAUDE.md
API spec docs/openapi.yaml
Security guidelines docs/Security/SECURITY.md
Backend systems & patterns docs/agent/backend-systems.md
Frontend pages & layouts docs/agent/frontend-pages.md
Imported schedule onboarding docs/imported-schedule-onboarding.md
Operational UX map docs/operational-ux-phase.md
Priority 2 pilot readiness docs/runbooks/pilot-priority-2.md

Key Design Principles

No Automation Magic — The platform surfaces constraints and conflicts for human review. Scheduling decisions remain visible and auditable, not hidden behind opaque algorithms.

Engine-First Validation — All business rules live in the backend assignment engine, not the frontend. The UI can never bypass constraints.

Immutable History — Schedule definitions are frozen at creation time. Changes don't retroactively affect past schedules.

Multi-Tenancy Native — Two-level hierarchy (facilities → departments). Every entity is scoped to its department; users span across departments via platform roles.

Developer-Friendly — Clear separation of concerns, strong TypeScript types, comprehensive test coverage, and detailed architectural documentation.


Contributing

  • Read docs/ARCHITECTURE.md for design constraints and non-negotiable invariants
  • Check app-level CLAUDE.md files for gotchas and conventions
  • All mutations require end-to-end tests via Playwright
  • 80%+ test coverage required for new code

License

Proprietary. See LICENSE file for details. For licensing inquiries: info@getshiftd.com