Skip to main content

Virtual Care Service — Application Logic

Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · 03 platform-services · 02 DDD

1. Commands (Write Use Cases)

CommandHandlerDescription
CreateVirtualSessionCommandCreateVirtualSessionUseCaseValidate consent + license; provision Jitsi room; persist session row
EndSessionCommandEndSessionUseCaseFSM end; trigger Encounter creation; emit billing event
CancelSessionCommandCancelSessionUseCaseFSM cancel with reason; notify participants
AdmitParticipantCommandAdmitParticipantUseCaseMove participant from waiting → admitted; generate video join URL
RemoveParticipantCommandRemoveParticipantUseCaseRemove participant from active session
InitiateFallbackCommandInitiateFallbackUseCaseTrigger async messaging fallback; emit fallback event
UpdateTenantConfigCommandUpdateTenantConfigUseCaseValidate + encrypt credentials; persist; emit config.updated
SubmitAsyncVisitCommandSubmitAsyncVisitUseCaseValidate offline content; persist; notify provider
AcceptAiSummaryCommandAcceptAiSummaryUseCaseHITL acceptance gate; push accepted summary to patient-chart-service

2. Queries (Read Use Cases)

QueryHandlerDescription
GetSessionListQueryGetSessionListUseCasePaginated list with status/patient/date filters
GetSessionDetailQueryGetSessionDetailUseCaseFull session with participants
GetJoinTokenQueryGetJoinTokenUseCaseIssue/refresh join token for participant
ValidateJoinTokenQueryValidateJoinTokenUseCaseToken-protected; returns destination (waiting_room or direct_join)
GetParticipantListQueryGetParticipantListUseCaseAll participants with status
GetTenantConfigQueryGetTenantConfigUseCaseConfig with credentials redacted

3. Ports (Interfaces)

PortTypeImplementation
VirtualSessionRepositoryRepositorypostgres-virtual-session.adapter.ts
SessionParticipantRepositoryRepositorypostgres-session-participant.adapter.ts
TenantConfigRepositoryRepositorypostgres-tenant-config.adapter.ts
VideoProviderPortOutboundjitsi-meet.adapter.ts (normative)
VideoProviderHealthPortOutboundjitsi-health-check.adapter.ts
FhirGatewayPortOutboundfhir-gateway.adapter.ts (Encounter creation)
EventPublisherPortOutboundnats-event-publisher.adapter.ts (outbox relay)
AuditPortOutboundnats-audit.adapter.ts
ConsentCheckPortOutboundconsent-check.adapter.ts
JoinTokenSignerPortOutboundhmac-join-token.adapter.ts
SecretStorePortOutboundkms-secret.adapter.ts (Jitsi JWT secrets)
AiGatewayPortOutboundai-gateway.adapter.ts (STT + summary)
OfflineQueuePortOutboundasync-visit-queue.adapter.ts

4. Orchestration Flows

4.1 Create Session Flow

4.2 Session End → Encounter Creation Flow

4.3 Bandwidth Fallback Flow

4.4 Appointment Auto-Create Flow (Event-driven)

5. Saga / Outbox Patterns

PatternWhere used
Outbox relayAll domain events via virtual_care_outbox table; relay after commit
Inbox deduplicationConsumed scheduling events deduped by CloudEvent id in virtual_care_inbox
Optimistic lockEvery session mutation checks version; conflict returns 409
FHIR Encounter sagaIf Encounter creation fails post-session-end, session row is marked ended but encounterId null; retry job reconciles within 5 min

6. Error Handling

ErrorHTTPCodeAction
Video backend unhealthy503VIDEO_PROVIDER_UNAVAILABLENo session row created; return diagnostic
Consent not on file403CONSENT_REQUIREDBlock creation; log attempt
Module not licensed403MODULE_NOT_LICENSEDReturn tenant licensing page hint
Invalid FSM transition409INVALID_STATUS_TRANSITIONReturn current status
Optimistic lock conflict409OPTIMISTIC_LOCK_CONFLICTReturn current version
Participant not in waiting room409PARTICIPANT_NOT_IN_WAITING_ROOMCannot admit
Join token expired401TOKEN_EXPIREDCaller must refresh token
Max participants exceeded422MAX_PARTICIPANTS_EXCEEDEDTenant config limit
Provider quota exceeded503PROVIDER_QUOTA_EXCEEDEDTry secondary backend if configured