medOS ultra

Nursing Kanban Board

Master plan for the ward nursing kanban surface.

12 min read diagramsUpdated 2026-05-14docs/architecture/nursing-kanban-board.md

Status: Proposal — 2026-05-14 Owner: plan@everapp.io Tagline: Don’t build a new Jira. Mount a Kanban view on top of the systems we already have, and let nurses use the same board for clinical work, sprint review, and feature requests.


1. Thesis

We have ~80% of a Kanban platform spread across 6 systems:

Jira concept medOS equivalent (already shipped)
Issue / Card Order + AcknowledgementRequest + FocusList item + medical-worklist row
Board department_queues (per dept, per status column)
Column / Status MASTER_WORKFLOW_NODES (typed state machine)
Swim lane Patient × encounter × nurse × shift
Workflow rules policy_gates (transition gates) + workflow_templates (graph)
Notifications / Watchers AcknowledgementRequest + central notification system
Sprint NurseShift (morning / noon / night / เวร)
Retrospective Care-plan evaluation column (already modeled in interfaceData2.ts)
Activity feed hospital_events + audit logs
Board config worklist-editor + main-flow-editor (visual workflow graph)
Recurring reviews cron_jobs registry
Card layout config Worklist-editor tab/column UI
Bulk actions BulkActionToolbar (nutrition miniapp) — already reusable

What we’re missing is the visual surface that unifies them and a thin “shift = sprint instance” wrapper. That’s it. No new database, no new realtime layer, no new permissions model.


2. Three boards, three timescales

A ward needs three concurrent boards, all backed by the same cards:

Board Cadence Source Audience
Shift board (live operations) 8-hour shift department_queues + active orders + open FocusList problems + pending acks Floor nurses
Care-plan board (per-patient) Per encounter, days→weeks FocusList items + linked interventions + evaluation status Charge nurse, primary nurse
Ward improvement board (meta) Sprints of 1–2 weeks Feature requests, policy-gate tweaks, equipment issues, training notes Head nurse, ward manager, super-admin

All three use the same card schema, the same drag-drop UX, the same filters. Just different default filters and column sets.


3. The card — one schema, five flavors

interface KanbanCard {
  id: string;                          // stable across realtime updates
  source: 'order' | 'focus' | 'ack' | 'worklist' | 'improvement';
  sourceRef: string;                   // FK back to the originating entity
  title: string;                       // problem name / order name / ack subject
  patientRef?: { _id: string; hn: string; name: string };
  encounterRef?: string;
  ward: string;                        // routing
  status: string;                      // MASTER_WORKFLOW_NODES state id
  priority: 'routine' | 'urgent' | 'stat';
  assignee?: { _id: string; name: string; role: string };
  watchers?: string[];                 // ack escalation chain
  due?: Date;                          // RRULE-derived for repeating
  shiftId?: string;                    // sprint instance — see §5
  labels?: string[];                   // free-form chips (NANDA Dx, focus group, etc.)
  color?: string;                      // derived (priority / NEWS2 / overdue)
  badges?: { news2?: number; mews?: number; falls?: 'high' | 'med' | 'low' };
  links?: { type: 'blocks' | 'blocked-by' | 'relates' | 'evaluates'; cardId: string }[];
  createdAt: Date;
  updatedAt: Date;
  // Optional render-on-card details, lazy-loaded:
  detail?: KanbanCardDetail;
}

No new table. KanbanCard is a view-model, projected by a small Supabase view (or edge function) that unions:

  • department_queues rows (operational queue)
  • orders with status (medication, lab, imaging, procedure)
  • acknowledgement_requests with status
  • focus_list items (care plan)
  • improvement_cards (one new tiny table — the only net-new schema)

Each row tags its source. Frontend can filter / split / merge cards by source without round-tripping.


4. Columns — derive, don’t hardcode

Columns come from the workflow template attached to the ward (workflow_templates).

  • Default ward template ships with 6 columns: To do → Doing → Awaiting result → Awaiting sign-off → Done → Carried over.
  • Per-ward templates override (ICU has Pre-procedure → In-procedure → Recovery → Discharge).
  • Column transitions are gated by policy_gates rows (already live).
  • Drag-drop calls the existing workflowActionHandler — no new state machine.

This is exactly the main-flow-editor model. The board UI is a horizontal projection of an existing workflow graph.


5. Sprint = Shift instance (the one net-new concept)

Sprints in nursing already exist — they’re called shifts (เวร). One small table:

create table nursing_shifts (
  id uuid primary key default gen_random_uuid(),
  ward text not null,
  shift_type nurse_shift not null,            -- existing enum: morning/noon/night
  date date not null,
  start_at timestamptz not null,
  end_at timestamptz not null,
  charge_nurse_id text,
  staff_ids text[],
  handover_from uuid references nursing_shifts(id),
  handover_to uuid references nursing_shifts(id),
  status text default 'planning',             -- planning | active | handover | closed
  notes text,
  created_at timestamptz default now()
);

create index on nursing_shifts (ward, date, shift_type);

That’s the entire new schema. Everything else hangs off shift_id as a label/filter on existing cards.

Lifecycle:

  1. Shift planning (15 min before start) — board opens in “planning” mode. Pull carried-over cards from previous shift, accept handover packet, claim assignments.
  2. Shift active — normal board operations.
  3. Shift handover (15 min before end) — board switches to “handover” mode. Generate handover packet: completed cards, in-flight cards, escalations, new problems opened. Acknowledgement chain to incoming charge nurse.
  4. Shift closed — read-only. Retrospective metrics computed by a cron job (median time-to-complete per source, # carried over, # escalated, NEWS2 worsening events).

6. Retrospective / Regression review — ride the evaluation column

The nursing-care-plan format already has evaluation as a first-class field in interfaceData2.ts. The board treats it as a column with two flavors:

  • Per-shift retrospective — at shift close, surface cards whose interventions completed and ask the charge nurse to write the evaluation. Hijack AcknowledgementRequest for the sign-off.
  • Per-encounter regression — when an encounter discharges, run a cron-job-scheduled review: every focus opened during the encounter, every linked intervention, every evaluation. Cards that closed without evaluation = QA flag, posted to the ward improvement board.

This is the same evaluation field nurses already fill in. We’re not adding a new ritual — we’re surfacing the existing one as a column.


7. Ward improvement board — the “new features for them” surface

A 6th card source: improvement_cards. One small table:

create table improvement_cards (
  id uuid primary key default gen_random_uuid(),
  ward text not null,
  category text not null,        -- 'feature' | 'bug' | 'policy' | 'equipment' | 'training'
  title text not null,
  description text,
  reporter_id text not null,
  reporter_role text,
  priority text default 'medium',
  status text default 'triage',  -- triage | accepted | in-progress | done | rejected
  assigned_to text,              -- admin / dev / vendor
  linked_policy_gate_id uuid references policy_gates(id),
  votes int default 0,
  attachments jsonb,
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

This is the channel for nurses to file:

  • “The MAR dialog doesn’t auto-focus the dose field” → routes to dev queue
  • “We need a column for restraint-check time” → links to a policy_gate proposal
  • “The blanket warmer in Room 4 broke again” → routes to facilities
  • “I want training on the new IV pump” → routes to in-service ed

Cards triaged by ward manager become input to the actual cron_jobs admin UI, the policy-gates admin UI, or routed to whoever owns the area. Same drag-drop board, different default filter.


8. What to ride / hijack (concrete file paths)

Existing system Hijack as Path
department_queues read model Card source for operational queue infrastructure/medbase/migrations/021_*.sql and successors
MASTER_WORKFLOW_NODES Column definitions workflowState.ts
policy_gates Column transition rules policy-gates.md
workflow_templates Per-ward board template worklist-editor/
worklist-editor Board settings UI (card layout, columns) same
main-flow-editor Visual column-graph editor for ward admins main-flow-editor/
workflowActionHandler Drag-drop → state transition workflowActionHandler.ts
AcknowledgementRequest Card sign-off / escalation / reminders acknowledgement-system.md
cron_jobs registry Scheduled retrospectives + regression review cron-jobs-registry.md
manifest-data-layer Card data transport with realtime + adapter pattern manifest-data-layer/
useManifestMedicalWorklist hook Board data hook same
NurseShift enum Sprint type interfaceData2.ts
FocusList (goal/outcomes/assessment/intervention/evaluation) Card structure for care plan same
NursingCarePlanTarget (2759 LOC sandbox) Card detail dialog NursingCarePlanTarget.tsx
BulkActionToolbar (nutrition) Multi-select card operations BulkActionToolbar.tsx
QueueManagementFloater Per-page board FAB queue-management-floater.md
hospital_events → orchestrator Realtime card updates encounter-orchestrator-triggers.md
dynamic-sheet-labour-room-v2 Bento toolbar pattern Sub-toolbar for board actions (just landed in 2d9d4192)
Order system (medical-kit/src/order/) Card source: medication / lab / imaging / procedure orders many files

Don’t build: new DB realtime, new notification system, new permissions, new audit log, new schedule engine, new bulk-edit, new bilingual layer, new state machine. All exist.


9. Phased build

Phase 0 — Read-only Kanban view (1 module-loop, ~3 days)

  • One sandbox target: WardKanbanTarget.
  • Card view-model union over department_queues + open orders + focus_list + acknowledgement_requests.
  • Columns from a hardcoded default workflow template (no policy gates yet).
  • No mutations — just render cards in columns with filter by ward / shift / nurse.
  • Realtime via existing manifest-data-layer subscriptions.
  • Demo: “here are all the work items for Ward 4 right now, grouped by status.”

Phase 1 — Drag-drop + policy-gated transitions (1 loop)

  • Wire drag-drop to existing workflowActionHandler.
  • Pull column definitions from workflow_templates per ward.
  • Honor policy_gates on transitions — if denied, snap back + show the gate’s denial_reason.
  • Demo: “drag a MAR card from To-do → Doing; cashier hold blocks discharge card; policy rule live-editable.”

Phase 2 — Shift sprint wrapper (1 loop)

  • nursing_shifts table + planning/active/handover/closed lifecycle.
  • Shift filter on board, handover-packet generator (PDF via printing service).
  • Acknowledgement chain for handover sign-off.
  • Demo: “morning charge nurse hands off to noon shift; carried-over cards auto-attach to new shift.”

Phase 3 — Care-plan board with intervention→evaluation linking (1 loop)

  • Repurpose NursingCarePlanTarget as card detail dialog.
  • Add evaluation column to the per-patient board view.
  • Acknowledgement-system hooks for charge-nurse evaluation sign-off.
  • Demo: “open IICP focus card; see linked interventions across 3 shifts; sign off evaluation.”

Phase 4 — Ward improvement board (1 loop)

  • improvement_cards table + admin routing.
  • Free-form card creation from any board (“Report an issue with this column”).
  • Triage filter for ward manager.
  • Link improvement → policy_gate proposal (deep-link into existing policy-gates admin UI).
  • Demo: “nurse files MAR-autofocus feature; ward manager triages; routes to dev queue; one-click create policy-gate.”

Phase 5 — Sprint review + regression review automation (1 loop)

  • Cron-job: shift-close retrospective (metrics per source, NEWS2 worsening, carried-over count).
  • Cron-job: encounter-discharge care-plan regression (unevaluated focus → QA flag).
  • Read-only metrics dashboard per ward.
  • Demo: “ward KPI page; click into ‘unevaluated focus’ flag; see exactly which encounter, which nurse.”

Phase 6 — Mount in production routes

  • /ward/:wardId/board — shift board.
  • /encounter/:id/care-plan-board — per-encounter board.
  • /ward/:wardId/improvement — ward improvement board.
  • /admin/ward-boards — head nurse / super-admin overview.
  • Register all 4 as DynamicCoreApp.WARD_KANBAN_* so they can be embedded in patient profile tabs / clinic workspace widgets.

Total: 6 loops, ~3 weeks if focused. Phase 0 is demoable on its own.


10. Risks / tradeoffs

Risk Mitigation
Card source union becomes a 4-table JOIN nightmare Use a materialized view refreshed on hospital_events, not live JOIN
Drag-drop fights with policy gates Optimistic UI + snap-back; never let the card commit before backend confirms
improvement_cards becomes a feature graveyard Ward manager must triage within 7 days (cron-job nag); votes from nurses bubble up
Per-ward column customization explodes config surface Ship 3 ward templates (general / ICU / OR-recovery); custom only via head-nurse override
Shift handover packet becomes a PDF nobody reads Make it the board state itself — handover = next shift opens the same board pre-filtered
Performance with 200+ cards per ward Virtualize columns; cards lazy-load detail; pagination at 50 per column
i18n burden (TH primary, EN secondary, JA/FIL for market packs) Card schema is data — labels are template-driven; no new translation keys for the engine
“Yet another board” rejection by nurses Don’t ship as net-new; replace the existing focus-list table view with the board, keep table view as a toggle

11. The hijack opportunity that ties it all together

The single biggest leverage: the board is just a different rendering of the existing workflow graph. Every clinical workflow already has a workflow_template with MASTER_WORKFLOW_NODES. Today we render those as:

  • main-flow-editor graphs (admin)
  • worklist-editor tabs + queues (operational)
  • Patient-journey timelines (per-patient)

Adding Kanban as a 4th rendering is mostly UI work. Same nodes, same edges, same policies. Different camera angle.

If we land Phase 0, we get this for free in 12 other places:

  • Doctor consult worklist → Kanban
  • Lab specimen tracking → Kanban
  • Pharmacy verification queue → Kanban
  • OR scheduling → Kanban
  • Discharge pipeline → Kanban (the existing IPD discharge cockpit is already 90% this shape)
  • Imaging acknowledgement queue → Kanban
  • Cashier billing queue → Kanban

So this isn’t a nursing feature — it’s a rendering primitive for the whole workflow layer. Nursing is just the best beachhead because (a) nurses already think in shift cycles, (b) the care-plan format already has assessment → intervention → evaluation columns, and © the NursingCarePlanTarget prototype proves the UX.


12. First concrete step

If approved, the smallest demoable slice:

  1. Create web/sandbox/targets/WardKanbanTarget.tsx (~400 LOC).
  2. Use useManifestMedicalWorklist for data, group by MASTER_WORKFLOW_NODES state.
  3. Hardcode 6 columns for “general ward” template.
  4. Wire 3 card sources: orders, focus list items, pending acknowledgements.
  5. Filter chips: ward, shift, nurse, priority.
  6. Drag-drop optimistic only (no policy gates yet).

Demoable in one sitting on http://localhost:5179/?target=WardKanban. Decision point at the demo: do we proceed to Phase 1, or pivot.

Ask Anything