Skip to main content

Virtual Care Service — User Stories

Service: virtual-care-service Story prefix: VCARE-US Last updated: 2026-04-18

Stories

VCARE-US-001 — Create a virtual care session

FieldValue
Issue typeStory
SummaryCreate virtual session with Jitsi room provisioning; enforce consent + license
Epic linkVCARE-EPIC-01
StatusTo Do
PriorityMust
Story points8
Labelsservice:virtual-care, type:backend, type:api, slice:S1
Componentssession-lifecycle, jitsi-adapter
FR referencesFR-VCARE-001
Legacy FR refsFR-VC-001, FR-VC-008, FR-VC-011 (TELEMED-VC)
DependenciesVCARE-US-005 (consent gate must exist first)

User story: As a clinician, when I create a virtual care session for a patient, I want the system to provision a Jitsi Meet room and return session details so that the patient and I can join at the scheduled time.

Acceptance criteria (Gherkin):

  • Given the tenant has virtual care licensed and the patient has telehealth consent on file, when I POST /api/v1/virtual-care/sessions with valid patientId and scheduledStart, then I receive 201 with a VirtualSessionDto containing roomUrl, roomName, status: scheduled, and version: 1.
  • Given the Jitsi health check returns 503, when I attempt to create a session, then I receive 503 VIDEO_PROVIDER_UNAVAILABLE and no session row is created in the database.
  • Given the patient does not have telehealth consent on file, when I attempt to create a session, then I receive 403 CONSENT_REQUIRED and no session row is created.
  • Given a successfully created session, when POST /api/v1/virtual-care/sessions is called, then virtual_care.session.created.v1 is published to NATS.

Technical notes:

  • CreateVirtualSessionUseCase must call VideoProviderHealthPort before VideoProviderPort.createRoom().
  • Session row created only after createRoom() succeeds.
  • Optimistic lock: version = 1 on creation.

Definition of Done:

  • Unit + integration tests added; coverage ≥ thresholds.
  • OpenAPI contract updated; Pact consumer tests green.
  • Event schema registered; schema conformance test green.
  • Telemetry spans/metrics added.
  • Documentation updated in relevant 17 docs.

VCARE-US-002 — Join session and enter waiting room

FieldValue
Issue typeStory
SummaryPatient joins via HMAC join token; enters waiting room state
Epic linkVCARE-EPIC-01
StatusTo Do
PriorityMust
Story points5
Labelsservice:virtual-care, type:backend, type:api, slice:S1
Componentswaiting-room, join-token
FR referencesFR-VCARE-002
Legacy FR refsFR-VC-002 (TELEMED-VC)
DependenciesVCARE-US-001

User story: As a patient, when I click the join link from my appointment notification, I want to enter the waiting room so that the provider can admit me when ready.

Acceptance criteria (Gherkin):

  • Given a valid, non-expired join token, when I call GET /api/v1/virtual-care/sessions/join?token=<token>, then I receive { destination: "waiting_room", url: "...", sessionStatus: "scheduled" }.
  • Given an expired join token, when I call the join endpoint, then I receive 401 TOKEN_EXPIRED.
  • Given a join token for a cancelled session, when I call the join endpoint, then I receive 409 INVALID_STATUS_TRANSITION.
  • Given a patient successfully validates their token, when they enter the waiting room, then virtual_care.session.participant.joined.v1 is published with role: patient and participantStatus: waiting.

Technical notes:

  • Join endpoint configured in Kong to bypass JWT auth; uses HMAC token only.
  • JoinTokenSignerPort validates HMAC signature + expiry + participantId claim.

Definition of Done: Standard DoD applies.


VCARE-US-003 — Admit patient from waiting room

FieldValue
Issue typeStory
SummaryProvider admits patient from waiting room; session transitions to active
Epic linkVCARE-EPIC-01
StatusTo Do
PriorityMust
Story points3
Labelsservice:virtual-care, type:backend, slice:S1
Componentswaiting-room
FR referencesFR-VCARE-003
Legacy FR refsFR-VC-003 (TELEMED-VC)
DependenciesVCARE-US-002

User story: As a clinician, when a patient is in the waiting room, I want to admit them to the active session so that the consultation can begin.

Acceptance criteria (Gherkin):

  • Given a patient in waiting status and a provider in the session, when I POST /api/v1/virtual-care/sessions/:id/admit/:participantId, then the patient's status transitions to admitted and I receive { videoJoinUrl: "..." }.
  • Given a participant NOT in waiting status, when I attempt to admit them, then I receive 409 PARTICIPANT_NOT_IN_WAITING_ROOM.
  • Given the admit succeeds and this is the first provider join, when the session transitions to active, then virtual_care.session.started.v1 is published.
  • Given virtual_care.session.participant.admitted.v1 is emitted, when audit-service receives it, then the event is logged with actorId, participantId, and timestamp.

Technical notes: AdmitParticipantUseCase applies FSM transition on the VirtualSession aggregate.

Definition of Done: Standard DoD applies.


VCARE-US-004 — End a session and trigger Encounter creation

FieldValue
Issue typeStory
SummaryEnd session; create FHIR Encounter; emit billing event
Epic linkVCARE-EPIC-01
StatusTo Do
PriorityMust
Story points5
Labelsservice:virtual-care, type:backend, slice:S1
Componentssession-lifecycle, fhir-integration, billing-events
FR referencesFR-VCARE-004
Legacy FR refsFR-VC-006, FR-VC-031 (TELEMED-VC)
Dependenciespatient-chart-service (FHIR Gateway), billing-service

User story: As a clinician, when I end a virtual care session, I want the system to automatically create a FHIR Encounter in the patient's chart and emit a billing event so that the visit is documented and can be claimed.

Acceptance criteria (Gherkin):

  • Given a session in active status, when I POST /api/v1/virtual-care/sessions/:id/end, then the session transitions to ended and encounterId is populated.
  • Given the session ends, when FHIR Gateway creates the Encounter, then the Encounter has class: VR, subject: Patient/{patientId}, and appointment: Appointment/{appointmentId}.
  • Given the session ends, when virtual_care.billing.session_chargeable.v1 is emitted, then durationSeconds, patientId, and encounterId are included.
  • Given FHIR Gateway is temporarily unavailable when session ends, when it recovers within 5 min, then the retry job creates the Encounter and updates encounterId on the session.
  • Given an already-ended session, when I call end again, then I receive 200 with the current session state (idempotent).

Technical notes:

  • EndSessionUseCase calls FHIR Gateway; on failure, session is still marked ended and retry job is enqueued.
  • Version optimistic lock checked on end.

Definition of Done: Standard DoD applies.


FieldValue
Issue typeStory
SummaryBlock session creation if patient telehealth consent not on file
Epic linkVCARE-EPIC-02
StatusTo Do
PriorityMust
Story points3
Labelsservice:virtual-care, type:backend, slice:S1
Componentsconsent-gate
FR referencesFR-VCARE-020
Legacy FR refsFR-VC-020 (TELEMED-VC)
Dependenciesaccess-policy service

User story: As a compliance officer, when a clinician attempts to create a virtual care session for a patient without telehealth consent, I want the system to block the session and record an audit event so that the platform never initiates telehealth without documented patient consent.

Acceptance criteria (Gherkin):

  • Given the patient has no telehealth consent record, when POST /api/v1/virtual-care/sessions is called, then I receive 403 CONSENT_REQUIRED and a CONSENT_GATE_BLOCKED audit event is emitted.
  • Given the consent service is unreachable (503), when POST /api/v1/virtual-care/sessions is called, then the session is blocked (fail-closed) with 503 CONSENT_SERVICE_UNAVAILABLE.
  • Given the patient has valid telehealth consent, when session creation proceeds, then no consent-related error is returned.

Technical notes:

  • ConsentCheckPort → access-policy service; fail-closed on network error.
  • Consent audit event logged regardless of source of block.

Definition of Done: Standard DoD applies.


FieldValue
Issue typeStory
SummaryRecording consent required separately before enabling session recording
Epic linkVCARE-EPIC-02
StatusTo Do
PriorityMust
Story points3
Labelsservice:virtual-care, type:backend, slice:S1
Componentsconsent-gate, recording
FR referencesFR-VCARE-022
Legacy FR refsFR-VC-022, FR-VC-028 (TELEMED-VC)
DependenciesVCARE-US-005

User story: As a patient, when a provider tries to record my session, I want the system to verify that I have specifically consented to recording (separate from general telehealth consent) so that my privacy is respected.

Acceptance criteria (Gherkin):

  • Given a session creation request with recordingEnabled: true and no recording consent on file, when the request is processed, then 403 CONSENT_REQUIRED is returned with gate: recording_consent.
  • Given recording consent IS on file and recordingEnabled: true is requested, when the session is created, then recordingEnabled: true is set on the session row.
  • Given a session ends with recording, when virtual_care.session.ended.v1 is emitted, then recordingRef is included if Jibri recording was completed.

Definition of Done: Standard DoD applies.


VCARE-US-007 — Jitsi Meet room provisioning and health check

FieldValue
Issue typeStory
SummaryJitsi adapter: room creation, JWT auth, health check before session create
Epic linkVCARE-EPIC-03
StatusTo Do
PriorityMust
Story points8
Labelsservice:virtual-care, type:backend, slice:S1
Componentsjitsi-adapter
FR referencesFR-VCARE-030
Legacy FR refsFR-VC-008, FR-VC-011, FR-VC-035–036 (TELEMED-VC)
DependenciesJitsi Meet self-hosted deployment

User story: As a platform engineer, when virtual care sessions are created, I want Jitsi Meet rooms provisioned automatically with tenant-branded configuration and JWT authentication so that providers and patients join a fully configured video environment.

Acceptance criteria (Gherkin):

  • Given Jitsi is healthy, when CreateRoom is called with tenant branding config, then a room with tenant roomSlugPrefix, brandingLogoUrl, and brandingPrimaryColor is created.
  • Given Jitsi returns 503, when the health check fails, then CreateVirtualSessionUseCase does not persist a session row and returns 503.
  • Given a session is created, when a join token is issued, then the token is a valid HS256 JWT signed with the tenant's Jitsi secret from KMS.

Technical notes:

  • jitsiJwtSecret is retrieved from KMS; never stored in DB.
  • Room slug: {roomSlugPrefix}-{random-8-chars}.
  • Tenant branding fields validated (HTTPS only, CSS hex color) before use in Meet config.

Definition of Done: Standard DoD applies.


VCARE-US-008 — Bandwidth fallback: video → audio → async messaging

FieldValue
Issue typeStory
SummaryAutomatic degradation from video to async messaging on persistent connectivity loss
Epic linkVCARE-EPIC-03
StatusTo Do
PriorityMust
Story points5
Labelsservice:virtual-care, type:backend, slice:S1
Componentsbandwidth-fallback
FR referencesFR-VCARE-032 – FR-VCARE-034
Legacy FR refsFR-VC-023–024 (TELEMED-VC)
Dependenciescommunication-service (messaging thread), VCARE-US-004

User story: As a clinician in Afghanistan, when the patient's video connection drops and cannot be restored within the grace period, I want the system to automatically offer an async messaging fallback so that the consultation can continue.

Acceptance criteria (Gherkin):

  • Given a session in failed status (grace reconnect expired), when I POST /api/v1/virtual-care/sessions/:id/fallback-message, then a messaging thread is created in communication-service and { messagingThreadId: "..." } is returned.
  • Given the fallback is initiated, when virtual_care.session.fallback.initiated.v1 is emitted, then communication-service subscribes and creates the thread linked to the session.
  • Given a session NOT in failed or active status, when fallback is requested, then 409 INVALID_STATUS_TRANSITION is returned.

Technical notes:

  • Grace reconnect window is tenant-configurable (default 60s via sessionGraceMinutesAfter).
  • Fallback threshold detection may be implemented at client or backend signaling layer; this story covers the server-side fallback API.

Definition of Done: Standard DoD applies.


VCARE-US-009 — FHIR Encounter and billing event on session end

FieldValue
Issue typeStory
SummaryFHIR Encounter class=VR created on session end; billing event emitted
Epic linkVCARE-EPIC-04
StatusTo Do
PriorityMust
Story points5
Labelsservice:virtual-care, type:backend, slice:S1
Componentsfhir-integration, billing-events
FR referencesFR-VCARE-040
Legacy FR refsFR-VC-031 (TELEMED-VC)
Dependenciespatient-chart-service (FHIR Gateway), billing-service

User story: As a health records administrator, when a telehealth session ends, I want a FHIR R4 Encounter resource automatically created in the patient's chart so that the virtual visit is documented in the EHR without manual entry.

Acceptance criteria (Gherkin):

  • Given a session ends with durationSeconds > 0, when FHIR Gateway responds 201, then encounterId is stored on the session row.
  • Given FHIR Gateway is down at session end, when the retry job runs within 5 min, then Encounter is created and encounterId updated.
  • Given Encounter is created, when virtual_care.billing.session_chargeable.v1 is emitted, then billing-service receives encounterId, patientId, durationSeconds.

Technical notes: EndSessionUseCaseFhirGatewayPort.createEncounter()POST /fhir/Encounter.

Definition of Done: Standard DoD applies.


VCARE-US-010 — Tenant virtual-care configuration management

FieldValue
Issue typeStory
SummaryAdmin configures video backend, Jitsi branding, recording policy, participant limits
Epic linkVCARE-EPIC-05
StatusTo Do
PriorityMust
Story points3
Labelsservice:virtual-care, type:api, type:backend, slice:S1
Componentstenant-config
FR referencesFR-VCARE-050 – FR-VCARE-054
Legacy FR refsFR-VC-018–019, FR-VC-035–036 (TELEMED-VC)
DependenciesKMS

User story: As a tenant administrator, when I configure virtual care for my facility, I want to set the Jitsi server URL, branding, recording policy, and participant limits so that sessions reflect our organization's identity and policies.

Acceptance criteria (Gherkin):

  • Given tenant_admin role, when I PUT /api/v1/virtual-care/config with jitsiServerUrl, brandingLogoUrl, and maxParticipants, then the config is saved and virtual_care.config.updated.v1 is emitted with only changedFields (no credentials).
  • Given I GET /api/v1/virtual-care/config, when the response is returned, then jitsiJwtSecret, zoomApiKey, and any other credential fields are returned as "****".
  • Given I POST /api/v1/virtual-care/config/test-connection, when Jitsi responds healthy, then { healthy: true, latencyMs: N } is returned.

Technical notes: Credentials stored via SecretStorePort → KMS. Config field changedFields computed as diff between old and new config.

Definition of Done: Standard DoD applies.


VCARE-US-011 — AI speech-to-text transcription during session

FieldValue
Issue typeStory
SummaryClinician initiates STT transcription; transcript shown in review panel
Epic linkVCARE-EPIC-06
StatusTo Do
PriorityShould
Story points8
Labelsservice:virtual-care, type:backend, slice:S2
Componentsai-integration
FR referencesFR-VCARE-060
Legacy FR refsFR-VC-029 (TELEMED-VC)
Dependenciesai-gateway-service

User story: As a clinician, during an active session, I want to activate speech-to-text transcription so that I have a running transcript I can review before accepting it into the patient chart.

Acceptance criteria (Gherkin):

  • Given an active session and clinician role, when I POST /api/v1/virtual-care/sessions/:id/ai/transcribe with an audio chunk, then a transcript is returned and is NOT automatically added to the chart.
  • Given ai-gateway is unreachable, when the STT request is made, then I receive a user-friendly error and the session continues normally.
  • Given the STT returns a transcript, when it is displayed, then no PHI appears in service logs.

Technical notes:

  • Audio content never persisted in virtual-care-service DB.
  • PHI (transcript content) must not appear in logs; log only metadata.

Definition of Done: Standard DoD applies.


VCARE-US-012 — AI visit summary draft with mandatory HITL acceptance

FieldValue
Issue typeStory
SummaryGenerate visit summary draft; clinician must explicitly accept before chart entry
Epic linkVCARE-EPIC-06
StatusTo Do
PriorityShould
Story points5
Labelsservice:virtual-care, type:backend, slice:S2
Componentsai-integration, clinical-documentation
FR referencesFR-VCARE-061 – FR-VCARE-062
Legacy FR refsFR-VC-029–030 (TELEMED-VC)
Dependenciesai-gateway-service, patient-chart-service

User story: As a clinician, after the session transcript is available, I want to generate a visit summary draft and review it before deciding to add it to the patient's chart so that I maintain full control over documented clinical content.

Acceptance criteria (Gherkin):

  • Given a session transcript is available, when summary generation is triggered, then a draft is returned to the clinician in the review panel (not yet in the chart).
  • Given the clinician reviews and accepts the summary, when POST /api/v1/virtual-care/sessions/:id/ai/accept-summary is called with accepted: true, then the summary is pushed to patient-chart-service with AI provenance metadata.
  • Given the clinician declines the summary, when accepted: false is submitted, then no content is written to the chart.
  • Given a refused AI completion from ai-gateway, when the summary endpoint is called, then the clinician is notified and can document manually.

Technical notes:

  • No auto-push path exists; AcceptAiSummaryUseCase is the only path to chart.
  • AI provenance: aiGenerated: true, aiModel, aiAcceptedBy, aiAcceptedAt written to note metadata.

Definition of Done: Standard DoD applies.


VCARE-US-013 — Async store-and-forward visit (offline support)

FieldValue
Issue typeStory
SummaryPatient submits async visit content offline; provider reviews and responds
Epic linkVCARE-EPIC-07
StatusTo Do
PriorityShould
Story points8
Labelsservice:virtual-care, type:backend, type:api, slice:S2
Componentsasync-visits, offline-support
FR referencesFR-VCARE-070 – FR-VCARE-072
Legacy FR refs— (synthesized)
Dependenciescommunication-service, patient-chart-service

User story: As a patient in a remote area with limited connectivity, when I cannot join a live video session, I want to submit my chief complaint and photos offline and have my provider review and respond asynchronously so that I still receive care.

Acceptance criteria (Gherkin):

  • Given an async visit drafted offline, when I POST /api/v1/virtual-care/async-visits with a clientMutationId, then the visit is created and virtual_care.async_visit.submitted.v1 is emitted.
  • Given the same clientMutationId is submitted twice (offline retry), when the second request arrives, then the server returns 200 with the original AsyncVisitDto (idempotent; no duplicate created).
  • Given a provider responds to the async visit, when the response is saved, then a FHIR Encounter is created in patient-chart-service and the visit transitions to responded.

Technical notes:

  • clientMutationId: stable UUID set at draft creation time; carried through offline queue to server.
  • UNIQUE (tenant_id, client_mutation_id) DB constraint enforces idempotency.

Definition of Done: Standard DoD applies.