Patient Portal
Patient-facing dashboard for prescriptions, shipments, messaging, and telehealth.
Overview
The Patient Portal is an Express 5 BFF (Backend for Frontend) serving a React SPA at
patient.hisera.com. It runs on ECS behind the ALB at priority 5 and provides
patients with a self-service dashboard for managing their prescriptions, tracking shipments,
messaging their care team, and scheduling telehealth appointments.
The BFF layer handles authentication, session management, and proxies requests to both Canvas FHIR and the Integration Service, ensuring patients only see their own data.
Architecture
┌──────────────────────────────────────────┐
│ patient.hisera.com (ECS via ALB) │
│ Express 5 BFF + Vite React SPA │
└───────────┬──────────────┬───────────────┘
│ │
Canvas FHIR API Integration Service
│ │
├─ Patients ├─ Shipments
├─ MedicationReq ├─ Notifications
├─ Communications ├─ FedEx Tracking
└─ Appointments └─ Scheduling
Infrastructure
| Component | Value |
|---|---|
| Host | patient.hisera.com |
| ALB Priority | 5 (highest priority rule) |
| Target Group | hisera-tg-patient-portal |
| Runtime | ECS Fargate |
Authentication
The Patient Portal supports two authentication methods. Both result in a JWT session cookie with a 4-hour expiry.
Email OTP
Patients enter their email address and receive a verification code via SendGrid. The code is validated server-side and a JWT session cookie is set.
Sends a verification code to the patient's email address via SendGrid.
Validates the verification code and sets a JWT session cookie (4h expiry).
Canvas OAuth SSO
Patients who access the portal from a Canvas magic link are authenticated via Canvas OAuth. The BFF exchanges the authorization code for a Canvas access token, looks up the patient, and issues a JWT session cookie.
yourera.canvasmedical.com sends magic link emails
via the SendInviteEffect plugin. The magic link redirects to the patient portal
with an OAuth authorization code.
Dashboard
The dashboard is the patient's landing page after authentication. It displays a personalized greeting and a summary of their active treatment.
Dashboard Components
- Greeting — Personalized with the patient's first name from Canvas FHIR
- Active Subscriptions — Current medication, dosage, and next refill date
- Shipment Tracker — Most recent shipment status with tracking link
- Telehealth Status — Upcoming appointment or option to schedule
- Notifications — Unread notification count badge
Prescriptions
The Prescriptions page displays the patient's medication history from Canvas FHIR
MedicationRequest resources. Each prescription shows the medication name,
dosage, prescriber, status, and date written.
Returns the authenticated patient's prescriptions from Canvas FHIR MedicationRequest.
Prescription Fields
| Field | Source | Description |
|---|---|---|
medication |
MedicationRequest.medicationCodeableConcept | Medication name and code |
dosage |
MedicationRequest.dosageInstruction | Dosage and frequency instructions |
prescriber |
MedicationRequest.requester | Prescribing practitioner name and NPI |
status |
MedicationRequest.status | active, completed, cancelled, stopped |
dateWritten |
MedicationRequest.authoredOn | Date the prescription was written |
Shipments
The Shipments page shows all shipments for the patient, sourced from the Integration Service database. Each shipment includes real-time FedEx tracking data with a Leaflet map visualization.
Tracking Map
When a shipment has an active tracking number, the portal displays a Leaflet map (using CARTO Voyager tiles) with a pulsing location dot showing the package's last known location. The map is code-split into a ~47KB chunk and only loaded when needed.
Returns all shipments for the authenticated patient from the integration service database.
Proxies FedEx tracking data with ownership verification and geocoding. Results are cached for 30 minutes in the tracking_cache table.
Shipment Status Flow
label_created → packed → shipped → delivered
↘
voided
/api/patient/tracking/:trackingNumber endpoint verifies that the tracking
number belongs to the authenticated patient before returning data. This prevents patients
from viewing other patients' shipment details.
Messages
The Messages page provides a secure messaging interface between the patient and their
assigned care team. Messages are stored as Canvas FHIR Communication resources
and auto-polled every 15 seconds for new messages.
Features
- Auto-Polling — New messages checked every 15 seconds
- Practitioner Routing — Messages are sent to the patient's assigned practitioner
- Read Receipts — Messages are marked as read when viewed
- Thread View — Conversation-style chronological message display
Returns Canvas FHIR Communication resources for the authenticated patient.
Sends a new message to the patient's assigned practitioner via Canvas FHIR Communication.
Scheduling
The Scheduling page allows patients to book, reschedule, and cancel telehealth appointments. The availability engine checks practitioner schedules and the Zoom integration creates meeting links automatically.
Booking Flow
- Patient selects a date from the availability calendar
- Available time slots are displayed based on practitioner schedules
- Patient selects a time slot and confirms the appointment
- A Zoom meeting is created automatically via the Zoom API
- Confirmation is sent to the patient via email and in-app notification
Returns available time slots for the given date from the availability engine.
Books a telehealth appointment. Creates a Zoom meeting and sends confirmation notifications.
Returns the patient's upcoming and past appointments with Zoom meeting links.
Notifications
The notification system provides persistent, database-backed notifications delivered via the Integration Service. Notifications are displayed as an in-app feed with an unread count badge on the dashboard.
Notification Types
- Shipment Shipped — Triggered when shipment status transitions to "shipped"
- Shipment Delivered — Triggered when FedEx confirms delivery
- Prescription Approved — Triggered after orchestrator approval pipeline
- Appointment Reminder — Sent 24 hours before a telehealth appointment
- New Message — Triggered when the care team sends a message
- Refill Upcoming — Sent 7 days before a scheduled refill
Returns persistent notifications for the authenticated patient, ordered by creation date descending.
Marks a notification as read.
API Endpoints
All /api/patient/* endpoints require a valid JWT session cookie.
The BFF enforces patient-scoped access — patients can only view their own data.
Authentication
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/patient/auth/send-code |
Send verification code via SendGrid |
| POST | /api/patient/auth/verify |
Verify code and set JWT session cookie |
| GET | /api/patient/auth/canvas-callback |
Canvas OAuth callback handler |
| POST | /api/patient/auth/logout |
Clear session cookie |
Patient Data
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/patient/profile |
Patient profile from Canvas FHIR |
| GET | /api/patient/prescriptions |
Prescription list from Canvas MedicationRequest |
| GET | /api/patient/shipments |
Shipment history from integration DB |
| GET | /api/patient/tracking/:trackingNumber |
FedEx tracking with ownership check |
| GET | /api/patient/messages |
Messages from Canvas FHIR Communications |
| POST | /api/patient/messages |
Send message to practitioner |
| GET | /api/patient/notifications |
Notification feed |
| POST | /api/patient/notifications/:id/read |
Mark notification as read |
| GET | /api/patient/availability |
Available appointment time slots |
| POST | /api/patient/appointments |
Book telehealth appointment |
| GET | /api/patient/appointments |
Appointment list with Zoom links |