LumisCare — Enterprise Healthcare Platform

Home health and community care management SaaS. Rebrand from VivaCareUSA. Stack: React 19, Java 21 Spring Boot, Azure.

Rebrand Plan — VivaCareUSA → LumisCare

Plan: LumisCare Rebrand — VivaCareUSA → LumisCare

Architect: Petter Graff (Team Lead) Date: 2026-04-05 Estimated execution: 1 working day


Research Summary

Golden Commit

c80a3637 — "ALL TESTS GREEN: Element 100%, CEO 100%, Flow PASS" (2026-01-25) This is the autocoder Day 1 commit: full project skeleton + 500 features registered in features.db. No VivaCareUSA-branded code built yet — cleanest possible rebrand starting point. 411 commits of autocoder feature builds come after this. We rebrand the skeleton, then rerun autocoder.

What Needs Rebranding

Design Tokens — Already Correct

index.css already has the right colors (Jade Green, Neon Blue, Mint Green). Only comments and legacy var names need updating.

Infrastructure — Already Exists

Azure Container Apps, Static Web Apps, Bicep IaC all deployed. deploy-frontends.sh + deploy-demo.sh exist and work.

The Core Problem

10 days of localStorage migrations, BFF wiring, header standardization — none of it was requested. The golden commit worked. We restore it, rebrand it, ship it.


Objective

Branch off c80a3637 (project skeleton, 500 features in DB, zero built code), rebrand all skeleton files (VivaCareUSA/VCC → LumisCare/LC), then run AutoCoder to rebuild all 500 features with LumisCare branding from day 1. No migrations. No patching. Clean rebuild.


Team Orchestration

Team Members

ID Name Role Agent
B1 branch-builder Create clean rebrand branch from golden commit builder
V1 branch-validator Verify branch is clean and builds validator
B2 rebrand-builder Execute mechanical find-replace rebrand codecraft
V2 rebrand-validator Verify zero VCC references remain, app builds validator
B3 design-builder Update CSS legacy var names + comments only builder
V3 design-validator Verify design tokens are correct, no visual regression validator
B4 deploy-builder Deploy to Azure dev environment flowforge
V4 deploy-validator Playwright smoke test on deployed URL sentinel-tester

Step-by-Step Tasks

Phase 1: Restore Golden State

Task 1.1 — Create rebrand branch from c80a3637 skeleton

Task 1.2 — Validate skeleton compiles


Phase 2: Mechanical Rebrand

Task 2.1 — Execute find-replace rebrand

Task 2.2 — Validate zero VCC references


Phase 3: Design Token Cleanup

Task 3.1 — Update CSS comments and legacy var names

Task 3.2 — Validate design tokens


Phase 4: Deploy

Task 4.1 — Deploy to Azure dev environment

Task 4.2 — Smoke test deployed app


Validation Commands (Final)

# 1. Zero VCC references in frontend
grep -rn "VCC\|VivaCare\|vivacare" ~/projects/client/lumiscare/frontend/web/src/ \
  | grep -v "//\|node_modules" | wc -l
# Expected: 0

# 2. Build passes
cd ~/projects/client/lumiscare/frontend/web && yarn build && yarn type-check

# 3. Portal URLs return 200
curl -s -o /dev/null -w "%{http_code}" https://jolly-bay-01cfa3003.6.azurestaticapps.net
curl -s -o /dev/null -w "%{http_code}" https://zealous-hill-097d4b803.6.azurestaticapps.net
curl -s -o /dev/null -w "%{http_code}" https://white-island-07c0e4c03.4.azurestaticapps.net

What This Plan Does NOT Do

Restore → Rebrand → Deploy. That's it.


Risk

Risk Mitigation
Azure DevOps pipeline still named "VCC" Rename pipeline display name only — do NOT touch infra resource names (breaking change)
Backend services still use X-VCC-* headers Frontend and backend header rename must be done in same PR, or keep old header names and only rename in comments
8b0effdc missing some later fixes V1 task verifies build — if broken, use next clean commit after 8b0effdc

Note on headers: X-VCC-Organization-Id is sent by frontend AND read by backend services. If we rename on frontend only, backend breaks. Either rename both simultaneously, or leave headers as-is (they're internal API headers, not user-visible branding).


Execution

Run /build-plan to execute with agent teams.

Architecture — Component HLD Master

LumisCare — Component High-Level Design Master Document

Version: 1.0 Date: 2026-04-04 Author: Dr. Sarah Chen, Healthcare IT Systems Architect Status: Active — Reflects verified implementation state as of 2026-04-04 Method: Static analysis of source tree + HLD document review + gap analysis synthesis


Document Purpose

This document provides the authoritative component-level HLD for all LumisCare microservices, BFF layers, and frontend features. It cross-references the documented architecture (VCC2-C4-Architecture-Diagrams.md, Services-Integration-Matrix.md, BFF-Architecture-Design.md, Service-Bus-Subscriptions-Design.md) against verified implementation on disk.

Each component section records: implementation status, controller/entity counts, BFF integration status, event bus wiring status, and known gaps.

CRITICAL NOTE — Naming inconsistency: HLD documents use "VCC 2.0" throughout. The BFF design switches to "iCON". The deployed product is "LumisCare". All three names refer to the same system. This document uses "LumisCare" as the canonical product name.


System Architecture Summary

Web (React 19) ──────────────────────── Web BFF (port 8080)
                                                │
Mobile (React Native / Expo SDK 52) ──── Mobile BFF
                                                │
                               ┌────────────────┴───────────────────┐
                               │    MICROSERVICES LAYER              │
                               │  (Java 21, Spring Boot 3.4)         │
                               │                                     │
                               │  identity-service                   │
                               │  assessment-service                 │
                               │  careplan-service                   │
                               │  visits-service                     │
                               │  hr-service                         │
                               │  scheduling-service                 │
                               │  incidents-service                  │
                               │  finance-service                    │
                               │  notification-service               │
                               │  safety-service                     │
                               │  policy-service                     │
                               │  document-service                   │
                               │  fhir-adapter-service              │
                               └─────────────────────────────────────┘
                                               │
                              Azure Service Bus (domain-events topic)
                              Azure PostgreSQL (per-service databases)
                              Azure Redis (shared cache)
                              Azure Blob Storage (documents)

Multi-tenancy: Row-Level Security (RLS) on organisation_id across all service databases. Auth: Azure Entra ID (MSAL) — JWT pass-through from BFF to microservices. Service-to-service via Azure Managed Identity. Deployment: Azure Container Apps (AKS target). Azure Static Web Apps for frontend.


Component Status Legend

Status Meaning
PRODUCTION-READY Controllers, entities, repositories, and migrations all present and verified
PARTIAL Core entities and controllers present but key integration (event bus, BFF, mobile) absent
SKELETON Directory exists, minimal or no Java source files
UNDOCUMENTED Implemented in code but absent from all HLD documents
DESIGN-ONLY Documented in HLD but not implemented in code

Component Index

  1. Identity
  2. HR
  3. Visits
  4. Scheduling
  5. Care Plans
  6. Assessments
  7. Incidents
  8. Finance
  9. Notifications
  10. Safety
  11. Policy (AI/RAG)
  12. Document
  13. FHIR Adapter
  14. Web BFF
  15. Mobile BFF

1. Identity

Purpose

Manages users, organisations, service users, RBAC roles, consent records, PHI access audit, and GDPR data rights. Serves as the authentication enrichment layer for Azure Entra ID tokens — all services call identity-service to resolve user context from JWTs.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


2. HR

Purpose

Manages employee records, qualifications, training certifications, availability preferences, leave management, performance reviews, and equality/diversity data. Acts as the canonical source of carer workforce data for the scheduling-service.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


3. Visits

Purpose

Manages the full visit execution lifecycle: Electronic Visit Verification (EVV) check-in/check-out, care note recording, eMAR (electronic medication administration record), vital sign capture, task completion, observation recording, real-time carer location tracking, and geofence enforcement. The most clinically active service during field operations.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


4. Scheduling

Purpose

Creates, manages, and publishes care schedules. Handles recurring appointment generation, carer assignment with skill matching, schedule approval workflow, cover arrangements, and proposed appointment review. Bridges care plan proposed visits and operational visit execution.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


5. Care Plans

Purpose

Manages the full care plan lifecycle: AI-assisted generation from assessments, plan versioning, task definition, master visit type configuration, and proposed visit generation. The care plan is the primary clinical document linking assessment outcomes to scheduled care delivery.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


6. Assessments

Purpose

Manages the complete clinical assessment lifecycle: intake, section/question/answer management, risk assessments (NEWS2, Waterlow, PHQ-9, GAD-7), Mental Capacity Assessment (MCA), DNACPR order management, medication reconciliation, clinical scoring, AI-assisted assessment transcription, and real-time collaborative assessment via Azure Web PubSub.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


7. Incidents

Purpose

Manages incident reporting, safeguarding concerns, hazard logging, complaints management, and CQC statutory reporting evidence. Provides CSV export for regulatory data extraction during CQC inspections.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


8. Finance

Purpose

Manages the complete financial lifecycle: invoice generation, pay rates, payroll, timesheet management, insurance claim generation (837P/837I EDI), remittance reconciliation (835 EDI), gross profit analysis, hours variance reporting, and payer management. The largest service by code volume in the fleet.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


9. Notifications

Purpose

Multi-channel notification dispatch: push (Firebase Cloud Messaging), email (SendGrid), SMS (Twilio), and in-app inbox. Consumes domain events from Azure Service Bus and routes them to appropriate users based on notification preferences and rate limits. Maintains notification history and delivery analytics.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


10. Safety

Purpose

Manages lone worker protection (LWP), SOS emergency alerts, and emergency contact management. The LWP timer service runs server-side (not dependent on carer device signal) and escalates overdue check-in sessions through a supervisor notification ladder. This service addresses the CQC requirement for lone worker safety in domiciliary care.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


11. Policy (AI / RAG)

Purpose

Provides RAG (Retrieval-Augmented Generation) based policy question-and-answer capability. Care workers and managers can ask questions about organisational policies, CQC standards, and care protocols in natural language. The service chunks policy documents, stores vector embeddings, and queries them via Azure OpenAI.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


12. Document

Purpose

Manages document storage, retrieval, and retention for clinical and operational documents. Uses Azure Blob Storage as the backing store with application-level retention policy enforcement. Supports document upload, categorisation, and time-limited access via pre-signed URLs.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


13. FHIR Adapter

Purpose

Exposes FHIR R4 resources (Patient, Observation, MedicationStatement) for interoperability with NHS systems, third-party care management platforms, and referral networks. Enables LumisCare to participate in NHS DSCR (Digitising Social Care Record) programme and GP Connect workflows.

Backend Service

Frontend

BFF Integration

Event Bus

Gaps


14. Web BFF

Purpose

Backend-for-Frontend aggregation layer for the React 19 web application. Orchestrates parallel and sequential calls to microservices, aggregates responses, enforces JWT validation, applies rate limiting (via Azure API Management), and provides OpenAPI-generated typed client contracts. Port 8080.

Backend Service

Frontend Integration

BFF Integration

Event Bus

Gaps


15. Mobile BFF

Purpose

Backend-for-Frontend aggregation layer for the React Native / Expo field worker mobile application. Provides a minimal, mobile-optimised API surface for care execution: care plan read access, appointment viewing, assessment submission, risk assessment, and blob storage for photos. Port not confirmed.

Backend Service

Frontend Integration

BFF Integration

Event Bus

Gaps


Event Bus Summary Table

Event Producer Publisher Code? Consumer Listener Code? Status
assessment.completed assessment-service NO careplan-service NO NOT WIRED
careplan.published careplan-service NO scheduling-service CarePlanEventIdempotencyEntity (ready) NOT WIRED
careplan.updated careplan-service NO visits-service NO NOT WIRED
schedule.published scheduling-service AppointmentEventPublisher YES notification-service @ServiceBusListener COMMENTED OUT BROKEN
schedule.updated scheduling-service AppointmentEventPublisher YES visits-service NO PARTIALLY WIRED
visit.checkedin visits-service VisitEventPublisher YES notification-service @ServiceBusListener COMMENTED OUT BROKEN
visit.completed visits-service VisitEventPublisher YES finance-service NO PARTIALLY WIRED
task.flagged visits-service VisitEventPublisher YES notification-service @ServiceBusListener COMMENTED OUT BROKEN
checkin.timeout visits-service VisitEventPublisher YES notification-service @ServiceBusListener COMMENTED OUT BROKEN
assistance.requested visits-service VisitEventPublisher YES notification-service @ServiceBusListener COMMENTED OUT BROKEN
invoice.created finance-service OutboxEvent entity only — NO publisher notification-service @ServiceBusListener COMMENTED OUT NOT WIRED
invoice.paid finance-service NO notification-service @ServiceBusListener COMMENTED OUT NOT WIRED
timesheet.created finance-service NO notification-service @ServiceBusListener COMMENTED OUT NOT WIRED
employee.created hr-service HrEventPublisher YES identity-service NO confirmed listener PARTIALLY WIRED
employee.terminated hr-service HrEventPublisher YES scheduling-service NO PARTIALLY WIRED
availability.updated hr-service HrEventPublisher YES scheduling-service AvailabilityUpdatedEventListener YES WIRED
leave.approved hr-service HrEventPublisher YES scheduling-service NO confirmed listener PARTIALLY WIRED
incident.created incidents-service EventPublisher YES (outbox) notification-service @ServiceBusListener COMMENTED OUT BROKEN
notification.sent notification-service NotificationEventPublisher YES analytics-service NOT IMPLEMENTED PARTIALLY WIRED

Summary: HR → Scheduling (availability.updated) is the only fully wired event chain. The primary clinical workflow (Assessment → CarePlan → Scheduling → Visits → Finance) has broken links at every node.


Priority Remediation Register

P0 — Patient Safety and Compliance Blocking

P0-001: Uncomment @ServiceBusListener in notification-service

P0-002: Resolve DNACPR dual-domain ownership

P1 — Regulatory Exposure

P1-001: Add event publisher to assessment-service for assessment.completed

P1-002: Add event publisher to careplan-service for careplan.published

P1-003: Add mobile BFF controllers for eMAR, EVV, incidents, and SOS

P1-004: Implement mandatory notification deadline and automated escalation in incidents-service

P1-005: Document and security-review fhir-adapter-service

P2 — Architecture Integrity

P2-001: Implement OutboxEventPublisher in finance-service

P2-002: Add finance-service listener for visit.completed event

P2-003: Confirm EmarController enforces witness requirement at service layer

P2-004: Add Flyway migrations to bring visits-service (7) and assessment-service (8) in line with entity complexity

P2-005: Standardise finance-service package namespace from com.lumiscare.icon.finance to com.lumiscare.finance

P2-006: Operationalise yarn generate:api pipeline


Architectural Risks

Risk Severity Description
BFF-less frontend in production CRITICAL Frontend routes to old Django monolith, not web-bff. All microservices are bypassed.
Broken clinical workflow event chain HIGH Assessment → CarePlan → Schedule → Visit → Finance has multiple broken publisher/subscriber links
Notification service deaf to event bus HIGH @ServiceBusListener commented out — all event-driven alerts are non-functional
Four undocumented services in production path HIGH safety, policy, document, fhir-adapter — no API contracts, no security posture
FHIR PHI exposure HIGH FHIR R4 resources expose PHI without documented authentication controls
Finance event bus gap MEDIUM Transactional outbox started but publisher absent — billing events are silent
Mobile BFF coverage gap HIGH eMAR, EVV, incidents, SOS absent from mobile BFF — direct service calls bypass auth boundary
DNACPR dual ownership HIGH Resuscitation decision data in two services with no confirmed sync
CQC mandatory notification deadline MEDIUM No automated enforcement for 24-hour statutory reporting requirement
OpenAPI client drift MEDIUM 6 of 10 services accessed via manual WebClient — contract drift inevitable

Document History

Version Date Author Changes
1.0 2026-04-04 Dr. Sarah Chen Initial — 13 components + 2 BFFs documented. Evidence base: static filesystem analysis + HLD document review. Cross-reference with lumiscare-backend-lld.md and lumiscare-hld-gap.md.

Architecture — Event Bus Map

LumisCare Event Bus — Current State Map

Date: 2026-04-04 Author: Martin Kleppmann (Distributed Systems Audit) Method: Static analysis of all publisher and listener classes in backend/services/ Source of truth: Actual Java source files, not design documents


Architecture

Azure Service Bus Premium tier, topics/subscriptions model. Each service owns its own topic and publishes events to it. Consumers subscribe to specific topics with SQL filters on event_type.

The design document (Service-Bus-Subscriptions-Design.md) specifies three topics: visit-events, schedule-events, notification-events. The actual implementation has diverged — publishers use five distinct topic names across six services, and the notification-service listener is wired to a different topic (domain-events) than what the visit and scheduling publishers write to.


Event Flow Diagram

graph LR
  subgraph WIRED["FULLY WIRED"]
    HR["hr-service<br/>(HrEventPublisher)"]
    SCHED["scheduling-service<br/>(AppointmentEventPublisher)"]
    SCHED_AVAIL["scheduling-service<br/>(HrAvailabilityUpdatedEventHandler)"]
    NOTIF_PUB["notification-service<br/>(NotificationEventPublisher)"]
  end

  subgraph PARTIAL["PARTIALLY WIRED — publisher exists, consumer absent or mis-wired"]
    VISITS["visits-service<br/>(VisitEventPublisher)"]
    INCIDENTS["incidents-service<br/>(EventPublisher)"]
    SAFETY["safety-service<br/>(SafetyEventPublisher)"]
    NOTIF_LISTEN["notification-service<br/>(ServiceBusEventListener)"]
    SCHED_CAREPLAN["scheduling-service<br/>(CarePlanPublishedEventHandler)"]
  end

  subgraph BROKEN["BROKEN — no publisher class exists"]
    ASSESS["assessment-service"]
    CAREPLAN["careplan-service"]
    FINANCE["finance-service<br/>(OutboxEvent entity only)"]
  end

  HR -->|"employee.created/updated<br/>availability.updated<br/>leave.approved<br/>certification.expiring<br/>topic: domain-events"| SCHED_AVAIL
  HR -->|"leave.approved<br/>topic: domain-events"| NOTIF_LISTEN
  VISITS -->|"visit.started/completed/missed<br/>visit.task.completed<br/>topic: visits-events"| NOTIF_LISTEN
  VISITS -->|"visit.completed<br/>topic: visits-events"| FINANCE_STUB["finance-service<br/>(NO listener class)"]
  SCHED -->|"schedule.published/updated<br/>appointment.created/updated/cancelled<br/>topic: scheduling-events"| NOTIF_LISTEN
  NOTIF_PUB -->|"notification.sent/failed/acknowledged<br/>topic: notification-events"| ANALYTICS_STUB["analytics-service<br/>(NOT IMPLEMENTED)"]
  INCIDENTS -->|"incident.created<br/>topic: incidents-events"| NOTIF_LISTEN
  SAFETY -->|"lwp.escalation.*<br/>topic: safety-events"| NOTIF_LISTEN
  CAREPLAN_STUB["careplan-service<br/>(NO publisher)"] -.->|"careplan.published — MISSING"| SCHED_CAREPLAN
  ASSESS -.->|"assessment.completed — MISSING"| CAREPLAN_STUB

  style WIRED fill:#1a4731,color:#fff
  style PARTIAL fill:#713f12,color:#fff
  style BROKEN fill:#7f1d1d,color:#fff

Critical Architectural Finding: Topic Name Mismatch

The notification-service ServiceBusEventListener subscribes to topic domain-events (default configured at ServiceBusConfig.java:29):

azure.servicebus.topic-name:domain-events

The visits-service VisitEventPublisher publishes to topic visits-events (default configured at VisitEventPublisher.java:45):

azure.servicebus.visits-topic-name:visits-events

The scheduling-service AppointmentEventPublisher publishes to topic scheduling-events (default configured at AppointmentEventPublisher.java:45):

azure.servicebus.scheduling-topic-name:scheduling-events

The HR-service HrEventPublisher publishes to topic domain-events (default configured at HrEventPublisher.java:40):

azure.servicebus.topic-name:domain-events

This means: the notification-service listener will receive HR events but will silently miss all visit and schedule events at runtime unless the application properties are overridden in deployment configuration. There are no application.properties or application.yml files with explicit topic overrides found in the source tree — only Spring @Value defaults. This must be validated against the actual Azure Container Apps environment variables before treating any visit-to-notification flow as working.


Event-by-Event Status

Event Topic (default) Producer Service Publisher Class Consumer Service Listener Class Status
employee.created domain-events hr-service HrEventPublisher scheduling-service HrAvailabilityUpdatedEventHandler WIRED — both sides present
employee.updated domain-events hr-service HrEventPublisher scheduling-service HrAvailabilityUpdatedEventHandler WIRED — both sides present
availability.updated domain-events hr-service HrEventPublisher (via AvailabilityPreferencesService) scheduling-service HrAvailabilityUpdatedEventHandler (listens for hr.availability.updated) WIRED — subject used in code is hr.availability.updated, design doc says availability.updated — schema mismatch risk
leave.approved domain-events hr-service HrEventPublisher (via LeaveManagementService) notification-service ServiceBusEventListener (case leave.approved) WIRED — both sides on same topic
certification.expiring domain-events hr-service HrEventPublisher (via CertificationExpiryScheduler) notification-service ServiceBusEventListener (case certification.expiring) WIRED — both sides on same topic
visit.started visits-events visits-service VisitEventPublisher.publishVisitStarted() notification-service ServiceBusEventListener (case visit.checkedin — event name mismatch) BROKEN — publisher emits visit.started, listener handles visit.checkedin; different names
visit.completed visits-events visits-service VisitEventPublisher.publishVisitCompleted() notification-service ServiceBusEventListener (case visit.completed) TOPIC MISMATCH — publisher on visits-events, listener on domain-events
visit.completed visits-events visits-service VisitEventPublisher.publishVisitCompleted() finance-service No listener class found NOT WIRED — finance has no Service Bus consumer
visit.missed visits-events visits-service VisitEventPublisher.publishVisitMissed() notification-service No explicit case in listener NOT HANDLED — listener has no visit.missed case
visit.task.completed visits-events visits-service VisitEventPublisher.publishTaskCompleted() notification-service No explicit case in listener NOT HANDLED
checkin.timeout visits-events visits-service NOT FOUND in VisitEventPublisher methods notification-service ServiceBusEventListener (case checkin.timeout) PUBLISHER ABSENT — listener expects this event but publisher has no publishCheckinTimeout() method
assistance.requested visits-events visits-service NOT FOUND in VisitEventPublisher methods notification-service ServiceBusEventListener (case assistance.requested) PUBLISHER ABSENT — listener expects this event but publisher has no method
task.flagged visits-events visits-service NOT FOUND in VisitEventPublisher methods notification-service ServiceBusEventListener (case task.flagged) PUBLISHER ABSENT — listener expects this but only visit.task.completed is published
redflag.detected unknown unknown NOT FOUND notification-service ServiceBusEventListener (case redflag.detected) PUBLISHER ABSENT — no publisher produces this event
visit.reassigned unknown unknown NOT FOUND notification-service ServiceBusEventListener (case visit.reassigned) PUBLISHER ABSENT
schedule.published scheduling-events scheduling-service AppointmentEventPublisher.publishSchedulePublished() notification-service ServiceBusEventListener (case schedule.published) TOPIC MISMATCH — publisher on scheduling-events, listener on domain-events
schedule.updated scheduling-events scheduling-service AppointmentEventPublisher (no explicit publishScheduleUpdated found — has publishScheduleApproved) notification-service ServiceBusEventListener (case not found) PARTIAL — method naming diverges from design doc
careplan.published careplan-events careplan-service NO PUBLISHER CLASS scheduling-service CarePlanPublishedEventHandler (subscribes to careplan-events) BROKEN — listener fully implemented, publisher does not exist
careplan.updated unknown careplan-service NO PUBLISHER CLASS notification-service ServiceBusEventListener (case careplan.updated) BROKEN — no publisher
assessment.completed unknown assessment-service NO PUBLISHER CLASS careplan-service NO LISTENER CLASS NOT WIRED — entire chain absent
incident.created incidents-events incidents-service EventPublisher notification-service ServiceBusEventListener — no incident.created case found in routing switch TOPIC MISMATCH + case absent — publisher on incidents-events, listener on domain-events
lwp.escalation.level1/2/3/4 safety-events safety-service SafetyEventPublisher.publishLWPEscalation() notification-service ServiceBusEventListener (cases lwp.escalation.level1 through level4) TOPIC MISMATCH — publisher on safety-events, listener on domain-events
invoice.created none finance-service NO PUBLISHER — only OutboxEvent entity + repository notification-service ServiceBusEventListener (no case found) NOT WIRED — outbox pattern incomplete, no dispatcher daemon
invoice.paid none finance-service NO PUBLISHER analytics-service NOT IMPLEMENTED NOT WIRED
timesheet.created none finance-service NO PUBLISHER — TimesheetBatchJobProcessor writes OutboxEvent but no Service Bus dispatch notification-service ServiceBusEventListener (no case found) NOT WIRED — outbox records written to DB but no relay to Service Bus
notification.sent notification-events notification-service NotificationEventPublisher.publishNotificationSent() analytics-service NOT IMPLEMENTED PUBLISHER WIRED, consumer service does not exist
notification.failed notification-events notification-service NotificationEventPublisher.publishNotificationFailed() analytics-service NOT IMPLEMENTED PUBLISHER WIRED, consumer service does not exist
daily.summary unknown unknown NOT FOUND notification-service ServiceBusEventListener (case daily.summary) PUBLISHER ABSENT

Broken Chains

Chain 1: Assessment to Care Plan AI Generation (Clinical Safety Risk)

The primary clinical workflow trigger is broken at its first link.

Where it breaks: assessment-service/src/main/java/ — no *Publisher*.java file exists in this directory.

Chain 2: Care Plan to Scheduling (Scheduling Cannot Start Automatically)

The CarePlanPublishedEventHandler in scheduling-service is fully implemented (300+ lines, idempotency logic, recurring schedule creation). It is waiting for a careplan.published event on topic careplan-events. That event is never published.

Where it breaks: careplan-service/src/main/java/ — no *Publisher*.java file exists. The handler waiting for the event is at scheduling-service/src/main/java/com/lumiscare/scheduling/event/CarePlanPublishedEventHandler.java:101.

Chain 3: Visit Check-in to Notification (Event Name Mismatch)

The design document specifies visit.checkedin. The VisitEventPublisher publishes visit.started (set at VisitEventPublisher.java:127). The ServiceBusEventListener routes on visit.checkedin (at ServiceBusEventListener.java:207). These names do not match. Even if the topic mismatch were fixed, this chain would still silently fail.

Where it breaks:

Chain 4: Visit Completed to Finance (Finance Cannot Generate Invoice Line Items)

VisitEventPublisher.publishVisitCompleted() publishes to topic visits-events. The finance-service has no ServiceBusProcessorClient, no listener class, and no subscription configuration. The billing data embedded in the visit.completed payload (rates, task categories, mileage) is never consumed. Invoice line item generation is not automated.

Where it breaks: finance-service/src/main/java/ — no Service Bus consumer class of any kind. Finance only writes OutboxEvent records to its own database for the timesheet batch job, which itself has no Service Bus dispatcher.

Chain 5: Critical Safety Alerts Silently Dropped (Topic Mismatch)

SafetyEventPublisher publishes to topic safety-events. ServiceBusEventListener in notification-service subscribes to topic domain-events. The LWP escalation events (lwp.escalation.level1 through level4) will never reach the notification service unless an application property override is set in deployment. For lone worker protection, this is a CQC compliance risk.

Where it breaks: SafetyEventPublisher.java:39 (topic: safety-events) vs ServiceBusConfig.java:29 (subscribed to: domain-events).

Chain 6: Visit Events Unreachable by Notification Service (Topic Mismatch)

VisitEventPublisher publishes to visits-events. AppointmentEventPublisher publishes to scheduling-events. ServiceBusEventListener subscribes to domain-events. Unless deployment environment variables override these defaults, all visit and schedule events are invisible to the notification service. This silences checkin.timeout, task.flagged, assistance.requested, and schedule.published notifications.

Where it breaks: Topic default misalignment across three services — see Critical Architectural Finding section above.

Chain 7: Events Listened For But Never Published

The ServiceBusEventListener routing switch includes cases for events that have no publisher anywhere in the codebase:

Event Missing Publisher Listener Location
checkin.timeout No publisher method in VisitEventPublisher ServiceBusEventListener.java:207
assistance.requested No publisher method in VisitEventPublisher ServiceBusEventListener.java:211
redflag.detected No publisher anywhere in any service ServiceBusEventListener.java:215
visit.reassigned No publisher anywhere in any service ServiceBusEventListener.java:220
task.flagged No publisher method in VisitEventPublisher (publishes visit.task.completed instead) ServiceBusEventListener.java:224
daily.summary No publisher anywhere in any service ServiceBusEventListener.java:249

Chain 8: Notification Outbound Events Have No Consumers

NotificationEventPublisher publishes notification.sent, notification.failed, and notification.acknowledged to topic notification-events. The analytics-service and audit-service that should consume these are not implemented as standalone services. The events will be published to a topic with no subscribers, age to TTL, and be discarded.


Fix Priority

Ordered by clinical and operational impact.

Priority 1 — Fix Topic Name Coherence (All Services)

Impact: Unblocks all visit and schedule notifications in one config change.

The notification-service ServiceBusConfig must subscribe to multiple topics, or all publishers must align on a shared topic name. The least-invasive fix is to add per-topic subscription processors in ServiceBusConfig.java for visits-events and scheduling-events in addition to domain-events. Alternatively, if the design intent is a single domain-events topic, all publishers must update their @Value defaults to domain-events.

This is a configuration and wiring change, not a logic change. No new business logic required.

Files to change:

Priority 2 — Fix visit.started / visit.checkedin Event Name

Impact: Allows check-in notifications to reach care managers.

Either rename the event type in VisitEventPublisher.java:127 from "visit.started" to "visit.checkedin", or update the listener case to "visit.started". The design document and listener both say visit.checkedin — the publisher is the outlier.

File to change: visits-service/src/main/java/com/lumiscare/visits/event/VisitEventPublisher.java:127

Priority 3 — Add Missing Publisher Methods to VisitEventPublisher

Impact: Enables checkin.timeout (clinical safety), task.flagged (care quality), assistance.requested (lone worker safety).

VisitEventPublisher needs three new publish methods. The listener routing and notification handlers for these events already exist. This is purely adding publisher-side methods and calling them from the appropriate visit execution service layer.

Events to add: checkin.timeout, task.flagged, assistance.requested File to change: visits-service/src/main/java/com/lumiscare/visits/event/VisitEventPublisher.java

Priority 4 — Add careplan.published Publisher to careplan-service

Impact: Allows scheduling to automatically create recurring visits when a care plan is approved. This is the central automation trigger for care delivery.

The CarePlanPublishedEventHandler in scheduling-service is complete and production-ready. Only the publisher side is missing. Add a publisher class to careplan-service that emits careplan.published on topic careplan-events when a care plan transitions to published status (the state transition already exists in CarePlanMapper.java).

Files to create/change:

Priority 5 — Add assessment.completed Publisher to assessment-service

Impact: Triggers automatic AI care plan generation after assessment completion.

Create an event publisher in assessment-service and publish assessment.completed when an assessment reaches a completed status. The careplan-service needs a corresponding listener (this does not yet exist either — both sides must be built).

Files to create:

Priority 6 — Add Finance Service Bus Consumer for visit.completed

Impact: Automates invoice line item generation from completed visits.

Add a ServiceBusProcessorClient to finance-service that subscribes to the visits-events topic with filter event_type = 'visit.completed'. The billing data payload already contains all required fields (billing_data section with visit_type, care_types, day_type, travel_time_minutes, mileage_miles).

Files to create:

Priority 7 — Complete the Finance Outbox Dispatcher

Impact: Enables timesheet.created and invoice.created notifications.

TimesheetBatchJobProcessor writes OutboxEvent records to the database but the comment in the code (TimesheetBatchJobProcessor.java:35) refers to an "external outbox-processor daemon" that does not exist. Either implement the outbox polling scheduler within the finance-service or replace the outbox pattern with a direct ServiceBusSenderClient call inside the existing transaction.

Files to change:

Priority 8 — Resolve hr.availability.updated vs availability.updated Event Name

Impact: Prevents silent message drops when carer availability changes.

HrAvailabilityUpdatedEventHandler expects message subject hr.availability.updated (at HrAvailabilityUpdatedEventHandler.java:94). HrEventPublisher publishes with event type availability.updated (called at AvailabilityPreferencesService.java:161). This is a subject field mismatch. The handler will silently complete all messages that do not match its expected subject, meaning availability changes will not trigger schedule recomputation.

Files to change: Align the event type string in AvailabilityPreferencesService.java:161 to hr.availability.updated, or update the handler constant at HrAvailabilityUpdatedEventHandler.java:94.


Summary Counts

Category Count
Fully wired event chains (publisher + consumer on matching topic) 3 (employee.created, employee.updated, leave.approved/certification.expiring via domain-events)
Partially wired (publisher exists, consumer absent or topic mismatch) 8
Events listener handles but no publisher produces 6
Events completely absent (no publisher, no consumer) 3 (assessment.completed, invoice.created, invoice.paid)
Publisher classes that exist 6 (HrEventPublisher, VisitEventPublisher, AppointmentEventPublisher, NotificationEventPublisher, SafetyEventPublisher, incidents EventPublisher)
Publisher classes missing 2 (assessment-service, careplan-service)
Services with no Service Bus integration at all 3 (assessment-service, careplan-service, finance-service consumer side)
Topic name mismatches between publisher default and notification-service subscription 3 (visits-events, scheduling-events, incidents-events, safety-events vs domain-events)

The HR to Notification chain (leave.approved, certification.expiring) is the only end-to-end path that works without deployment configuration overrides. Everything that involves visit execution events, schedule events, or safety escalations depends on either a topic name fix or missing publisher code.

Architecture — Frontend Route Map

LumisCare Frontend — Complete Route Map

Generated: 2026-04-04 Source of truth: frontend/web/src/routes/index.ts + src/components/navigation/sidebar/Sidebar.tsx Mobile source: mobile/app/src/app/ (Expo Router v4, file-based) Total registered web routes: 97 (including aliases and redirects) Portals covered: Back Office, Family Portal, Admin Panel, Mobile App


Back Office Routes

Route Component Lines Status RBAC Guard Notes
/ (index) DashboardPage 568 Functional All backoffice roles Full metrics + rota section
/clients ClientsPage 131 Functional Most backoffice roles Tabbed navigation, delegates to content components
/clients/:id ClientPage Functional Most backoffice roles Client detail page
/assessments AssessmentsPage Functional Clinical + admin roles Assessments overview
/clients/:clientId/assessment/live LiveAssessmentPage Functional None (no ProtectedRoute) Live assessment flow with client context
/clients/assessment/live LiveAssessmentPage Functional None Live assessment flow without client context
/clients/assessment/transcript AssessmentTranscriptPage Functional None Assessment transcript view
/clients/:clientId/body-map BodyMapPage Functional None Body observations with client context
/clients/body-map BodyMapPage Functional None Body observations without client context
/clients/:clientId/assessment/complete AssessmentCompletionPage Functional None Consent + attendees with client context
/clients/assessment/complete AssessmentCompletionPage Functional None Consent + attendees without client context
/clients/assessment/questions/:sectionId QuestionsPage Functional None Section questions view
/clients/assessment/question-management QuestionManagementPage Functional Clinical + admin roles Drag-and-drop reorder
/clients/:clientId/assessment/question-management QuestionManagementPage Functional Clinical + admin roles Drag-and-drop reorder with client context
/clients/assessment/risk-assessment-risks RAQuestionsPage Functional None Risk assessment questions
/clients/assessment/risk-assessment-risks/:sectionId RAQuestionsPage Functional None Risk assessment questions by section
/clients/assessment/section/:sectionId PersonalInformationPage Functional None Section detail view
/clients/assessment/medication/:medicationId/edit EditMedicationPage Functional Clinical + admin roles Edit medication (QA excluded)
/clients/:clientId/assessment/medications/add AddMedicationPage Functional Clinical + admin + carer Add medication with client context
/clients/assessment/medications/add AddMedicationPage Functional Clinical + admin + carer Add medication without client context
/clients/:clientId/assessment/medications/:medicationId MedicationDetailsPage Functional None Medication details (read-only for QA)
/clients/:clientId/assessment/medications/:medicationId/edit EditMedicationPage Functional Clinical + admin roles Edit medication with client context
/employees EmployeePage 753 Functional None (no ProtectedRoute) Full employee list
/employees/new CreateEmployeePage Functional Manager roles only Create employee (QA excluded)
/employees/:id EmployeeDetailsPage Functional None Employee detail page
/employees/find-by-skills FindCarersBySkillsPage Functional None Search carers by qualifications
/leaves LeavesOverviewPage 563 Functional None Leave management overview
/leaves/approval LeaveRequestApprovalPage Functional Manager + shift-leader roles Leave request approval (Feature #252)
/hr/training-matrix TrainingMatrixPage 636 Functional (1 TODO) HR + manager + admin roles Training compliance matrix
/hr/dbs DBSDashboardPage 393 Functional (1 TODO) HR + manager + admin roles DBS certificate status
/hr/bradford BradfordDashboardPage 372 Functional (1 TODO) HR + manager + admin roles Bradford Factor scoring
/hr/supervisions SupervisionSchedulePage 487 Functional (1 TODO) HR + manager + admin roles Supervision scheduling
/hr/care-certificate CareCertificateTrackerPage 450 Functional (1 TODO) HR + manager + admin roles Care Certificate tracker
/hr/cqc-pack CQCInspectionPackPage 554 Functional HR + manager + admin roles CQC inspection pack
/visits VisitPage Functional None Visit list and management
/visits/activity-log ActivityLogPage Functional None Visit activity log
/visits/gps-checkin GPSCheckInSimulationPage 548 Functional None GPS geofence test tool (Feature #275)
/visits/evv EVVPage 111 Functional None Electronic Visit Verification / QR check-in (Feature #277)
/visits/live-tracking LiveTrackingDashboard Functional None Real-time carer location (Feature #287)
/visits/completed-events CompletedEventsPage Functional None Completed visit review before invoicing
/visits/handoff ShiftHandoffPage Functional None SBAR shift handoff notes
/backoffice/scheduling SchedulingPage 799 Functional (1 TODO) Coordinator + manager + admin Full calendar/roster grid
/backoffice/incidents (index) IncidentsListPage 759 Functional (1 TODO) None Incident list
/backoffice/incidents/:id IncidentDetailPage 2487 Functional None Incident detail (investigation tab RBAC-gated inline)
/backoffice/incidents/safeguarding SafeguardingPage 59 Functional None RBAC wrapper — delegates to ClientsSafeguardContent
/care-plans CarePlansPage 599 Functional (1 TODO) None Care plans list
/care-plans/:id CarePlanReviewPage 864 Functional Manager + clinical + admin Care plan approval workflow
/care-plans/:id/edit CarePlanEditorPage 1768 Partial (53 TODOs) Manager + clinical + admin 10-section editor — incomplete fields
/care-plans/:id/task-linking CarePlanTaskLinkingPage Functional Manager + coordinator + clinical Task-to-visit-type linking
/care-plans/reviews-due CarePlansReviewDuePage 480 Functional Manager + clinical + QA NICE QS123 compliance reviews
/ai/care-plan-generator AICarePlanGeneratorPage 582 Functional Clinical + manager + admin AI-powered care plan generation
/finance FinancePage 82 Functional ModuleProtectedRoute: finance Tabbed finance hub
/finance/audit-log InvoicesAuditLogPage Functional ModuleProtectedRoute: finance Invoice audit trail
/finance/billing InsuranceBillingPage Functional ModuleProtectedRoute: finance Medicaid/Medicare claim management
/billing BillingPage 26 Redirect None Redirects to /finance/billing
/intake AddClientPage Functional Clinical + manager (QA excluded) New client intake
/smart-upload SmartUploadPage Functional Clinical + manager (QA excluded) AI PDF document extraction
/reports ReportsPage 283 Functional None Report generation UI
/cqc-readiness CQCReadinessPage 277 Functional Manager + clinical + QA + regional KLOE evidence + compliance scoring
/training/compliance TrainingCompliancePage 306 Functional Manager + HR + QA + regional Staff training gap analysis
/profile ProfilePage Functional None User profile (all authenticated users)
/notifications NotificationsInboxPage Functional None Notification feed (all authenticated users)
/settings/notifications NotificationPreferencesPage Functional None Channel preferences (Feature #322)

Back Office Alias / Redirect Routes

Route Destination Type Notes
/dashboard / Navigate redirect Legacy path compatibility
/compliance /admin/compliance Navigate redirect BUG: wrong destination for backoffice users
/incidents /backoffice/incidents Navigate redirect Legacy path compatibility
/schedule SchedulingPage (rendered directly) Alias Renders same component as /backoffice/scheduling
/training-compliance TrainingCompliancePage (rendered directly) Alias Renders same component as /training/compliance
/care-notes familyCareNotesPage (rendered directly) Alias Family portal alias
/care-plan familyCarePlanPage (rendered directly) Alias Family portal alias
/invoices familyInvoicesPage (rendered directly) Alias Family portal alias

Family Portal Routes

Route Component Lines Status RBAC Guard Notes
/family-portal-dashboard familyDashboardPage 522 Functional (1 TODO) family-member + admin roles Family dashboard
/family-portal-carenotes CareNotesPage 1272 Functional family-member + admin roles Full read view of visit notes
/family-portal-careplan CarePlanPage 797 Functional (2 TODOs) family-member + admin roles Care plan view
/family-portal-invoices InvoicesPage 2479 Functional (2 TODOs) family-member + admin roles Invoices and billing

Alias routes (workaround patches):

Alias Route Resolves To Notes
/care-notes familyCareNotesPage Shortcut alias
/care-plan familyCarePlanPage Shortcut alias
/invoices familyInvoicesPage Shortcut alias

Missing family portal features: No messaging/communication between family and carers. No visit scheduling from family side. No emergency contacts view.


Admin Panel Routes

Core Admin Routes

Route Component Lines Status RBAC Guard Notes
/admin/organizations OrganizationsPage 511 Functional (5 TODOs) system-admin + provider-admin Organization management
/admin/users UsersPage 991 Functional (7 TODOs) system-admin only User management
/admin/roles RolesPage 387 Functional (1 TODO) system-admin only Roles and permissions
/admin/settings SettingsPage 524 Functional system-admin only System settings
/admin/audit-logs AuditLogsPage 514 Functional (1 TODO) system-admin only Audit trail
/admin/compliance ComplianceDashboardPage 555 Functional system-admin only HIPAA compliance dashboard
/admin/dscr DSCRCompliancePage 386 Functional system-admin + provider-admin NHS DSCR compliance
/admin/data-import DataImportPage Functional system-admin only CSV/JSON data import
/admin/data-export DataExportPage Functional system-admin only CSV/JSON data export
/admin/multi-tenancy MultiTenancyTestPage Functional system-admin only Organization isolation test
/admin/module-subscriptions ModuleSubscriptionsPage Functional system-admin only Per-org module access (Feature #360)
/admin/questions QuestionManagementPage Functional system-admin + provider-admin Assessment question management (Feature #233)

Admin Test / Diagnostic Pages

These 18 routes are permanent in the router but function as feature verification tools. They should be gated by a dev/debug feature flag in production builds.

Route Component Feature # RBAC Guard Purpose
/admin/encryption-compliance EncryptionCompliancePage #362 system-admin Encryption at rest verification
/admin/tls-security TLSSecurityTestPage #363 system-admin TLS 1.3/1.2 enforcement
/admin/data-residency DataResidencyPage #365 system-admin US data sovereignty
/admin/openapi-validation OpenAPIValidationPage #366 system-admin API spec conformance
/admin/token-enrichment TokenEnrichmentTestPage #16 system-admin JWT token enrichment
/admin/api-auth-test ApiAuthTestPage #17 system-admin Bearer token validation
/admin/api-versioning APIVersioningTestPage #367 system-admin /api/v1/ prefix verification
/admin/api-sort-test APISortTestPage #369 system-admin Sort parameter verification
/admin/request-validation RequestValidationTestPage #371 system-admin Input validation
/admin/cors-test CORSTestPage #373 system-admin CORS header verification
/admin/fk-constraints ForeignKeyConstraintsTestPage #374 system-admin Referential integrity
/admin/check-constraints CheckConstraintsTestPage #376 system-admin Data validation constraints
/admin/push-notification-test PushNotificationTestPage #317 system-admin + provider-admin Azure Notification Hub push
/admin/sms-notification-test SmsNotificationTestPage #319 system-admin + provider-admin Azure Communication Services SMS
/admin/quiet-hours-test QuietHoursTestPage #321 system-admin + provider-admin Critical notification bypass
/admin/channel-routing-test ChannelRoutingTestPage #323 system-admin + provider-admin Channel preference routing
/admin/device-registration-test DeviceRegistrationTestPage #325 system-admin + provider-admin Mobile device token storage
/admin/notification-template-test NotificationTemplateTestPage #324 system-admin + provider-admin Template variable substitution
/admin/delivery-tracking-test DeliveryTrackingTestPage #327 system-admin + provider-admin Notification delivery logging
/admin/notification-retry-test NotificationRetryTestPage #328 system-admin + provider-admin Failed notification retry
/admin/in-app-read-tracking-test InAppReadTrackingTestPage #329 system-admin + provider-admin Read status tracking
/admin/notification-analytics NotificationAnalyticsPage #329 system-admin + provider-admin Delivery statistics dashboard

Admin Sidebar Navigation (from Sidebar.tsx)

The admin sidebar exposes 7 items — only a subset of all admin routes. Test/diagnostic pages are not listed in the sidebar.

Sidebar Label Route Allowed Roles
Organizations /admin/organizations system-admin + provider-admin
Users /admin/users system-admin + provider-admin
Roles & Permissions /admin/roles system-admin only
Settings /admin/settings system-admin + provider-admin
Audit Logs /admin/audit-logs system-admin only
HIPAA Compliance /admin/compliance system-admin only
NHS DSCR /admin/dscr system-admin + provider-admin

Mobile Screens (Expo Router v4)

File-based routing at mobile/app/src/app/. Routes correspond to the filesystem path under (app)/.

Screen / File Lines Status Notes
(app)/index.tsx — Home/Schedule 1624 Functional Large comprehensive carer dashboard
(app)/schedule.tsx 671 Functional Carer schedule view
(app)/visit/[visitId]/index.tsx 490 Functional Visit detail hub
(app)/visit/[visitId]/care-note.tsx 46 Functional Thin wrapper, delegates to CareNoteForm
(app)/visit/[visitId]/emar.tsx 1182 Functional (2 TODOs) Electronic MAR administration
(app)/visit/[visitId]/vitals.tsx 1087 Needs review (19 TODOs) Critical: clinically sensitive vitals screen — highest TODO density in codebase
(app)/visit/[visitId]/medications.tsx 122 Functional Medication list for visit
(app)/visit/[visitId]/task-validation.tsx 295 Functional (1 TODO) Task validation flow
(app)/visit/[visitId]/signature.tsx 308 Functional (2 TODOs) Signature capture
(app)/visit/[visitId]/check-out.tsx 5 Functional Thin delegator to CheckOutView
(app)/visit/[visitId]/client-details.tsx 264 Functional Client info within visit
(app)/visit/[visitId]/structured-note.tsx Present Structured clinical note entry
(app)/visit/[visitId]/observation.tsx Present Clinical observations
(app)/visit/[visitId]/pictures.tsx Present Camera/media capture
(app)/visit/[visitId]/online-assistance.tsx Present Remote assistance feature
(app)/visit/[visitId]/manual-checkout.tsx Present Manual override checkout
(app)/visit/[visitId]/upload-progress.tsx Present Upload status indicator
(app)/assessment/index.tsx 684 Functional (1 TODO) Mobile assessment flow
(app)/profile/index.tsx 490 Functional User profile
(app)/profile/availability.tsx Present Carer availability management
(app)/video-call/[callId]/index.tsx 31 Present LiveKit WebRTC video call
(app)/voice-commands.tsx 390 Functional Voice input feature
(app)/notifications/index.tsx Present Notification feed
(app)/notifications/settings.tsx Present Notification preferences
(app)/settings.tsx Present App settings
(app)/dev-tools.tsx Present Developer tools screen
auth.tsx Present OAuth callback handler

Navigation Gaps

Menu Item Sidebar Path Route Exists? Content Status Fix Needed
Dashboard / Yes Functional (568 lines) None
Notifications /notifications Yes Functional None
Clients /clients Yes Functional None
Employees > DBS Status /hr/dbs Yes Functional (1 TODO) None
Employees > Training Matrix /hr/training-matrix Yes Functional (1 TODO) None
Employees > Bradford Factor /hr/bradford Yes Functional (1 TODO) None
Employees > Supervisions /hr/supervisions Yes Functional (1 TODO) None
Employees > Care Certificate /hr/care-certificate Yes Functional (1 TODO) None
Employees > CQC Pack /hr/cqc-pack Yes Functional None
Schedule (parent) /visits Yes Functional Structural: parent links to /visits but sub-items link to /backoffice/scheduling, /visits/completed-events, /visits/handoff — mixed path hierarchy
Schedule > Rostering /backoffice/scheduling Yes Functional (1 TODO) None
Schedule > Completed Events /visits/completed-events Yes Functional None
Schedule > Shift Handoff /visits/handoff Yes Functional None
Care Plans /care-plans Yes Functional (1 TODO) None
AI Care Plan /ai/care-plan-generator Yes Functional None
Assessments /assessments Yes Functional None
Finance /finance Yes Functional (ModuleProtectedRoute) None
Incidents /backoffice/incidents/safeguarding Yes Functional (thin wrapper) Architectural: sidebar links to /safeguarding but incidents list is at /backoffice/incidents — users cannot reach incidents list from sidebar
Reports /reports Yes Functional None
Compliance (parent) /compliance Redirect only Redirects to /admin/compliance BUG P1: backoffice sidebar Compliance parent path redirects to HIPAA admin panel, not to backoffice CQC/compliance hub
Compliance > CQC Readiness /cqc-readiness Yes Functional None
Compliance > Training Compliance /training/compliance Yes Functional None

Mock Data Pages

Based on audit evidence, the following pages carry TODO markers explicitly referencing "connect to real API" or similar — indicating they may be rendering mock/sample data in some sections:

Page File Location TODO Count Nature of Mock
CarePlanEditorPage features/backOffice/carePlans 53 Many section fields not wired to real API — // TODO: connect to real API patterns throughout
vitals.tsx (mobile) mobile/app/src/app/(app)/visit/[visitId]/vitals.tsx 19 Clinically sensitive screen with incomplete API wiring
UsersPage features/admin/users 7 Minor TODOs — some user management operations may fall back
OrganizationsPage features/admin/organizations 5 Minor TODOs
IncidentsListPage features/backOffice/incidents/list 1 Single TODO
SchedulingPage features/backOffice/scheduling 1 Single TODO in 799-line page
CarePlansPage features/backOffice/carePlans 1 Single TODO
DBSDashboardPage features/backOffice/hr/pages/DBSDashboardPage 1 Single TODO
TrainingMatrixPage features/backOffice/hr/pages/TrainingMatrixPage 1 Single TODO
BradfordDashboardPage features/backOffice/hr/pages/BradfordDashboardPage 1 Single TODO
SupervisionSchedulePage features/backOffice/hr/pages/SupervisionSchedulePage 1 Single TODO
CareCertificateTrackerPage features/backOffice/hr/pages/CareCertificateTrackerPage 1 Single TODO
familyPortalDashboardPage pages/familyPortal/dashboard 1 Minor TODO
CarePlanPage (family) features/familyPortal/carePlan 2 Minor TODOs
InvoicesPage (family) features/familyPortal/invoices 2 Minor TODOs
AuditLogsPage features/admin/auditLogs 1 Minor TODO
RolesPage features/admin/roles 1 Minor TODO

Note on methodology: TODO counts use literal string grep of "TODO". They include code comments such as // TODO: connect to real API and represent technical debt markers, not blank or placeholder UI. No page renders "Coming soon" or empty content.


Stub / Placeholder Pages

No pages are pure stubs rendering blank or "Coming soon" content. All registered pages render substantive UI. The following are below 50 lines but delegate intentionally:

Page File Lines Nature
BillingPage features/backOffice/billing 26 Intentional redirect wrapper to /finance/billing
SafeguardingPage features/backOffice/incidents/safeguarding 59 Intentional RBAC wrapper delegating to ClientsSafeguardContent
check-out.tsx (mobile) (app)/visit/[visitId]/check-out.tsx 5 Intentional thin delegator to CheckOutView component
care-note.tsx (mobile) (app)/visit/[visitId]/care-note.tsx 46 Intentional thin wrapper for CareNoteForm
video-call/[callId]/index.tsx (mobile) (app)/video-call/[callId]/index.tsx 31 LiveKit integration, thin entry point

Unrouted Components

The following components exist in the source tree but have no registered route in src/routes/index.ts:

Component File Path Concern Level Notes
SOSHistoryPage features/backOffice/dashboard/SOSHistoryPage.tsx (96 lines) P1 Referenced in comment as /backoffice/safety/sos-history but route never registered — feature dead end
KeywordPage features/backOffice/keywords/pages/KeywordPage.tsx P1 Keyword management feature exists with no route — unreachable
RedFlagDetectionDemoPage features/backOffice/clients/pages/RedFlagDetectionDemoPage.tsx P2 Demo/diagnostic page exists but is unrouted

Summary Statistics

Metric Count
Total registered web routes (including aliases/redirects) ~97
Back Office routes (primary) 56
Back Office alias/redirect routes 8
Family Portal routes (primary) 4
Family Portal alias routes 3
Admin core routes 12
Admin test/diagnostic routes 22
Auth routes (/login, /logout, /access-denied) 3
Catch-all 404 route 1
Mobile screens 27
Pages with TODO markers (web) 17
Unrouted components 3
Navigation gaps (bugs) 2 confirmed

Priority Issues

Priority Issue Impact
P0 CarePlanEditorPage (1768 lines, 53 TODOs) — core clinical page, incomplete fields Clinical product gap
P0 Mobile vitals.tsx (1087 lines, 19 TODOs) — clinically sensitive screen Clinical product gap
P1 Sidebar /compliance redirects to HIPAA admin page instead of backoffice CQC/compliance hub Wrong UX for all backoffice users
P1 Sidebar Incidents links to /backoffice/incidents/safeguarding — users cannot reach the incidents list from the sidebar Navigation dead end
P1 SOSHistoryPage component exists (96 lines) but has no registered route Feature dead end
P1 KeywordPage component exists but is not routed Unreachable feature
P2 Family portal URLs (/family-portal-dashboard etc.) violate URL hierarchy — alias patches mask the structural problem UX and URL semantics debt
P2 RedFlagDetectionDemoPage exists but is unrouted Dead code
P2 switch.tsx file and switch/ folder coexist in src/components/ui/ — import resolution ambiguity Build risk
P2 calender folder typo in src/components/ui/ DX friction, propagates through all calendar imports
P3 22 admin test/diagnostic pages as permanent routes — should be gated by dev/debug feature flag Security surface area in production, route tree clutter
P3 SafeguardingPage (59 lines) delegates to ClientsSafeguardContent — component lives in Clients feature, not Incidents Architectural boundary violation

Fix Backlog — P0/P1/P2 Issues

LumisCare — Fix Backlog

Consolidated from 5 expert reports — 2026-03-25 Total issues: 32

Format: [PORTAL] [PAGE] [ELEMENT] [PROBLEM] [FIX NEEDED]


P0 — Demo Blocking

Issues that will be visible within 60 seconds of any stakeholder opening the app. Must be fixed before any demo or investor showing.

# Portal Page Element Problem Fix Needed
1 Admin Panel Organizations (/admin/organizations) "Add Organization" button Button renders; no form or modal wired Wire button to create organization form/modal with: Organization Name, Status, Contact details → POST /api/v1/organizations
2 Admin Panel Organizations (/admin/organizations) Per-card "More options" (…) button Button renders; no dropdown or menu attached Add dropdown menu with actions (Edit, View, Deactivate) per org card
3 Family Portal Care Plan (/family-portal-careplan) Print button (header) onClick handler missing — button does nothing Wire to window.print() or PDF export
4 Family Portal Care Plan (/family-portal-careplan) More options (3-dot) button (header) onClick handler missing — button does nothing Add dropdown with relevant actions (Download, Share) or remove button
5 Family Portal Care Notes (/family-portal-carenotes) "Week" button (rounded-full with left chevron) No onClick handler — looks interactive but does nothing Wire to goToPreviousWeek() (same as the arrow button) or replace with correct UI
6 Family Portal Care Plan (/family-portal-careplan) Draw Signature area inside Sign & Consent Modal Draw tab shows placeholder <div>, no canvas or drawing library hooked up Integrate a canvas drawing library (e.g. react-signature-canvas) — draw mode must capture a real signature
7 Back Office Body Map (/clients/:id/body-map) "This Week" time filter button No onClick handler wired Wire to filter observations by current week, or remove button until implemented
8 Back Office Body Map (/clients/:id/body-map) "Filters" button No onClick handler wired Open filter drawer/modal for observation category/severity, or remove button until implemented
9 Back Office Body Map (/clients/:id/body-map) Zoom controls (minus / zoom icon / plus) UI renders; no zoom logic implemented Implement zoom state and apply CSS transform on body diagram container
10 Back Office Body Map (/clients/:id/body-map) Per observation card "Edit" (pencil icon) onEdit(id) handler marked TODO — not implemented Implement edit observation flow (open edit dialog pre-populated with observation data)
11 Family Portal Invoices (/family-portal-invoices) Per-row "Pay" button Calls console.log or shows "Online payment will be available in the next release." toast; no payment flow For demo: show a modal stub. For production: integrate payment provider. Disable with clear "Coming Soon" state if not ready.
12 Family Portal Dashboard (/family-portal-dashboard) Per-invoice "Pay" button Same as above — triggers info toast only Same fix as above
13 Back Office Visits Header (/visits) Print button console.log placeholder — "Print functionality coming soon" Wire to print or remove button
14 Back Office Visits Header (/visits) Export button console.log placeholder — "Export functionality coming soon" Wire to CSV/PDF export or remove button
15 Back Office Activity Log (/visits/activity-log) Print button No onClick handler wired Wire to print or remove button
16 Back Office Activity Log (/visits/activity-log) Export button No onClick handler wired Wire to export (CSV at minimum) or remove button
17 Family Portal Dashboard Video thumbnails in visit cards Play icon overlay shown on thumbnails but no onClick handler — non-interactive Either remove play overlay or implement video playback modal

P1 — Pilot Blocking

Issues that block a paying pilot customer from using core workflows. Must be resolved before any live pilot.

# Portal Page Element Problem Fix Needed
18 Admin Panel Audit Logs (/admin/audit-logs) Export functionality No export button present anywhere on the page Add export button → generate CSV/PDF of audit log entries with current filters applied
19 Admin Panel Audit Logs (/admin/audit-logs) Date range filter No date range picker present — only type filter and text search Add date range picker (start/end) to filter audit log by date
20 Admin Panel Compliance Dashboard (/admin/compliance) All action items Page is fully read-only — data rights requests, anomaly alerts, consent override all require action Add action controls: respond to data rights requests, acknowledge anomaly alerts, manage consent
21 Family Portal Profile (/profile) Edit contact information Profile page is fully read-only — no edit buttons, no form, no save Add edit form for at minimum: phone number, preferred contact method. Name/email via Azure AD.
22 Admin Panel Organizations (/admin/organizations) Organization data All data is hardcoded array in component state — not API-connected Connect to /api/v1/organizations GET (list) and POST (create) endpoints
23 Admin Panel Roles & Permissions (/admin/roles) Role management Roles page is view-only — no "Add Role" or "Edit Role" UI Add ability to create custom roles and edit permissions, or document that this is intentionally RBAC-fixed
24 Back Office Activity Log (/visits/activity-log) "This Month" date filter button Button renders with dropdown chevron but no onClick handler wired Wire to date range picker — currently filters are impossible to apply by date on this page
25 Back Office Completed Events Tab (/visits — Completed Events) Date Range button Visual button with no date picker wired Wire to date range picker for filtering completed events by date range
26 Back Office Finance Billing Page Entire page is placeholder: <div>Welcome to BillingPage</div> Implement billing page or redirect to Insurance Billing page until ready
27 Back Office Scheduling Recompute Schedule Demo-only — hardcoded with carer-1 / "Sarah Mitchell" data Connect to real scheduling data and real recomputation logic

P2 — Production Blocking

Issues that are acceptable for demo/pilot but must be resolved before production launch. Real persistence and real backend required.

# Portal Page Element Problem Fix Needed
28 Admin Panel Settings (all tabs) Save Changes Persists to localStorage only Connect to backend settings API with proper per-org persistence
29 Admin Panel Assessment Questions Save Question Persists to localStorage('admin_assessment_questions') Connect to backend questions API
30 Admin Panel Profile Save Photo Stores base64 in localStorage Upload to blob storage; store reference in user record
31 Back Office Body Map Add Observation Saves to localStorage('lumiscare-body-map-observations-{clientId}') Persist observations to assessment service / clinical records
32 Back Office Care Plan Review Schedule Review Saves to localStorage('lumiscare_scheduled_care_plan_reviews') and localStorage('lumiscare_schedule_blocks') Persist to scheduling service; create real calendar entries

Summary by Portal

Portal P0 P1 P2 Total
Back Office (Clinical/Scheduling/Finance/HR) 8 4 3 15
Admin Panel 2 6 3 11
Family Portal 7 1 0 8
Total 17 11 6 32

Quick Wins (P0 items fixable in < 1 hour each)

These P0 bugs are simple missing handler wires — not missing features:

  1. [P0-3] Family Portal Care Plan Print button — onClick={() => window.print()}
  2. [P0-4] Family Portal Care Plan More options button — add dropdown or remove icon
  3. [P0-5] Family Portal Care Notes "Week" button — onClick={goToPreviousWeek}
  4. [P0-13] Backoffice Visits Print button — onClick={() => window.print()}
  5. [P0-15] Activity Log Print button — onClick={() => window.print()}
  6. [P0-7] Body Map "This Week" button — remove or stub with toast "Filters coming soon"
  7. [P0-8] Body Map "Filters" button — remove or stub with toast "Filters coming soon"
  8. [P0-17] Dashboard video thumbnails — remove play icon overlay until implemented

Generated 2026-03-25. Source: consolidated from 5 expert subagent reports.

Mock-to-Real Migration Plan

Mock API to Real Backend — Migration Plan

Generated: 2026-03-26 Author: FlowForge (ALAI DevOps) Project: LumisCare Enterprise Healthcare Platform Scope: 222 mock endpoints → 11 Spring Boot microservices via Web BFF


1. Current State Summary

Component Status
Mock API (server.js) Running — 5,280 lines, 222 endpoints, frontend pointed here
Spring Boot services 11 deployed on Azure Container Apps — all Running
PostgreSQL (10 databases) Flyway migrated, schemas applied, zero seed data
Web BFF Deployed — assessment, careplan, incidents, hr, finance clients wired; visits + scheduling + notification + identity NOT fully wired
Frontend Points to mock API

2. Coverage Analysis — 222 Mock Endpoints vs Real Services

Method

Mock endpoints extracted from mock-api/server.js via route registration. Real coverage determined from OpenAPI specs in openapi-specs/ and Web BFF controller inventory in backend/bff/web-bff/src/main/java/.../controller/.

Total endpoint count breakdown:

Coverage By Service Domain

VISITS — 14 mock endpoints

Mock routes: GET/POST /api/v1/visits, GET/PATCH/DELETE /api/v1/visits/:id, check-in, check-out, eMAR, tasks, clinical-observations, SOS, travel-record, publish, running-late, pre-visit-brief

Real service (visits-service): OpenAPI defines /visits, /visits/{visitId}, check-in, check-out, tasks, observations, status, notes, eMAR.

Web BFF: No VisitsController found in BFF controller list. VISITS_SERVICE_BASE_URL is configured in application.yml (port 8085) but no BFF controller proxies it yet.

Coverage status: Service READY, BFF wiring MISSING. Estimated real coverage: 9 of 14 endpoints have a backend implementation. 5 (clinical-observations format, SOS, pre-visit-brief, travel-record, eMAR administer/refuse detail) need verification.

SCHEDULING / ROSTERING — 8 mock endpoints

Mock routes: GET /api/v1/schedule-blocks, GET/POST/PATCH/DELETE /api/v1/schedule-blocks/:id, GET /api/v1/completed-events, bulk-confirm, publish

Real service (scheduling-service): OpenAPI defines schedule-events, appointments, rostered-hours, recurring-schedules, availability. Maps partially — schedule-blocks naming differs from schedule-events.

Web BFF: CalendarController.java exists. SCHEDULING_SERVICE_BASE_URL configured (port 8086).

Coverage status: PARTIAL — naming mismatch between mock and real service paths needs alignment. Estimated real coverage: 5 of 8.

ASSESSMENT — 12 mock endpoints

Mock routes: GET/POST/PUT/PATCH /api/v1/assessments, body-map, scores, complete, GET /api/v1/intake

Real service (assessment-service): Full OpenAPI — assessment CRUD, sections, subsections, questions, risk sections, observations, photos, medications, status, submit, intake.

Web BFF: BffAssessmentController.java + AssessmentWebDashBoardController.java exist. AssessmentClientConfig wired.

Coverage status: COVERED for core paths. Scores/clinical-tools endpoints may map to risk-section in real service. Estimated real coverage: 10 of 12.

CARE PLANS — 14 mock endpoints

Mock routes: GET/POST/PUT/DELETE /api/v1/care-plans, versions, tasks, risk-alerts, reviews, approve, publish, submit-for-approval, consent, review-due

Real service (careplan-service): OpenAPI defines care-plans CRUD, publish, regenerate, generation-status, versions, master-task-types/visit-types.

Web BFF: CarePlanController.java exists. CarePlanClientConfig wired.

Coverage status: Core CRUD + publish + versions covered. Task management, risk-alerts, reviews, consent are mock-only. Estimated real coverage: 7 of 14.

HR — 18 mock endpoints

Mock routes: GET /api/v1/hr/supervisions, absences, dbs, bradford, care-certificate, training matrix, supervision-schedule, cqc-inspection-pack; legacy /employees/*

Real service (hr-service): Extensive OpenAPI — employees full profile, leaves, supervisions, training, appraisals, documents, equality diversity, onboarding.

Web BFF: EmployeeController.java + ResumeUploadController.java exist. HrClientConfig wired.

Coverage status: Employee core COVERED. HR compliance sub-paths (DBS checks, Bradford factor, care certificate, CQC pack) are mock-only abstractions — hr-service has training and supervision but not as named sub-routes. Estimated real coverage: 10 of 18.

FINANCE — 20 mock endpoints

Mock routes: invoices, timesheets, rate-cards, funders, invoice-groups, payment-groups, payroll preview/export/approve, aged-debtors, NMW compliance, bank-holidays, month-end status, dashboard

Real service (finance-service): OpenAPI defines invoices (full lifecycle), timesheets, invoice-groups, payment-groups, mandates, dashboard. Rate-cards and funders are mock-only concepts.

Web BFF: FinanceBffController.java exists. FinanceClientConfig wired.

Coverage status: Invoice + timesheet core COVERED. Rate-cards, funders, payroll export, NMW compliance, aged-debtors are MOCK-ONLY. Estimated real coverage: 12 of 20.

INCIDENTS — 8 mock endpoints

Mock routes: GET/POST/PATCH/DELETE /api/v1/incidents, GET /api/v1/incidents/:id

Real service (incidents-service): OpenAPI defines accidents, complaints, hazards, safeguarding, summary, actions log.

Web BFF: IncidentsController.java exists. IncidentsClientConfig wired.

Coverage status: COVERED — mock uses generic /incidents but real service has typed categories (accidents, complaints, hazards, safeguarding). Path mapping required in BFF. Estimated real coverage: 6 of 8.

NOTIFICATIONS — 10 mock endpoints

Mock routes: notifications inbox, unread-count, preferences, devices register/unregister, mark-all-read, push

Real service (notification-service): OpenAPI defines inbox, devices, preferences, templates, unread-count, send, mark-read.

Web BFF: No NotificationController found. notification-service NOT listed in application.yml service URLs.

Coverage status: Service READY, BFF wiring MISSING. Estimated real coverage: 7 of 10 (paths align), but BFF layer absent.

IDENTITY / USERS / ORGS / SERVICE USERS — 14 mock endpoints

Mock routes: GET /api/v1/users, GET /api/v1/service-users, organizations, settings, carers, skills

Real service (identity-service): OpenAPI defines users, organizations, service-users, roles, settings.

Web BFF: ServiceUsersController.java exists. IdentityClientConfig found in config.

Coverage status: PARTIAL — users and service-users COVERED. Carers-by-skills, skills list, rostering-settings are mock-only. Estimated real coverage: 9 of 14.

FAMILY PORTAL — 16 mock endpoints

Mock routes: family care-plan view, complaints, messages/threads, notifications, payments initiate/confirm

Real service: No dedicated family-portal-service. Family portal routes would be served by web-bff aggregating careplan-service + notification-service + identity-service.

Web BFF: No family portal controller found.

Coverage status: MOCK-ONLY. No real backend for family portal BFF layer. Estimated real coverage: 0 of 16.

MISC (dashboard, CQC, EVV, import, audit, observations, insurance, handoff) — 24 mock endpoints

Includes: GET /api/v1/dashboard/stats, /api/v1/cqc-readiness, /api/v1/evv/*, /api/v1/import/*, /api/v1/audit-logs, /api/v1/insurance/*, /api/v1/handoff/*, /api/v1/observations

Real services: EVV (electronic visit verification) maps to visits-service tracking endpoints. Dashboard stats aggregate from multiple services. Import, insurance, handoff are mock-only constructs.

Coverage status: MOSTLY MOCK-ONLY. Estimated real coverage: 4 of 24 (dashboard + some audit, EVV via visits tracking).


Coverage Summary Table

Domain Mock Endpoints Real Coverage Status
Visits 14 ~9 BFF wiring missing
Scheduling 8 ~5 Path naming mismatch
Assessment 12 ~10 BFF wired, good coverage
Care Plans 14 ~7 BFF wired, tasks/risks mock-only
HR 18 ~10 BFF wired, compliance routes mock-only
Finance 20 ~12 BFF wired, rate-cards/payroll mock-only
Incidents 8 ~6 BFF wired, path mapping needed
Notifications 10 ~7 BFF wiring MISSING
Identity/Users/Orgs 14 ~9 BFF partial
Family Portal 16 0 No backend at all
Misc / EVV / Dashboard 24 ~4 Mostly mock-only
TOTAL 158 (excl wildcards) ~79 ~50% real coverage

Bottom line: approximately 79 of 158 meaningful mock endpoints have a corresponding real service implementation. The remaining ~79 are either BFF-wiring gaps, path-mapping gaps, or features that do not yet exist in any real service.


3. Seed Data Blocking Issue

Problem

Azure PostgreSQL Flexible Server blocks all public inbound connections by default. The 10 service databases have schemas (Flyway applied) but no seed data. Attempts to run seed scripts from a local machine are blocked by the firewall.

Options to Load Seed Data

Option A — Azure Cloud Shell (Recommended, zero setup)

# Open Azure Portal → Cloud Shell (Bash)
# Download seed scripts from repo or paste inline
psql "host=<your-pg-server>.postgres.database.azure.com \
      user=<admin> \
      dbname=identity_db \
      sslmode=require" \
  -f seed-identity.sql

No firewall changes needed. Cloud Shell is inside Azure's network boundary.

Option B — Temporary Firewall Rule (simple but requires cleanup)

# Add current IP to Azure PostgreSQL firewall
MY_IP=$(curl -s https://api.ipify.org)
az postgres flexible-server firewall-rule create \
  --resource-group rg-vcc-dev-001 \
  --name <pg-server-name> \
  --rule-name temp-local-dev \
  --start-ip-address $MY_IP \
  --end-ip-address $MY_IP

# Run seeds, then REMOVE the rule
az postgres flexible-server firewall-rule delete \
  --resource-group rg-vcc-dev-001 \
  --name <pg-server-name> \
  --rule-name temp-local-dev --yes

Option C — Run psql from a Container App (uses private endpoint, no firewall change)

# Exec into any running Container App that has psql available
az containerapp exec \
  --name ca-vcc-dev-identity-api-001 \
  --resource-group rg-vcc-dev-001 \
  --command "/bin/bash"
# Inside the container:
psql $DATABASE_URL -f /tmp/seed.sql

Option D — Seed via Service REST API (safest, uses existing auth/validation)

Write seed data through the service's own API endpoints (POST requests). Slower but validates business logic along with data. Best for production-like seed data.


4. Migration Strategy

Recommended: Option C — Proxy Pattern in Web BFF

The Web BFF already exists and has partial service wiring. The safest migration path is:

  1. Web BFF handles ALL frontend requests
  2. For endpoints with real service backing: BFF proxies to the real microservice
  3. For endpoints without real backing: BFF falls back to mock API (temporarily)
  4. Mock API is never called directly by frontend — only via BFF fallback

This is superior to Option A (hard cutover) and Option B (per-service switch) because:

Migration Architecture

Frontend (React)
     |
     v
Web BFF (Azure Container Apps, port 8080)
     |-- /api/v1/assessments        --> assessment-service (LIVE)
     |-- /api/v1/care-plans         --> careplan-service (LIVE)
     |-- /api/v1/incidents/*        --> incidents-service (LIVE)
     |-- /api/v1/hr/*               --> hr-service (LIVE)
     |-- /api/v1/finance/*          --> finance-service (LIVE)
     |-- /api/v1/visits             --> visits-service (WIRE NOW)
     |-- /api/v1/notifications/*    --> notification-service (WIRE NOW)
     |-- /api/v1/schedule-blocks/*  --> scheduling-service (WIRE NOW)
     |-- /api/v1/family/*           --> [MOCK FALLBACK] no service yet
     |-- /api/v1/evv/*              --> [MOCK FALLBACK] no service yet
     |-- /api/v1/dashboard/stats    --> [BFF aggregation from multiple services]
     |-- /api/v1/cqc-readiness      --> [MOCK FALLBACK]
     |-- everything else            --> [MOCK FALLBACK]
     |
     v (fallback only)
Mock API (Node.js, to be decommissioned incrementally)

5. Step-by-Step Migration Plan

Phase 0 — Preparation (1-2 days)

0.1 Load seed data

0.2 Verify all 11 Container Apps are healthy

az containerapp list \
  --resource-group rg-vcc-dev-001 \
  --query "[].{name:name, status:properties.runningStatus}" \
  --output table

0.3 Set frontend env var (do not deploy yet)

# In frontend/web/.env.production
VITE_API_BASE_URL=https://<web-bff-fqdn>.azurecontainerapps.io

Phase 1 — Wire Missing BFF Routes (3-5 days)

1.1 Wire visits-service to BFF

1.2 Wire notification-service to BFF

1.3 Wire scheduling-service to BFF

1.4 Verify identity-service routing


Phase 2 — Switch Frontend to BFF (1 day)

2.1 Update frontend environment

# In frontend/web/ Azure Static Web App config:
VITE_API_BASE_URL=https://<web-bff-fqdn>.azurecontainerapps.io

2.2 Add BFF fallback proxy for unimplemented routes In Web BFF, add a fallback route that proxies unknown /api/v1/* requests to the mock API:

# application-dev.yml
mock-api:
  fallback-url: ${MOCK_API_URL:http://mock-api:3000}
  fallback-enabled: ${MOCK_API_FALLBACK_ENABLED:true}

This ensures zero frontend breakage during migration. As each BFF controller is added, the fallback for that route is removed.

2.3 Keep mock API running (do not shut down) Mock API remains as a fallback target for the BFF. It can be stopped when fallback-enabled is set to false.


Phase 3 — Per-Domain Cutover (1-2 weeks)

Work through each domain in priority order. For each:

  1. Confirm seed data in that service's DB
  2. Smoke-test the real service endpoint directly (health + basic CRUD)
  3. Enable BFF routing to real service
  4. Disable fallback for that domain's routes
  5. Run Playwright smoke tests

Priority order:

  1. Identity (login, users, orgs) — everything else depends on auth
  2. Assessment (core clinical workflow)
  3. Care Plans (built on assessment)
  4. Visits (mobile carer workflow)
  5. Incidents (safety-critical, short paths)
  6. HR (staff management)
  7. Scheduling (complex, validate separately)
  8. Finance (invoicing, last due to rate-card gaps)
  9. Notifications (async, lower urgency)
  10. Family Portal (no service — keep mock until service is built)

Phase 4 — Decommission Mock (after Phase 3 complete)

4.1 Disable BFF fallback

MOCK_API_FALLBACK_ENABLED=false

4.2 Run full Playwright test suite Confirm zero regressions. Mock fallback should not be needed.

4.3 Stop mock API Container App (or LaunchAgent if local)

az containerapp update \
  --name ca-vcc-dev-mock-api \
  --resource-group rg-vcc-dev-001 \
  --min-replicas 0 \
  --max-replicas 0

4.4 Archive mock-api/server.js (do not delete — reference for missing features)


6. Rollback Plan

Rollback is available at every phase with zero data loss risk.

Instant rollback (any phase)

# Re-point frontend to mock API
# In Azure Static Web App config:
VITE_API_BASE_URL=https://mock-api-url

# OR in BFF — re-enable fallback
MOCK_API_FALLBACK_ENABLED=true

Because the mock API is never decommissioned during active migration (only at Phase 4), rollback is a single env var change at the frontend or BFF level.

Per-service rollback

If a specific service is misbehaving, disable only its BFF route and re-enable fallback for that domain only. All other services continue serving real data.

Database rollback

Schema rollback is possible via Flyway undo migrations. Data rollback requires a database restore from Azure Backup (automated daily snapshots on PostgreSQL Flexible Server).


7. Endpoints That Are Mock-Only (No Real Service Equivalent)

These require new service implementation or design decisions before migration is possible:

Mock Endpoint Category Effort
GET /api/v1/finance/rate-cards Finance Medium — add to finance-service
GET /api/v1/finance/funders Finance Medium — add to finance-service
GET /api/v1/finance/payroll/* Finance High — payroll is a separate domain
GET /api/v1/finance/aged-debtors Finance Low — calculated report from invoices
GET /api/v1/finance/nmw-compliance Finance Medium
GET /api/v1/hr/bradford HR Low — calculated from absences
GET /api/v1/hr/care-certificate HR Medium
GET /api/v1/hr/cqc-inspection-pack HR High
GET /api/v1/cqc-readiness Compliance Medium — aggregate
GET /api/v1/evv/* EVV Medium — visits-service has tracking
GET /api/v1/family/* Family Portal High — no BFF layer exists
GET /api/v1/insurance/* Insurance Not in architecture — park for now
GET /api/v1/import/* Bulk Import Medium — batch job, not REST
GET /api/v1/handoff/* Handoff notes Low — maps to visits-service notes
GET /api/v1/observations Observations Low — maps to assessment-service

8. Timeline Estimate

Phase Work Duration
Phase 0 — Seed data + health verification 1-2 days DevOps + 1 backend dev
Phase 1 — Wire 3 missing BFF routes 3-5 days 2 backend devs
Phase 2 — Frontend switch + BFF fallback 1 day 1 frontend dev + 1 backend dev
Phase 3 — Per-domain cutover (10 domains) 8-10 days 2 backend devs
Phase 4 — Decommission mock 1 day DevOps
Total ~3 weeks

9. Risk Register

Risk Likelihood Impact Mitigation
Real service returns different schema than mock High High Adapter layer in BFF; validate against OpenAPI spec
Empty seed data causes null pointer errors Medium Medium Populate seed before Phase 2 cutover
PostgreSQL connection limits under load Low High Connection pooling via PgBouncer (already in infra)
Visits-service geofence check fails on dev Medium Medium Disable geofence enforcement flag in dev profile
Auth token propagation missing in new BFF controllers Medium High Follow existing WebClientConfig JWT propagation pattern
Family portal with no service breaks the portal High Medium Mock fallback covers family routes until service is built
Azure Container App cold start latency Low Low Min replicas = 1 already set in dev.bicepparam

10. Key File Locations

File Purpose
/Users/makinja/projects/client/lumiscare/mock-api/server.js Source of truth for all mock endpoint behavior
/Users/makinja/projects/client/lumiscare/backend/bff/web-bff/src/main/resources/application.yml BFF service URL configuration
/Users/makinja/projects/client/lumiscare/backend/bff/web-bff/src/main/java/.../controller/ BFF controllers — add new ones here
/Users/makinja/projects/client/lumiscare/backend/bff/web-bff/src/main/java/.../config/ Service client configs — add wiring here
/Users/makinja/projects/client/lumiscare/openapi-specs/ OpenAPI specs per service — source of truth for real paths
/Users/makinja/projects/client/lumiscare/infrastructure/env-parameters/dev.bicepparam Azure infra sizing and image names

DA Corrections — 9 Critical Gaps Addressed

Added 2026-03-26 — Devils Advocate review identified these gaps in the original plan. All 9 are corrections to existing sections or new sections not previously covered.


DA-1. Endpoint Priority Matrix

Full classification of all 222 mock endpoint registrations (18 catch-all wildcards excluded = 204 addressable endpoints).

Status definitions:

Domain Mock Route Status Notes
Assessment GET /api/v1/assessments REAL_READY BFF wired
GET /api/v1/assessments/:id REAL_READY BFF wired
POST /api/v1/assessments REAL_READY BFF wired
PUT /api/v1/assessments/:id REAL_READY BFF wired
PATCH /api/v1/assessments/:id REAL_READY BFF wired
POST /api/v1/assessments/:id/complete REAL_READY BFF wired
GET /api/v1/assessments/:id/body-map NEEDS_WIRING Service has photos/observations endpoints; body-map is a frontend-assembled view
PUT /api/v1/assessments/:id/body-map NEEDS_WIRING As above
GET /api/v1/assessments/:id/scores NEEDS_WIRING Maps to risk-section in assessment-service
GET /api/v1/assessments/:id/scores/:tool NEEDS_WIRING As above
POST /api/v1/assessments/:id/scores/:tool NEEDS_WIRING As above
GET /api/v1/intake REAL_READY OpenAPI /api/v1/intake defined
GET /api/v1/intake/:id REAL_READY OpenAPI /api/v1/intake/{intake_id} defined
POST /api/v1/intake REAL_READY OpenAPI defined
PATCH /api/v1/intake/:id NEEDS_WIRING OpenAPI has GET/POST only; PATCH not in spec
DELETE /api/v1/intake/:id SCOPE_OUT Not in spec; soft-delete not required for MVP
Care Plans GET /api/v1/care-plans REAL_READY BFF wired
GET /api/v1/care-plans/:id REAL_READY BFF wired
POST /api/v1/care-plans REAL_READY BFF wired
PUT /api/v1/care-plans/:id REAL_READY BFF wired
DELETE /api/v1/care-plans/:id REAL_READY BFF wired
POST /api/v1/care-plans/:id/publish REAL_READY BFF wired
GET /api/v1/care-plans/:id/versions REAL_READY BFF wired
GET /api/v1/care-plans/review-due MOCK_ONLY No real endpoint; aggregate query needed
GET /api/v1/master-task-types REAL_READY Service defines master-task-types
GET /api/v1/master-visit-types REAL_READY Service defines master-visit-types
Care plan tasks routes MOCK_ONLY careplan-service has task types, not task CRUD per plan
Care plan risk-alerts routes MOCK_ONLY Not in any service spec
Care plan reviews/consent routes MOCK_ONLY Not in any service spec
POST /api/v1/care-plans/:id/submit-for-approval MOCK_ONLY Status lifecycle managed differently in real service
Visits GET /api/v1/visits NEEDS_WIRING visits-service READY, no BFF VisitsController
GET /api/v1/visits/:id NEEDS_WIRING As above
POST /api/v1/visits NEEDS_WIRING As above
PATCH /api/v1/visits/:id NEEDS_WIRING As above
DELETE /api/v1/visits/:id NEEDS_WIRING As above
POST /api/v1/visits/publish MOCK_ONLY No equivalent in visits-service spec
POST /api/v1/visits/:id/check-in NEEDS_WIRING visits-service has /visits/{visitId}/check-in
POST /api/v1/visits/:id/check-out NEEDS_WIRING visits-service has /visits/{visitId}/check-out
GET /api/v1/visits/:id/emar NEEDS_WIRING visits-service has /visits/{visitId}/emar
POST /api/v1/visits/:id/emar NEEDS_WIRING visits-service has /visits/{visitId}/emar POST
Clinical observations (per-visit) NEEDS_WIRING visits-service has /visits/{visitId}/observations
SOS / running-late / pre-visit-brief MOCK_ONLY Not defined in visits-service OpenAPI
Travel record MOCK_ONLY Tracking endpoints exist but different shape
Scheduling GET /api/v1/schedule-blocks NEEDS_WIRING scheduling-service has /schedule-events; CalendarController exists but path mismatch
POST /api/v1/schedule-blocks NEEDS_WIRING As above
PATCH /api/v1/schedule-blocks/:id NEEDS_WIRING As above
DELETE /api/v1/schedule-blocks/:id NEEDS_WIRING As above
GET /api/v1/completed-events MOCK_ONLY No direct real equivalent; map to completed appointments
POST /api/v1/completed-events/:id/confirm MOCK_ONLY scheduling-service manages this via status update
POST /api/v1/completed-events/bulk-confirm MOCK_ONLY No bulk confirm endpoint in spec
Schedule publish route MOCK_ONLY scheduling-service has /schedules/generate + /schedules/{id}/approve which differs
HR GET /employees/list REAL_READY BFF EmployeeController wired
GET /employees/:id REAL_READY BFF wired
POST /employees REAL_READY BFF wired
PATCH /employees/:id REAL_READY BFF wired
DELETE /employees/:id REAL_READY BFF wired
GET /api/v1/leaves REAL_READY hr-service has leaves endpoint
POST /api/v1/leaves REAL_READY hr-service has leaves POST
PATCH /api/v1/leaves/:id REAL_READY hr-service has leaves PATCH
DELETE /api/v1/leaves/:id REAL_READY hr-service has leaves DELETE
GET /api/v1/hr/supervisions NEEDS_WIRING hr-service has supervisions; BFF sub-path mapping needed
GET /api/v1/hr/absences NEEDS_WIRING hr-service has absences/leaves
GET /api/v1/hr/dbs MOCK_ONLY Not in hr-service OpenAPI; compliance documents endpoint covers this partially
GET /api/v1/hr/bradford MOCK_ONLY Calculated from absences; no real endpoint
GET /api/v1/hr/care-certificate MOCK_ONLY Not in hr-service spec
GET /api/v1/training/courses NEEDS_WIRING hr-service has training; BFF not wired
GET /api/v1/training/compliance NEEDS_WIRING hr-service has training compliance; BFF not wired
GET /api/v1/hr/cqc-inspection-pack MOCK_ONLY No real equivalent — aggregate report
Finance GET /api/v1/finance/invoices REAL_READY BFF FinanceBffController wired
POST /api/v1/finance/invoices REAL_READY BFF wired
PUT /api/v1/finance/invoices/:id REAL_READY BFF wired
GET /api/v1/finance/invoice-groups REAL_READY BFF wired
GET /api/v1/finance/payment-groups REAL_READY BFF wired
GET /api/v1/finance/dashboard REAL_READY BFF wired
Finance timesheets routes REAL_READY finance-service defines timesheets
GET /api/v1/finance/rate-cards MOCK_ONLY Not in finance-service spec
GET /api/v1/finance/funders MOCK_ONLY Not in finance-service spec
GET /api/v1/finance/payroll/* MOCK_ONLY Payroll is a separate domain
GET /api/v1/finance/aged-debtors MOCK_ONLY Calculated report — not in spec
GET /api/v1/finance/nmw-compliance MOCK_ONLY Not in finance-service spec
Incidents GET /api/v1/incidents NEEDS_WIRING incidents-service uses typed routes (/accidents, /safeguarding, /complaints, /hazards); BFF IncidentsController must aggregate or map
GET /api/v1/incidents/:id NEEDS_WIRING Type-specific in real service
POST /api/v1/incidents NEEDS_WIRING Type must be specified to route to correct sub-endpoint
PATCH /api/v1/incidents/:id NEEDS_WIRING As above
DELETE /api/v1/incidents/:id NEEDS_WIRING As above
GET /api/v1/incidents/summary REAL_READY incidents-service has /summary
Export endpoints REAL_READY incidents-service has CSV export per type
Notifications GET /api/v1/notifications/inbox NEEDS_WIRING notification-service READY, BFF NOT wired
GET /api/v1/notifications/inbox/unread-count NEEDS_WIRING As above
PATCH /api/v1/notifications/inbox/:id/read NEEDS_WIRING As above
PATCH /api/v1/notifications/inbox/read-all NEEDS_WIRING As above
POST /api/v1/notifications/mark-all-read NEEDS_WIRING As above
GET /api/v1/notifications/preferences NEEDS_WIRING notification-service has preferences
POST /api/v1/notifications/preferences NEEDS_WIRING As above
PATCH /api/v1/notifications/preferences/quiet-hours NEEDS_WIRING As above
Notification device register/unregister NEEDS_WIRING notification-service has devices endpoint
GET /api/v1/notifications/analytics MOCK_ONLY Not in notification-service spec
Identity GET /api/v1/service-users REAL_READY identity-service + BFF ServiceUsersController
GET /api/v1/service-users/:id REAL_READY BFF wired
POST /api/v1/service-users REAL_READY BFF wired
PATCH /api/v1/service-users/:id REAL_READY BFF wired
DELETE /api/v1/service-users/:id REAL_READY BFF wired
GET /api/v1/organizations NEEDS_WIRING identity-service has organizations; BFF routing partial
GET /api/v1/organizations/:id NEEDS_WIRING As above
GET /api/v1/users NEEDS_WIRING identity-service has users; BFF routing partial
GET /users/about-me REAL_READY identity-service /users/me
GET /api/v1/carers NEEDS_WIRING identity-service users filtered by carer role
POST /api/v1/carers/by-skills MOCK_ONLY No real endpoint — would require identity + hr query
GET /api/v1/skills MOCK_ONLY Not in any service spec
GET /api/v1/settings NEEDS_WIRING identity-service has org settings
PATCH /api/v1/settings NEEDS_WIRING As above
GET /api/v1/rostering-settings MOCK_ONLY Not in any service spec
Family Portal All 16 GET/POST /api/v1/family/* routes MOCK_ONLY No FamilyPortalService; no BFF controller (see DA-8)
Misc / EVV / Dashboard GET /api/v1/dashboard/stats NEEDS_WIRING Requires BFF aggregation across 4+ services
GET /api/v1/cqc-readiness MOCK_ONLY Aggregate report — no real service
GET /api/v1/evv/compliance NEEDS_WIRING visits-service tracking endpoints cover EVV data
GET /api/v1/evv/records NEEDS_WIRING visits-service has location tracking history
GET /api/v1/audit-logs MOCK_ONLY No audit-service in architecture
GET /api/v1/insurance/* SCOPE_OUT Not in product architecture — park post-MVP
GET /api/v1/import/* SCOPE_OUT Batch job domain, not REST for MVP
GET /api/v1/handoff/notes NEEDS_WIRING visits-service /visits/{visitId}/notes covers this
GET /api/v1/handoff/history NEEDS_WIRING visits-service notes with type=handover
GET /api/v1/supervisor/dashboard MOCK_ONLY BFF aggregation — not yet designed
GET /api/v1/supervisor/dashboard/carer-locations NEEDS_WIRING visits-service /tracking/locations/current
GET /api/v1/observations (global) NEEDS_WIRING visits-service has per-visit observations; no global endpoint

Summary counts:

Status Count Action
REAL_READY ~65 Wire frontend → BFF, validate schema (see DA-3)
NEEDS_WIRING ~72 Add BFF controller code (Phase 1 work)
MOCK_ONLY ~52 Keep on mock fallback; schedule for post-MVP
SCOPE_OUT ~15 Remove from BFF routing; return 404 or 501

DA-2. Seed Data Verification (Phase 0.4)

The original plan (Phase 0.1) lists what to seed but provides no way to verify seeds actually loaded. Add Phase 0.4 after all seed scripts have run.

Phase 0.4 — Verify Seed Data Loaded Correctly

Run these queries via Azure Cloud Shell after Phase 0.1 seed load:

-- identity_db
SELECT COUNT(*) AS orgs          FROM organizations;          -- expect >= 1
SELECT COUNT(*) AS users         FROM users;                  -- expect >= 3
SELECT COUNT(*) AS service_users FROM service_users;          -- expect >= 2
SELECT COUNT(*) AS roles         FROM roles;                  -- expect >= 12 (system roles)

-- assessment_db
SELECT COUNT(*) AS intake        FROM assessment_intake;      -- expect >= 0 (can be empty)
SELECT COUNT(*) AS sections      FROM assessment_sections;    -- expect >= 7

-- careplan_db
SELECT COUNT(*) AS task_types    FROM master_task_types;      -- expect >= 5
SELECT COUNT(*) AS visit_types   FROM master_visit_types;     -- expect >= 3

-- visits_db
SELECT COUNT(*) AS visit_statuses FROM visit_status_lookup;   -- expect >= 6 (or check enum table)

-- hr_db
SELECT COUNT(*) AS leave_types   FROM leave_types;            -- expect >= 4
SELECT COUNT(*) AS training_cats FROM training_categories;    -- expect >= 3

-- scheduling_db
SELECT COUNT(*) AS appt_types    FROM appointment_types;      -- expect >= 4

-- finance_db
SELECT COUNT(*) AS inv_statuses  FROM invoice_status_lookup;  -- expect >= 4

-- incidents_db
SELECT COUNT(*) AS categories    FROM incident_categories;    -- expect >= 4 (acc, saf, cmp, haz)

-- notification_db
SELECT COUNT(*) AS templates     FROM notification_templates; -- expect >= 5

verify-seeds.sh — script to run from Azure Cloud Shell:

#!/bin/bash
# verify-seeds.sh — Run from Azure Cloud Shell after Phase 0.1 seed load
# Usage: bash verify-seeds.sh <pg-server-name> <admin-user>

PG_SERVER="${1}.postgres.database.azure.com"
PG_USER="$2"
FAILED=0

run_check() {
  local DB=$1 QUERY=$2 LABEL=$3 MIN=$4
  COUNT=$(psql "host=$PG_SERVER user=$PG_USER dbname=$DB sslmode=require" \
    -tAc "$QUERY" 2>/dev/null)
  if [ -z "$COUNT" ] || [ "$COUNT" -lt "$MIN" ]; then
    echo "FAIL [$DB] $LABEL: got $COUNT (expected >= $MIN)"
    FAILED=$((FAILED+1))
  else
    echo "PASS [$DB] $LABEL: $COUNT rows"
  fi
}

run_check "identity_db"      "SELECT COUNT(*) FROM organizations;"    "organizations"     1
run_check "identity_db"      "SELECT COUNT(*) FROM users;"            "users"             3
run_check "identity_db"      "SELECT COUNT(*) FROM service_users;"    "service_users"     2
run_check "identity_db"      "SELECT COUNT(*) FROM roles;"            "roles"             12
run_check "careplan_db"      "SELECT COUNT(*) FROM master_task_types;" "master_task_types" 5
run_check "careplan_db"      "SELECT COUNT(*) FROM master_visit_types;" "master_visit_types" 3
run_check "hr_db"            "SELECT COUNT(*) FROM leave_types;"      "leave_types"       4
run_check "scheduling_db"    "SELECT COUNT(*) FROM appointment_types;" "appointment_types" 4
run_check "incidents_db"     "SELECT COUNT(*) FROM incident_categories;" "incident_categories" 4
run_check "notification_db"  "SELECT COUNT(*) FROM notification_templates;" "notification_templates" 5

if [ "$FAILED" -gt 0 ]; then
  echo ""
  echo "SEED VERIFICATION: $FAILED check(s) FAILED. Do NOT proceed to Phase 1."
  exit 1
else
  echo ""
  echo "SEED VERIFICATION: All checks PASSED. Safe to proceed to Phase 1."
  exit 0
fi

Gate: Phase 1 (BFF wiring) must not begin until verify-seeds.sh exits 0.


DA-3. Shape Mismatch Matrix

Comparison of mock API response shapes vs real OpenAPI-defined shapes for high-traffic routes. These mismatches require BFF adapter code — the BFF cannot simply proxy; it must transform.

Visits — GET /api/v1/visits

Field Mock shape Real service shape Action
Response wrapper Array [...] Paginated object { content: [...], pageInfo: { ... } } BFF must extract content array or frontend must handle pagination
ID format "visit-0001" (string with prefix) UUID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" BFF must map or real service auto-generates UUIDs
Client reference clientId + clientName (flat) serviceUserId (UUID) — no embedded name BFF must enrich with identity-service lookup or frontend fetches separately
Status values "in-progress", "scheduled", "completed" (kebab-case) in_progress, scheduled, completed (snake_case enum) BFF adapter or frontend normalizes
Visit type "personal-care", "medication" (kebab-case strings) AppointmentType enum: care_visit, assessment_visit, medication_only, welfare_check Mapping required — not 1:1
GPS check-in gpsCheckIn: { lat, lng } checkInLocation: { latitude, longitude, accuracy, altitude, timestamp } (GpsLocation schema) Field rename + structure change
Duration duration: 60 (minutes, integer) Derived from scheduledStartTime / scheduledEndTime — no standalone duration field BFF calculates or omits
Required headers None X-VCU-Organization-Id, X-VCU-User-Id, X-VCU-Roles must be forwarded BFF must propagate JWT-extracted headers

Incidents — GET /api/v1/incidents

Field Mock shape Real service shape Action
Response wrapper { incidents: [...], total: N } Each type has own paginated endpoint: /accidents, /safeguarding, /complaints, /hazards BFF must fan-out to 4 endpoints and merge, OR frontend switches to type-specific routes
id format "inc-001" UUID BFF-generated or real service UUID
type values "Accident", "Medication_Error", "Safeguarding" (mixed case, non-typed) Routes are typed: /accidents = type ACCIDENT/INCIDENT/NEAR_MISS; /safeguarding uses ConcernType enum Routing logic required in BFF
status values "Resolved", "Under_Review", "Investigating" LogStatus enum: IDENTIFIED, RAISED, IN_PROGRESS, UPHELD, NOT_UPHELD, PARTIALLY_UPHELD, WITHDRAWN, RESOLVED Mapping table needed
incident_number "INC-2024-001" (mock format) Auto-generated: "ACC-2026-00001", "SAF-2026-00001" etc. Display only; reference format changes
Duplicate fields Both serviceUserName and service_user_name exist Single serviceUserId (UUID reference) Remove duplicates; BFF enriches name
actionsTaken Embedded array of action objects Separate endpoint: /logs/{logType}/{logId}/actions BFF must fetch separately or omit on list
Header X-Org-Id (mock uses no header) X-VCC-Organization-Id required BFF must add

Scheduling — GET /api/v1/schedule-blocks

Field Mock shape Real service shape Action
Path /api/v1/schedule-blocks /api/v1/scheduling/schedule-events BFF maps path
Response wrapper Array [...] Paginated { content: [...], ... } BFF unwraps or frontend adapts
type values "team-meeting", "training", "supervision", "appraisal" ScheduleEventType enum: appraisal, meeting, supervision, training team-meetingmeeting mapping
id format "sb-001" UUID BFF maps
carerId String "3" UUID BFF must translate carer numeric ID → UUID via identity-service

Assessment — GET /api/v1/assessments/:id

Field Mock shape Real service shape Action
completionStatus "IN_PROGRESS" / "COMPLETED" status field in real service with different enum values Field rename
patientId UUID reference serviceUserId — same concept, different field name BFF renames
assessmentId + id Both present (legacy compat) Single id field BFF normalizes to single id
overview Nested object { riskLevel, allergies, dnacp, nextAssessmentDate, ... } Not a single nested block — data spread across sections and risk-section endpoints BFF must assemble from multiple sub-endpoints
assessments Array of section objects with nested questions Sections are separate sub-resources fetched via /assessments/{id}/sections BFF must aggregate
Header No header in mock X-VCC-User-Id, X-VCC-Organization-Id, X-VCC-User-Email required BFF forwards

Care Plans — GET /api/v1/care-plans/:id

Field Mock shape Real service shape Action
clientId String Real service uses serviceUserId (UUID) Field rename in BFF adapter
status values Custom string values CarePlanStatus enum: draft, ai_generated, under_review, approved, active, suspended, completed, cancelled Map mock statuses to enum values
Server URL Mock uses /api/v1/care-plans Real service base: https://api.vcc2.com/v1/api/v1/care-plans — note double prefix in careplan OpenAPI Confirm actual deployed base path
tasks Embedded array in plan response Separate resource: TaskCategory objects under Visit objects Frontend must navigate new structure

Action required for all shape mismatches: Add an adapter/transformer class in the BFF for each domain when wiring controllers (Phase 1). Do not rely on the real service coincidentally matching the mock shape.


DA-4. Post-Migration Schema Audit

After Phase 3 (per-domain cutover) completes for each domain, run a schema audit before disabling the mock fallback for that domain.

Add to Phase 3 per-domain checklist:

Step 6 (new) — Schema audit for domain being cut over:

# Example for visits domain — run from a machine with curl access to BFF
BFF_URL="https://<web-bff-fqdn>.azurecontainerapps.io"
AUTH_TOKEN="<valid-bearer-token>"

# 1. Fetch a real response
curl -s -H "Authorization: Bearer $AUTH_TOKEN" \
  "$BFF_URL/api/v1/visits?page=0&size=5" \
  -o /tmp/real-visits-response.json

# 2. Validate against OpenAPI spec using swagger-cli or similar
npx @apidevtools/swagger-cli validate \
  /Users/makinja/projects/client/lumiscare/openapi-specs/visits-open-api/open-api.yaml

# 3. Manual spot-check — verify required fields present
node -e "
  const data = require('/tmp/real-visits-response.json');
  const required = ['id','status','scheduledStartTime','scheduledEndTime','serviceUserId','carerId'];
  const first = data.content?.[0] || data[0] || {};
  required.forEach(f => {
    if (first[f] === undefined) console.log('MISSING:', f);
    else console.log('PRESENT:', f, '=', JSON.stringify(first[f]).slice(0, 40));
  });
"

Acceptance criteria for schema audit:

Gate: Do not disable mock fallback for a domain until schema audit passes.


DA-5. Rollback Test (Phase 2.4)

The existing rollback plan (Section 6) describes the mechanism but never tests it. A rollback that has never been tested is not a reliable rollback.

Add Phase 2.4 — Rollback Test (run after Phase 2.3, before Phase 3)

Procedure:

  1. Confirm BFF fallback is enabled (MOCK_API_FALLBACK_ENABLED=true)
  2. Confirm frontend is pointing to BFF URL (Phase 2.1 complete)
  3. For one REAL_READY domain (recommended: Identity), disable the BFF route to real service:
    • Comment out or stub the real service client for that domain in BFF
    • Redeploy BFF (or use feature flag)
  4. Verify BFF fallback activates:
    • curl $BFF_URL/api/v1/service-users should return mock data (HTTP 200, mock IDs like "su-001")
    • Browser: service users page must render without error
  5. Re-enable the real service client
  6. Verify real data is served again
  7. Document the rollback time (target: under 5 minutes end-to-end including BFF redeploy)

Pass criteria:

Gate: If rollback test fails, do NOT proceed to Phase 3. Fix the fallback mechanism first.


DA-6. Phase Environment Matrix

At each phase, different environments run on different data sources. This was implicit in the original plan — made explicit here.

Phase Dev environment Test environment Staging environment Production
Pre-migration (now) Frontend → Mock direct N/A N/A N/A
Phase 0 (prep) Seed loaded in Azure dev DBs Mock still running Not affected Not affected
Phase 1 (BFF wiring) BFF code changes in dev branch Mock fallback enabled Not affected Not affected
Phase 2 (frontend switch) Frontend → BFF; BFF fallback ON for all routes Frontend → BFF; BFF fallback ON Not affected Not affected
Phase 3 (per-domain cutover) BFF routes real per domain; fallback OFF per domain after audit BFF + fallback; promote domain-by-domain after dev validates BFF + fallback per domain; reduced fallback set Not affected until explicit prod migration
Phase 4 (decommission) Mock stopped Mock stopped Mock stopped N/A (mock never ran in prod)

Environment-specific flags:

# application-dev.yml
mock-api:
  fallback-url: ${MOCK_API_URL:http://ca-vcc-dev-mock-api:3000}
  fallback-enabled: true
  fallback-domains:
    visits: true          # flip to false after Phase 3 domain cutover
    scheduling: true
    notifications: true
    family: true          # stays true until FamilyPortalService exists
    misc: true

# application-test.yml
mock-api:
  fallback-url: ${MOCK_API_URL:http://ca-vcc-test-mock-api:3000}
  fallback-enabled: true
  fallback-domains:
    visits: true
    # ... test environment follows dev by ~1 sprint

# application-staging.yml
mock-api:
  fallback-enabled: false   # staging runs real services or explicit test data
  fallback-domains: {}      # no fallback in staging

# application-prod.yml
mock-api:
  fallback-enabled: false   # mock never deployed in prod

DA-7. Evidence Checklist per Domain (Cutover Gate)

For each domain cutover in Phase 3, the following evidence must be machine-generated before the mock fallback is disabled for that domain. "Works on my machine" and agent-reported PASS are not acceptable (ZAKON #21).

Template — fill out for each domain:

Domain: _______________
Date: _______________
Engineer: _______________

[ ] 1. seed-verify: DB row counts pass verify-seeds.sh for this domain's DB (exit 0)
[ ] 2. health-check: Container App status = Running
      Evidence: az containerapp show --name <ca-name> --query properties.runningStatus
[ ] 3. direct-service: Direct HTTP call to real service returns 200
      Evidence: curl -s -o /tmp/service-health.json -w "%{http_code}" http://<service-internal-url>/actuator/health
[ ] 4. bff-proxy: BFF routes traffic to real service (not mock)
      Evidence: curl -s -H "Authorization: Bearer $TOKEN" $BFF_URL/api/v1/<domain-route> | head -c 200
      Confirm: IDs are UUIDs, not mock format (e.g., "su-001")
[ ] 5. schema-audit: Required fields present in response (DA-4 procedure)
      Evidence: node schema-audit.js /tmp/<domain>-response.json
[ ] 6. no-500s: Zero 500 errors in Azure Application Insights for domain in last 30 min
      Evidence: az monitor app-insights query --app <app-insights-name> --analytics-query "..."
[ ] 7. frontend-render: Domain UI renders without console errors
      Evidence: Screenshot or Playwright test output
[ ] 8. rollback-ready: MOCK_API_FALLBACK_ENABLED=true can be set within 5 min if needed
      Evidence: Rollback test passed (Phase 2.4)

PASS if all 8 checked. FAIL = keep mock fallback for this domain.

Minimum bar per domain:


DA-8. Family Portal ADR (Architecture Decision Record)

Decision required before Phase 3 begins.

Context

The Family Portal has 16 mock endpoints (/api/v1/family/*). There is no FamilyPortalService in the deployed microservice architecture. Building a proper BFF layer for family portal requires aggregating from:

Options

Option A — Build FamilyPortalBffController in web-bff (or new family-bff)

Option B — Scope out Family Portal from MVP; keep on mock fallback

Decision

Recommendation: Option B — Scope Family Portal out of MVP migration.

Family portal features are non-critical for the primary care agency workflow. The MVP needs the back-office and mobile carer workflows operational. Family portal is a Phase 2 deliverable.

Actions:

  1. Do NOT wire family portal routes to any real service during Phase 3
  2. Keep mock-api.fallback-domains.family: true permanently through MVP launch
  3. Add POST /api/v1/family/* routes to the MOCK_ONLY fallback list explicitly in BFF config
  4. Create a new backlog item: "FamilyPortalService design + BFF wiring" — target: post-MVP sprint 1
  5. Timeline target for family portal real wiring: 6-8 weeks post-MVP launch

This ADR is a CEO-level decision. Tag for explicit sign-off before Phase 3 begins.


DA-9. Demo Protection

During Phase 3 and leading up to any investor demo or client presentation, certain routes must remain stable. A real service returning unexpected data or a 500 error during a demo is unacceptable.

Demo-Critical Routes

These routes are rendered on the first screens visible during a standard demo:

GET  /api/v1/dashboard/stats
GET  /api/v1/service-users
GET  /api/v1/service-users/:id
GET  /api/v1/care-plans
GET  /api/v1/care-plans/:id
GET  /api/v1/assessments
GET  /api/v1/visits
GET  /api/v1/incidents
GET  /api/v1/notifications/inbox
GET  /api/v1/notifications/inbox/unread-count

DEMO_MODE Flag

Add a DEMO_MODE environment flag to the BFF:

# application.yml (BFF)
demo:
  mode: ${DEMO_MODE:false}
  # When true: all demo-critical routes use mock fallback regardless of domain cutover status
  # Overrides per-domain fallback-enabled settings for demo-critical routes only
  protected-routes:
    - /api/v1/dashboard/stats
    - /api/v1/service-users
    - /api/v1/service-users/**
    - /api/v1/care-plans
    - /api/v1/care-plans/**
    - /api/v1/assessments
    - /api/v1/visits
    - /api/v1/incidents
    - /api/v1/notifications/inbox
    - /api/v1/notifications/inbox/unread-count

BFF routing logic (pseudo-code):

// In BFF route handler
if (demoMode && demoProtectedRoutes.matches(request.getPath())) {
    return mockFallback.forward(request);  // always use mock for demo routes in DEMO_MODE
}
// Otherwise: normal real-service routing
return realService.forward(request);

48-Hour Stability Rule

For demo-critical routes, do not disable the mock fallback until the real service has been stable for 48 hours with zero 5xx errors. Evidence required: Azure Application Insights query showing error rate = 0 for 48h window.

# Check 48h stability for visits domain
az monitor app-insights query \
  --app <app-insights-resource> \
  --analytics-query "
    requests
    | where timestamp > ago(48h)
    | where url contains '/api/v1/visits'
    | where resultCode startswith '5'
    | count
  "
# Expected output: count = 0

Demo Runbook

Before any investor demo or client presentation:

  1. Set DEMO_MODE=true in BFF Container App environment (Azure Portal or az containerapp update)
  2. Verify dashboard loads with realistic mock data
  3. Do NOT disable DEMO_MODE until demo is complete
  4. After demo: reset DEMO_MODE=false to resume real-service routing

DA-1. Endpoint Priority Matrix

All 204 addressable mock endpoints classified by migration readiness. Wildcards and catch-alls excluded.

Classification key:

Visits (14 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/visits NEEDS_WIRING visits-service /visits exists; BFF controller missing
POST /api/v1/visits NEEDS_WIRING visits-service /visits POST exists; BFF controller missing
GET /api/v1/visits/:id NEEDS_WIRING visits-service /visits/{visitId} exists
PATCH /api/v1/visits/:id NEEDS_WIRING visits-service PATCH exists
DELETE /api/v1/visits/:id NEEDS_WIRING visits-service DELETE exists
POST /api/v1/visits/:id/check-in NEEDS_WIRING visits-service check-in exists
POST /api/v1/visits/:id/check-out NEEDS_WIRING visits-service check-out exists
GET /api/v1/visits/:id/emar NEEDS_WIRING visits-service eMAR exists
GET /api/v1/visits/:id/tasks NEEDS_WIRING visits-service tasks list exists
GET /api/v1/visits/today NEEDS_WIRING visits-service /visits/today defined
POST /api/v1/visits/publish MOCK_ONLY No publish concept in visits-service OpenAPI
POST /api/v1/visits/:id/running-late MOCK_ONLY No equivalent in visits-service spec
GET /api/v1/visits/:id/pre-visit-brief MOCK_ONLY Aggregated BFF feature, not a service endpoint
POST /api/v1/visits/:id/travel-record MOCK_ONLY Tracking endpoint in visits-service is different shape

Scheduling (8 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/schedule-blocks NEEDS_WIRING Maps to /schedule-events in scheduling-service; CalendarController exists but not wired for this alias
POST /api/v1/schedule-blocks NEEDS_WIRING Maps to POST /schedule-events
GET /api/v1/schedule-blocks/:id NEEDS_WIRING Maps to /schedule-events/{eventId}
PATCH /api/v1/schedule-blocks/:id NEEDS_WIRING Maps to PUT /schedule-events/{eventId}
DELETE /api/v1/schedule-blocks/:id NEEDS_WIRING Maps to DELETE /schedule-events/{eventId}
GET /api/v1/completed-events NEEDS_WIRING Maps to /appointments with status=completed filter
POST /api/v1/completed-events/:id/confirm NEEDS_WIRING Maps to POST /appointments/{id}/cancel pattern (status update)
POST /api/v1/completed-events/bulk-confirm MOCK_ONLY No bulk-confirm operation in scheduling-service spec

Assessment (12 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/assessments REAL_READY BffAssessmentController wired
GET /api/v1/assessments/:id REAL_READY BffAssessmentController wired
POST /api/v1/assessments REAL_READY BffAssessmentController wired
PUT /api/v1/assessments/:id REAL_READY BffAssessmentController wired
PATCH /api/v1/assessments/:id REAL_READY BffAssessmentController wired
POST /api/v1/assessments/:id/complete REAL_READY Maps to assessment submit endpoint
GET /api/v1/assessments/:id/body-map NEEDS_WIRING assessment-service has body-map section; BFF wiring unconfirmed
PUT /api/v1/assessments/:id/body-map NEEDS_WIRING as above
GET /api/v1/assessments/:id/scores MOCK_ONLY No scoring endpoint in assessment-service spec; maps to risk-section concept
GET /api/v1/assessments/:id/scores/:tool MOCK_ONLY No tool-specific scores in spec
POST /api/v1/assessments/:id/scores/:tool MOCK_ONLY No tool-specific scores in spec
GET /api/v1/intake REAL_READY assessment-service /api/v1/intake matches

Care Plans (14 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/care-plans REAL_READY CarePlanController wired
GET /api/v1/care-plans/:id REAL_READY CarePlanController wired
POST /api/v1/care-plans REAL_READY CarePlanController wired
PUT /api/v1/care-plans/:id REAL_READY CarePlanController wired
DELETE /api/v1/care-plans/:id REAL_READY CarePlanController wired
POST /api/v1/care-plans/:id/publish REAL_READY careplan-service publish endpoint exists
GET /api/v1/care-plans/:id/versions REAL_READY careplan-service versions endpoint exists
GET /api/v1/care-plans/review-due MOCK_ONLY No review-due filter in careplan-service spec
POST /api/v1/care-plans/:id/submit-for-approval MOCK_ONLY No submit-for-approval step in real spec
GET /api/v1/care-plans/:id/tasks MOCK_ONLY Task management not in careplan-service OpenAPI
GET /api/v1/care-plans/:id/risk-alerts MOCK_ONLY No risk-alerts endpoint in careplan-service
GET /api/v1/care-plans/:id/reviews MOCK_ONLY No reviews endpoint in careplan-service
POST /api/v1/care-plans/:id/consent MOCK_ONLY No consent endpoint in careplan-service
GET /api/v1/master-task-types REAL_READY careplan-service has master-task-types

HR (18 endpoints)

Mock Endpoint Classification Notes
GET /employees/list REAL_READY EmployeeController wired (legacy path)
GET /employees/:id REAL_READY EmployeeController wired
POST /employees REAL_READY EmployeeController wired
PATCH /employees/:id REAL_READY EmployeeController wired
DELETE /employees/:id REAL_READY EmployeeController wired
GET /api/v1/leaves REAL_READY hr-service leaves endpoint exists; BFF wired
POST /api/v1/leaves REAL_READY hr-service leaves POST exists
PATCH /api/v1/leaves/:id REAL_READY hr-service leaves PATCH exists
DELETE /api/v1/leaves/:id REAL_READY hr-service leaves DELETE exists
GET /api/v1/hr/supervisions NEEDS_WIRING hr-service has supervisions; BFF sub-route not wired
GET /api/v1/hr/supervision-schedule NEEDS_WIRING hr-service has supervision data; path mapping needed
GET /api/v1/hr/absences NEEDS_WIRING hr-service has absence/leave data; path alias needed
GET /api/v1/hr/training NEEDS_WIRING hr-service has training; BFF route not wired
GET /api/v1/training/courses NEEDS_WIRING hr-service training module; BFF path different
GET /api/v1/hr/dbs MOCK_ONLY DBS checks not in hr-service OpenAPI as named endpoint
GET /api/v1/hr/bradford MOCK_ONLY Calculated aggregate; no endpoint in hr-service
GET /api/v1/hr/care-certificate MOCK_ONLY Not in hr-service OpenAPI
GET /api/v1/hr/cqc-inspection-pack SCOPE_OUT Complex regulatory aggregate; not MVP

Finance (20 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/finance/invoices REAL_READY FinanceBffController wired
GET /api/v1/finance/invoices/:id REAL_READY FinanceBffController wired
POST /api/v1/finance/invoices REAL_READY FinanceBffController wired
PUT /api/v1/finance/invoices/:id REAL_READY FinanceBffController wired
GET /api/v1/finance/invoice-groups REAL_READY finance-service invoice-groups; BFF wired
POST /api/v1/finance/invoice-groups REAL_READY finance-service wired
GET /api/v1/finance/payment-groups REAL_READY finance-service wired
POST /api/v1/finance/payment-groups REAL_READY finance-service wired
GET /api/v1/finance/timesheets NEEDS_WIRING finance-service has timesheets; BFF sub-route unconfirmed
GET /api/v1/finance/dashboard NEEDS_WIRING finance-service dashboard exists; aggregation needed
GET /api/v1/finance/rate-cards MOCK_ONLY Not in finance-service OpenAPI
GET /api/v1/finance/funders MOCK_ONLY Not in finance-service OpenAPI
GET /api/v1/finance/payroll/preview MOCK_ONLY Payroll is separate domain; not in MVP
POST /api/v1/finance/payroll/approve MOCK_ONLY Payroll not in MVP
GET /api/v1/finance/payroll/export SCOPE_OUT Out of MVP scope
GET /api/v1/finance/aged-debtors MOCK_ONLY Calculated from invoices; no dedicated endpoint
GET /api/v1/finance/nmw-compliance SCOPE_OUT Compliance report; out of MVP scope
GET /api/v1/finance/month-end-status MOCK_ONLY No equivalent in finance-service spec
GET /api/v1/finance/bank-holidays MOCK_ONLY Static data; serve from BFF config
GET /api/v1/invoices REAL_READY Legacy path; maps to finance-service invoices

Incidents (8 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/incidents NEEDS_WIRING Real service has typed routes (/accidents, /safeguarding, /complaints, /hazards); BFF must aggregate or route by type
GET /api/v1/incidents/:id NEEDS_WIRING BFF must determine type and proxy to correct sub-service
POST /api/v1/incidents NEEDS_WIRING BFF must route by type field to correct incident sub-resource
PATCH /api/v1/incidents/:id NEEDS_WIRING Same routing requirement
DELETE /api/v1/incidents/:id NEEDS_WIRING Same routing requirement
GET /api/v1/incidents/summary REAL_READY incidents-service /summary endpoint exists; IncidentsController wired
POST /api/v1/incidents/:id/actions NEEDS_WIRING incidents-service log-actions endpoint exists; BFF wiring unconfirmed
GET /api/v1/incidents/export SCOPE_OUT Export for each sub-type exists in spec; aggregate export not MVP

Notifications (10 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/notifications/inbox NEEDS_WIRING notification-service inbox exists; BFF controller missing entirely
GET /api/v1/notifications/inbox/unread-count NEEDS_WIRING notification-service unread-count exists; BFF missing
PATCH /api/v1/notifications/inbox/:id/read NEEDS_WIRING notification-service mark-read exists; BFF missing
PATCH /api/v1/notifications/inbox/read-all NEEDS_WIRING notification-service mark-all-read exists; BFF missing
GET /api/v1/notifications/preferences NEEDS_WIRING notification-service preferences exists; BFF missing
POST /api/v1/notifications/preferences NEEDS_WIRING notification-service preferences POST exists; BFF missing
PATCH /api/v1/notifications/preferences/quiet-hours NEEDS_WIRING notification-service; BFF missing
POST /api/v1/notifications/devices NEEDS_WIRING notification-service device registration; BFF missing
POST /api/v1/notifications/push NEEDS_WIRING notification-service send endpoint; BFF missing
GET /api/v1/notifications/analytics MOCK_ONLY Not in notification-service spec

Identity / Users / Orgs / Service Users (14 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/service-users REAL_READY ServiceUsersController wired; identity-service backs it
GET /api/v1/service-users/:id REAL_READY ServiceUsersController wired
POST /api/v1/service-users REAL_READY ServiceUsersController wired
PATCH /api/v1/service-users/:id REAL_READY ServiceUsersController wired
DELETE /api/v1/service-users/:id REAL_READY ServiceUsersController wired
GET /api/v1/users NEEDS_WIRING identity-service users endpoint exists; BFF route may not be exposed
GET /api/v1/organizations NEEDS_WIRING identity-service orgs endpoint exists; BFF route unconfirmed
GET /api/v1/organizations/:id NEEDS_WIRING identity-service; BFF unconfirmed
GET /api/v1/settings NEEDS_WIRING identity-service org settings; BFF route unconfirmed
PATCH /api/v1/settings NEEDS_WIRING identity-service org settings PATCH; BFF unconfirmed
GET /api/v1/carers NEEDS_WIRING Maps to identity-service users with carer role filter
POST /api/v1/carers/by-skills MOCK_ONLY No skills-based search in identity-service spec
GET /api/v1/skills MOCK_ONLY No dedicated skills list endpoint in identity-service
GET /api/v1/rostering-settings MOCK_ONLY Not in identity-service spec

Family Portal (16 endpoints)

Mock Endpoint Classification Notes
ALL GET /api/v1/family/* MOCK_ONLY No FamilyPortalService exists. See DA-8 ADR below.

Misc / EVV / Dashboard / Compliance (24 endpoints)

Mock Endpoint Classification Notes
GET /api/v1/dashboard/stats NEEDS_WIRING Aggregate from multiple services; BFF orchestration needed
GET /api/v1/cqc-readiness MOCK_ONLY Aggregate; not in any service spec
GET /api/v1/evv/compliance NEEDS_WIRING Maps to visits-service tracking data; BFF aggregation needed
GET /api/v1/evv/records NEEDS_WIRING Maps to visits-service location tracking history
GET /api/v1/evv/records/:id NEEDS_WIRING Maps to visits-service tracking detail
GET /api/v1/audit-logs MOCK_ONLY No audit service in current architecture
GET /api/v1/insurance/claims SCOPE_OUT Not in architecture; park for post-MVP
GET /api/v1/insurance/payers SCOPE_OUT Not in architecture; park for post-MVP
POST /api/v1/handoff/notes NEEDS_WIRING Maps to visits-service care notes with type=handover
GET /api/v1/handoff/history NEEDS_WIRING Maps to visits-service care notes filtered by type
POST /api/v1/handoff/notes/:id/acknowledge MOCK_ONLY No acknowledgement concept in visits-service notes
GET /api/v1/observations NEEDS_WIRING Maps to assessment-service or visits-service observations
GET /api/v1/supervisor/dashboard MOCK_ONLY Aggregate view; BFF composition needed post-MVP
GET /api/v1/supervisor/dashboard/carer-locations NEEDS_WIRING Maps to visits-service /tracking/locations/current
POST /api/v1/alerts/:id/acknowledge MOCK_ONLY No alert acknowledgement service
GET /api/v1/clients/:id/outcomes MOCK_ONLY No outcomes service
GET /api/v1/clients/:id/care-summary MOCK_ONLY BFF aggregate; not MVP priority
GET /api/v1/training/compliance NEEDS_WIRING Maps to hr-service training compliance data
GET /api/v1/care-alerts/:id/acknowledge MOCK_ONLY No care-alerts service
ALL others (wildcards) SCOPE_OUT Catch-all routes; decommission with mock

Priority Matrix Summary

Classification Count Action
REAL_READY ~47 Verify in Phase 3; disable mock fallback per-route
NEEDS_WIRING ~68 Phase 1 + Phase 3 BFF work
MOCK_ONLY ~63 Keep mock fallback; build real service post-MVP
SCOPE_OUT ~26 Disable with no replacement; document as out-of-scope

DA-2. Seed Data Verification (Phase 0.4)

Add this phase between Phase 0.1 (seed load) and Phase 0.2 (container health check).

Phase 0.4 — Verify Seed Data Loaded Correctly

After running seed scripts via Azure Cloud Shell, verify row counts before proceeding to Phase 1.

Expected minimum row counts per database:

Database Table Minimum Rows Purpose
identity_db organizations 1 Test org
identity_db users 5 1 admin, 1 care-manager, 3 carers
identity_db service_users 3 Test clients
identity_db roles 12 Pre-seeded system roles
assessment_db assessment_sections 7 ASSESSMENT_SECTION_DEFS equivalent
assessment_db risk_sections 6 RISK_SECTION_DEFS equivalent
careplan_db master_task_types 10 Task type catalogue
careplan_db master_visit_types 4 Visit type catalogue
visits_db visit_statuses 7 scheduled, late, in_progress, completed, cancelled, missed, flagged
hr_db leave_types 5 Annual, sick, maternity, etc.
hr_db training_categories 4 Mandatory, CPD, compliance, specialist
scheduling_db appointment_types 4 care_visit, assessment_visit, medication_only, welfare_check
finance_db invoice_statuses 5 Draft, issued, paid, overdue, cancelled
incidents_db incident_type_config 4 accidents, safeguarding, complaints, hazards
notification_db notification_templates 5 Core template types

Verification queries — run in Azure Cloud Shell after seed:

-- identity_db
SELECT 'organizations' as tbl, count(*) FROM organizations
UNION ALL SELECT 'users', count(*) FROM users
UNION ALL SELECT 'service_users', count(*) FROM service_users
UNION ALL SELECT 'roles', count(*) FROM roles;

-- assessment_db
SELECT 'assessment_sections', count(*) FROM assessment_sections
UNION ALL SELECT 'risk_sections', count(*) FROM risk_sections;

-- careplan_db
SELECT 'master_task_types', count(*) FROM master_task_types
UNION ALL SELECT 'master_visit_types', count(*) FROM master_visit_types;

-- visits_db
SELECT 'visit_task_types', count(*) FROM visit_task_types;

-- incidents_db
SELECT table_name, 0 as dummy FROM information_schema.tables
WHERE table_schema = 'public'; -- verify tables exist

-- finance_db
SELECT 'invoice_line_items_config', count(*) FROM invoice_statuses;

Verify-seeds script spec:

Create /Users/makinja/projects/client/lumiscare/scripts/verify-seeds.sh:

#!/bin/bash
# verify-seeds.sh — run from Azure Cloud Shell after seed load
# Usage: bash verify-seeds.sh <pg-host> <admin-user>

PG_HOST="$1"
PG_USER="$2"
FAIL=0

check() {
  local DB=$1 TBL=$2 MIN=$3
  COUNT=$(psql "host=$PG_HOST user=$PG_USER dbname=$DB sslmode=require" \
    -tAc "SELECT count(*) FROM $TBL 2>/dev/null || echo 0")
  if [ "$COUNT" -lt "$MIN" ]; then
    echo "FAIL: $DB.$TBL has $COUNT rows (expected >= $MIN)"
    FAIL=1
  else
    echo "PASS: $DB.$TBL = $COUNT rows"
  fi
}

check identity_db organizations 1
check identity_db users 5
check identity_db service_users 3
check assessment_db assessment_sections 7
check careplan_db master_task_types 10
check visits_db visit_task_types 4
check finance_db invoice_statuses 3
check incidents_db incident_categories 4

[ $FAIL -eq 0 ] && echo "ALL SEED CHECKS PASSED" || { echo "SEED VERIFICATION FAILED — do not proceed to Phase 1"; exit 1; }

Seed verification must pass before Phase 1 work begins. If any check fails, re-run the corresponding seed script.


DA-3. Shape Mismatch Matrix

Critical field-level differences between mock API response shapes and real OpenAPI-specified shapes. BFF adapter layer must translate these on cutover.

Visits — GET /api/v1/visits

Field Mock Shape Real Service Shape (visits-service OpenAPI) BFF Action
List wrapper [...visits] (bare array) { "visits": [...], "pageInfo": { "total": N, "page": 0, "size": 20 } } BFF must unwrap visits array for frontend; frontend expects array
id "visit-0001" (string, dash-prefixed) UUID format "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ID format will change; frontend must handle UUID
clientId "su-001" (string, dash-prefixed) serviceUserId (UUID) Field rename: clientIdserviceUserId
clientName "Dorothy Johnson" (string in visit object) Not in visit object — join required from identity-service BFF must enrich with identity-service lookup or accept that frontend needs separate call
status "in-progress" (kebab-case) "in_progress" (snake_case enum: scheduled, late, in_progress, completed, cancelled, missed, flagged) BFF must normalize status values
type "personal-care" (kebab-case, free string) appointmentType (enum: care_visit, assessment_visit, medication_only, welfare_check) Field rename + value normalization
gpsCheckIn { lat: 51.5074, lng: -0.1278 } { "latitude": 51.5074, "longitude": -0.1278, "accuracy": 5.0, "timestamp": "..." } (GpsLocation schema) Field rename: latlatitude, lnglongitude; add required fields
careNotes String field on visit object Separate endpoint GET /visits/{visitId}/notes[{ "noteType": "...", "content": "..." }] Notes must be fetched separately; BFF may aggregate or frontend must call separately
actualCheckIn / actualCheckOut ISO string on visit object Nested in check-in/check-out response objects, not returned on visit GET BFF must compose from visit + lifecycle data

Scheduling — GET /api/v1/schedule-blocks

Field Mock Shape Real Service Shape (scheduling-service OpenAPI) BFF Action
Resource name schedule-blocks (array of blocks) schedule-events (ScheduleEvent objects) Path alias handled by BFF
type "team-meeting", "training", "supervision", "appraisal" (kebab-case) ScheduleEventType enum: meeting, training, supervision, appraisal (no dash, no team- prefix) BFF must normalize team-meetingmeeting
duration Integer (minutes) Not a top-level field; calculated from startDateTime and endDateTime BFF may compute duration from datetime diff
startTime / endTime ISO string startDateTime / endDateTime (ISO 8601 with timezone) Field rename in BFF adapter
List wrapper Bare array Paginated: { "content": [...], "page": 0, "size": 20, "totalElements": N, "totalPages": N } BFF extracts content or adapts to paginated format

Incidents — GET /api/v1/incidents

Field Mock Shape Real Service Shape (incidents-service OpenAPI) BFF Action
List wrapper { "incidents": [...], "total": N } Per type: { "content": [...], "page": 0, "totalElements": N, "totalPages": N } BFF must aggregate responses from /accidents, /safeguarding, /complaints, /hazards
id "inc-001" (string) UUID (auto-generated) ID format change; BFF cannot map old IDs
type "Accident", "Medication_Error", "Safeguarding" Separate resources by route; type determined by endpoint (/accidents vs /safeguarding) BFF adds type field when aggregating
incident_number "INC-2024-001" referenceNumber field: "ACC-2026-00001" (typed prefix format) Field rename + prefix format changes
severity "High", "Medium", "Critical" (title-case) SeverityLevel enum: HIGH, MEDIUM, LOW, CRITICAL (UPPER_CASE) BFF normalizes to uppercase
status "Resolved", "Under_Review" (mixed case) LogStatus enum: IDENTIFIED, RAISED, IN_PROGRESS, RESOLVED etc. (UPPER_CASE) BFF normalizes case; Under_ReviewIN_PROGRESS
dateAndTime ISO string incidentDatetime (ISO 8601 with Z suffix) Field rename in BFF
actionsTaken Array on the incident object Separate endpoint: GET /logs/{logType}/{logId}/actions Actions must be fetched separately
has_investigation Boolean Not in incidents-service OpenAPI — derived from status BFF computes from status

Care Plans — GET /api/v1/care-plans

Field Mock Shape Real Service Shape (careplan-service OpenAPI) BFF Action
clientId "su-001" clientId (UUID) Same field name; ID format changes to UUID
status "active", "draft", "under_review" CarePlanStatus enum: draft, ai_generated, under_review, approved, active, suspended, completed, cancelled Values align but ai_generated is new — frontend must handle
Tasks nested tasks: [...] array on care plan Tasks NOT on care plan object in careplan-service spec; separate route /care-plan/{id}/tasks BFF may aggregate or frontend must call separately
Visit structure visits: [...] array CarePlanDetailsResponse has Visit[] with nested TaskCategory[] and CarePlanTask[] Nested structure differs significantly from mock flat array

Assessment — GET /api/v1/assessments/:id

Field Mock Shape Real Service Shape (assessment-service OpenAPI) BFF Action
id vs assessmentId Both id and assessmentId present (legacy dual fields) assessmentId only (UUID) Remove dual field; use assessmentId consistently
patientId UUID string patientId (UUID) — matches No change needed
completionStatus "IN_PROGRESS", "COMPLETED" completionStatus enum per spec Matches — no change
lastUpdated Concatenated date + literal T10:30:00Z suffix ISO 8601 datetime from service Remove hardcoded suffix hack
overview Nested object with riskLevel, allergies, etc. Not a direct response field — derived from assessment sections BFF must compose overview from section data

DA-4. Schema Validation (Post-Migration Audit Step)

Add as Phase 3.5, after all per-domain cutovers complete but before Phase 4 decommission.

Phase 3.5 — Schema Audit

Objective: Machine-verify that every active BFF response matches its OpenAPI contract. No visual inspection.

Step 1 — Generate JSON Schemas from OpenAPI specs:

# Using openapi-schema-validator or ajv-openapi
npx @apidevtools/swagger-parser validate \
  /Users/makinja/projects/client/lumiscare/openapi-specs/visits-open-api/open-api.yaml
# Repeat for each service spec

Step 2 — Record BFF responses against schema:

For each REAL_READY or newly NEEDS_WIRING domain, run automated contract tests:

# Install dredd or schemathesis
pip install schemathesis

# Run against BFF with real backend:
schemathesis run \
  /Users/makinja/projects/client/lumiscare/openapi-specs/visits-open-api/open-api.yaml \
  --base-url https://<web-bff-fqdn>.azurecontainerapps.io \
  --auth-type bearer --auth "$JWT_TOKEN" \
  --header "X-VCU-Organization-Id: $ORG_ID"

Step 3 — Adapter correction loop:

For each schema violation found:

  1. Identify if the mismatch is in the BFF adapter or the service response
  2. Fix the BFF adapter layer (preferred) or raise a service ticket
  3. Re-run schemathesis until zero schema violations remain

Step 4 — Acceptance criteria:

Pass criteria for Phase 4 entry: Schema audit exits with code 0 for all 10 domains.


DA-5. Rollback Test (Phase 2.4)

Add between Phase 2.3 (keep mock running) and Phase 3 (per-domain cutover).

Phase 2.4 — Validate Rollback Mechanism Works

Before committing to Phase 3 cutovers, prove the rollback path is functional. This is a one-time gate check.

2.4.1 Simulate a domain failure:

# Disable visits-service in BFF by setting a bad URL (or scale to 0)
az containerapp update \
  --name ca-vcc-dev-visits-service-001 \
  --resource-group rg-vcc-dev-001 \
  --min-replicas 0 --max-replicas 0

2.4.2 Verify BFF fallback activates automatically:

# Call a visits endpoint through BFF — should return mock data, not 502
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $JWT_TOKEN" \
  https://<web-bff-fqdn>.azurecontainerapps.io/api/v1/visits
# Expected: 200 (served from mock fallback)

2.4.3 Verify fallback data is recognizable (not silent corruption):

# Response should include mock data markers (e.g., "visit-0001" style IDs)
curl -s -H "Authorization: Bearer $JWT_TOKEN" \
  https://<web-bff-fqdn>.azurecontainerapps.io/api/v1/visits \
  | jq '.[0].id'
# Expected: "visit-0001" or similar mock ID pattern

2.4.4 Re-enable the service and confirm real data returns:

az containerapp update \
  --name ca-vcc-dev-visits-service-001 \
  --resource-group rg-vcc-dev-001 \
  --min-replicas 1 --max-replicas 3

# Wait for healthy status, then re-test
curl -s -H "Authorization: Bearer $JWT_TOKEN" \
  https://<web-bff-fqdn>.azurecontainerapps.io/api/v1/visits \
  | jq '.[0].id'
# Expected: UUID format (real service data)

2.4.5 Document rollback timings:

Rollback Type Expected Time Acceptable Max
BFF env var toggle (MOCK_API_FALLBACK_ENABLED=true) < 2 minutes 5 minutes
Per-domain BFF route disable (redeploy BFF) 3-5 minutes 10 minutes
Frontend env var change (Static Web App) < 5 minutes 15 minutes
Database restore from Azure backup 30-60 minutes 2 hours

Gate: Phase 2.4 must PASS before any Phase 3 cutover proceeds.


DA-6. Phase Timing and Environment Clarity

Which systems run on what at each migration phase, per environment.

Environment Matrix by Phase

Phase Dev Test Staging Production
Current (pre-migration) Frontend → Mock API direct Frontend → Mock API direct N/A N/A
Phase 0 (seed + prep) Mock API still direct; seeds loaded to Azure DBs No change No change No change
Phase 1 (BFF wiring) BFF development; Mock API still used by frontend Mock API still used No change No change
Phase 2 (frontend switch) Frontend → BFF (BFF → real service OR mock fallback) Frontend → BFF (all fallback) BFF deployed, fallback enabled for all routes Not deployed
Phase 3 (per-domain cutover) BFF → real services per-domain; fallback only for MOCK_ONLY BFF + per-domain fallback; real services tested here BFF + fallback per-domain; each domain promoted after test passes Not deployed
Phase 4 (decommission) BFF → real services; fallback disabled; mock stopped Mock stopped Mock stopped Deploy begins post-stability

Service URL Routing by Environment

Dev:     Frontend → https://<bff-dev>.azurecontainerapps.io → {service}-dev → identity_db_dev
Test:    Frontend → https://<bff-test>.azurecontainerapps.io → {service}-test → identity_db_test
Staging: Frontend → https://<bff-stage>.azurecontainerapps.io → {service}-stage → identity_db_stage
Prod:    Frontend → https://<bff-prod>.azurecontainerapps.io → {service}-prod → identity_db_prod

Fallback Configuration by Environment

Environment MOCK_API_FALLBACK_ENABLED MOCK_API_URL Notes
Dev true during Phase 1-3; false at Phase 4 http://mock-api-dev:3000 Toggle per domain using route-level flags
Test true until domain passes test suite; then false http://mock-api-test:3000 Automated test gate controls the toggle
Staging true for 48h stability window per domain; then false http://mock-api-stage:3000 See DA-9 Demo Protection
Production false from day one (start clean) N/A No mock in production ever

DA-7. Evidence Checklist per Domain (Cutover Gate)

For each domain in Phase 3, the following machine-verified criteria must ALL pass before disabling the mock fallback for that domain. Evidence artifacts must be saved.

Cutover Checklist Template

Replace {DOMAIN} with the domain name (e.g., assessment, visits).

[ ] 1. Seed data verified — verify-seeds.sh passes for {DOMAIN}_db
[ ] 2. Service health — GET /actuator/health returns {"status":"UP"} (HTTP 200)
[ ] 3. BFF route active — GET /api/v1/{domain-path} returns HTTP 200 (not 502 or fallback)
[ ] 4. Auth propagation — JWT + org header accepted; 401 returned without token
[ ] 5. Data shape — schemathesis or equivalent schema check passes (zero violations)
[ ] 6. CRUD smoke — POST creates, GET retrieves, PATCH updates, DELETE removes (where applicable)
[ ] 7. Pagination — List endpoint returns paginated wrapper, not raw array
[ ] 8. Tenant isolation — org-A data not visible when calling with org-B token
[ ] 9. Error format — 404 returns standardized error schema, not mock `{ error: "Not found" }`
[ ] 10. Fallback disabled — MOCK_API_FALLBACK_ENABLED=false for this domain; mock NOT serving requests
[ ] 11. Playwright smoke tests — existing frontend test suite passes against BFF (no regressions)
[ ] 12. Rollback verified — fallback re-enable tested and confirmed working (DA-5 gate)

Evidence artifacts per domain:

Artifact Format Location
verify-seeds output .txt log /docs/migration-evidence/{domain}-seed-verify.txt
schemathesis report JSON or HTML /docs/migration-evidence/{domain}-schema-report.json
Playwright test report JUnit XML or HTML CI artifact
Cutover timestamp ISO 8601 string /docs/migration-evidence/{domain}-cutover.json

Domain cutover sign-off: All 12 checks must show machine-generated PASS. No self-certification. DevOps engineer reviews artifact paths before toggling MOCK_API_FALLBACK_ENABLED=false.

Domain Priority and Cutover Order

Priority Domain Blocker For Estimated Cutover Date (relative)
1 Identity All others — auth depends on it Week 1 Day 1
2 Assessment Care Plans, clinical workflow Week 1 Day 3
3 Care Plans Visits task planning Week 1 Day 5
4 Visits Mobile carers, eMAR Week 2 Day 1
5 Incidents Safeguarding compliance Week 2 Day 2
6 HR Staff compliance reporting Week 2 Day 3
7 Scheduling Calendar view, rostering Week 2 Day 4
8 Notifications Non-blocking but improves UX Week 2 Day 5
9 Finance Invoicing, billing Week 3 Day 1
10 Family Portal MOCK_ONLY — stays on mock Post-MVP

DA-8. Family Portal Architecture Decision Record (ADR-001)

Date: 2026-03-26 Status: ACCEPTED Deciders: Engineering Lead, Product Owner

Context

The Family Portal frontend (GET /api/v1/family/*) has 16 mock endpoints. There is no dedicated FamilyPortalService in the current microservice architecture. The endpoints aggregate data from:

No FamilyPortalController exists in the Web BFF. Building a full family portal BFF layer during the mock-to-real migration would be a parallel new-feature build, not a migration task.

Decision

Family Portal routes are SCOPED OUT of the mock-to-real MVP migration.

The 16 family portal mock endpoints will remain served by the mock API fallback indefinitely until a dedicated post-MVP sprint is resourced.

Rationale

  1. Zero real service coverage — building from scratch, not migrating
  2. Requires new BFF controller + aggregation logic across 3+ services
  3. Family Portal is a secondary product — primary migration priority is Back Office and Mobile
  4. The mock API fallback handles family portal routes with zero user impact during migration

Post-MVP Implementation Plan

Phase Work Timeline
FP-1 Define FamilyPortalController in Web BFF; aggregate careplan + identity endpoints Sprint after MVP cutover
FP-2 Wire notification-service for family inbox + message threads FP-1 + 1 sprint
FP-3 Payment initiation (Stripe/payment gateway) — separate investigation TBD
FP-4 Family Portal authentication (separate Entra B2C tenant for non-staff) TBD — security review required

Consequences

Mock Fallback Route Config

# application.yml — BFF fallback config
mock-api:
  fallback-routes:
    - /api/v1/family/**   # permanent until FP-1 sprint

DA-9. Demo Protection Protocol

Context

During Phase 3 cutovers, demo sessions may be running against staging or dev environments. A failed real service during a demo is unacceptable. This protocol defines demo-critical routes and a DEMO_MODE fallback concept.

Demo-Critical Routes

Routes that, if broken, will visibly fail a standard stakeholder demo:

Route Why Critical
GET /api/v1/dashboard/stats First screen shown in every demo
GET /api/v1/service-users Client list — primary navigation
GET /api/v1/visits Visit calendar — core value demo
GET /api/v1/care-plans Care plan list — clinical workflow demo
GET /api/v1/assessments Assessment list — intake workflow demo
GET /api/v1/notifications/inbox Notification bell — real-time demo
GET /api/v1/incidents Incident log — compliance demo
GET /api/v1/family/* Family portal views — stakeholder demo

DEMO_MODE Flag

Add a DEMO_MODE environment variable to the BFF:

# application.yml
demo:
  mode: ${DEMO_MODE:false}
  protected-routes:
    - /api/v1/dashboard/stats
    - /api/v1/service-users
    - /api/v1/visits
    - /api/v1/care-plans
    - /api/v1/assessments
    - /api/v1/notifications/inbox
    - /api/v1/incidents
    - /api/v1/family/**

When DEMO_MODE=true:

When DEMO_MODE=false (default):

Stability Window Protocol

For each demo-critical domain, the fallback is not disabled until 48 consecutive hours of stability in the target environment:

48h stability check:
[ ] Zero 5xx errors from real service in Azure Monitor
[ ] P95 latency < 500ms for the domain's endpoints
[ ] Zero fallback activations recorded in BFF logs
[ ] At least 1 full demo walkthrough completed successfully against real backend

Only after all 4 checks pass → disable mock fallback for this domain

Pre-Demo Checklist

Before any stakeholder demo during Phase 3:

# 1. Enable DEMO_MODE in dev/staging BFF
az containerapp update \
  --name ca-vcc-dev-web-bff-001 \
  --resource-group rg-vcc-dev-001 \
  --set-env-vars DEMO_MODE=true

# 2. Verify mock fallback is serving demo-critical routes
curl -s -H "Authorization: Bearer $DEMO_JWT" \
  https://<bff-fqdn>/api/v1/dashboard/stats \
  | jq '.totalClients'
# Expected: non-null value from mock data

# 3. After demo — reset to real-service mode
az containerapp update \
  --name ca-vcc-dev-web-bff-001 \
  --resource-group rg-vcc-dev-001 \
  --set-env-vars DEMO_MODE=false

Mock Data Preservation

The mock API's seed data (server.js in-memory arrays) must not be modified or reset during active demo periods. Tag a stable demo snapshot:

# Before Phase 3 begins, create a demo-data tag in git
cd /Users/makinja/projects/client/lumiscare/mock-api
git tag demo-data-snapshot-$(date +%Y%m%d)

If mock data gets corrupted, restore from this tag and restart the mock API container.

LumisCare Demo P0-Batch Closure — MC #102844

LumisCare Demo P0-Batch Closure — MC #102844

Date: 2026-06-03 Status: DONE — 9/9 P0 demo defects fixed, deployed, live-verified.

Scope

Frontend: GlobalSearch service-users endpoint, Assessments/Notifications/CQC spinner-stuck error handling, Snowit branding removal. Backend: visits 500, scheduling 500, incidents/assessments/training-matrix 404 routes, intake/careplan detail 500, careplan UUID seed.

Deploy

Validation (Proveo retest 2026-06-03T07:08Z — 9/9 PASS)

Proveo Retest Report — MC #102844

Date: 2026-06-03T07:08:57.476Z Bundle: index-BBJqymqC.js | BFF: rev 0000036 | Visits: rev 0000010

Summary: 9/9 fixed

ID Name Verdict Screenshot Note
R01 Global search → service-users endpoint PASS R01-search-typed.png searchInput visible: true, result text found: true, service-users called: true, /clients called: false, /clients 404: fa
R02 /assessments page renders PASS R02-assessments.png noSpinner: true, hasSpinner: false, hasContent: true, isLogin: false, url: https://app.lumiscare.com/assessments
R03 /notifications page renders PASS R03-notifications.png noSpinner: true, hasSpinner: false, hasContent: true, isLogin: false
R04 /cqc-readiness page renders PASS R04-cqc-readiness.png noSpinner: true, hasSpinner: false, hasContent: true, is404: false, url: https://app.lumiscare.com/cqc-readiness
R05 Login page footer — no Snowit/v2.0 branding PASS R05-login-footer.png hasSnowit: false, hasV2Footer: false. Bundle scan: 0 hits for 'Powered by Snowit'. v2.0 strings in bundle are MSAL OAuth
R06 /visits page renders (visits-service 200) PASS R06-visits.png noSpinner: true, has500: false, has200: false, hasVisitContent: true, calls: []
R07 Scheduling page renders PASS R07-scheduling.png landed: false, noSpinner: true, has500: false, has200: false, hasSchedContent: true, url: https://app.lumiscare.com/back
R08 Incidents list renders (GET incidents 200) PASS R08-incidents.png landed: false, noSpinner: true, has404: false, has200: false, hasIncidentContent: true, url: https://app.lumiscare.com/b
R09 Care plan detail — no 500/white-screen PASS R09-careplan-detail.png hasList: true, clickedDetail: true, has500: false, isWhiteScreen: false, hasDetailContent: true, url: https://app.lumisc

Failed Items

Evidence

P2P verifier

Company Mesh thread mesh-thr-bc26724d-4348-4bd9-ac5d-fb707942e536 → PASS.

Evidence

Backlog (not in this batch)

P1/P2 empty seeded data, family-portal app, finance dashboard zeros, careplan-service detail seed, intake/assessment-service deeper wiring; source-hygiene merge branch fix/demo-be-p0-102844; security debt MC #102747.