Skip to content

Therapist-Patient Assignment

Overview

The therapist-patient assignment feature allows clinics to assign multiple therapists to a single patient. Previously, a patient was connected only to the therapist who invited them. With this feature enabled, any therapist in the clinic can be assigned to any patient — both at invite time and after onboarding.

The feature is gated by the therapistPatientAssignment feature flag (per-tenant). See docs/feature-flags.md for how flags work.

Assignment Flows

Flow 1: At Invite Time

When inviting a new patient via the "Invite New Patient" modal, the inviting therapist can optionally select additional therapists to assign:

  1. Therapist opens the invite modal and fills in patient details
  2. If the feature flag is enabled and the clinic has other therapists, an "Also assign to" section appears below the form fields
  3. For clinics with 5 or fewer other therapists, toggle-style pill buttons are shown inline
  4. For clinics with more than 5 therapists, a searchable multi-select dropdown is shown instead
  5. On submit, the backend creates the primary doctor-patient connection as usual, then creates additional connections for each selected therapist

The additional therapist IDs are sent as additionalTherapistIds in the invite payload. The backend validates each therapist (active, approved, same tenant, type DOCTOR) before creating the connection.

Flow 2: From the Dashboard (Post-Onboarding)

Therapists can manage assignments from two places on the dashboard:

All Active Patients Table

When viewing the "All Active Patients" tab (requires allActivePatientsDashboard flag), a "Therapists" column appears showing:

  • Avatar bubbles with therapist initials (current user highlighted in blue, others in gray)
  • A "+N" badge when there are multiple therapists
  • Quick-action buttons:
  • Assign to Me — appears if the current therapist is not yet connected to that patient
  • Add therapist — opens the assign modal to pick a different therapist

Since 2026-10-06 a search in the My Active Patients table also reaches the clinic's other therapists' patients (with allActivePatientsDashboard): matches outside the list appear under a Not your patients heading with the patient's therapists and Assign to Me (with therapistPatientAssignment), and matches among archived patients under Archived (opening one restores them, as in the archived view). In All Active Patients a search adds the Archived heading. The search takes the name in any word order, the email and phone digits. The app's directory search does the same under the same headings (see mobile-doctor-dashboard.md), and the add-patient form's existing-patient check offers Assign to Me for a colleague's patient on the web (see internal/patient-onboarding.md).

Patient Management Modal

When opening a patient's management modal, a "Therapist Management" section shows:

  • A list of all connected therapists (current user marked with "(You)")
  • Remove buttons beside therapists when more than one therapist is connected
  • Assign to Me button — if the current therapist is not connected
  • Add therapist button — opens the assign therapist modal

Mobile Patient Detail

On the mobile doctor patient detail screen, tenants with the feature enabled can manage the same care-team assignment from the patient's Care team section:

  • Current connected therapists are listed with (you) next to the viewer
  • Inline remove buttons appear when more than one therapist is connected
  • Assign to me appears when the viewer is browsing a patient outside their caseload
  • Add therapist opens a searchable mobile picker that excludes therapists already assigned to the patient

Assign Therapist Modal

A dedicated modal for assigning a patient to a specific therapist:

  1. Shows the patient name being assigned
  2. Searchable list of available therapists (excludes already-connected ones)
  3. Single-select a therapist, then confirm
  4. On success, the store updates optimistically (no page reload needed)

API Endpoints

Endpoint Method Purpose
/v2/doctor/patients/tenant-doctors GET Lists active, approved therapists in the tenant (excludes the caller). Requires therapistPatientAssignment flag.
/v2/doctor/patients/assign POST Assigns a patient to a target therapist. Body: { patientId, targetDoctorId? }. If targetDoctorId is omitted, assigns to the caller (self-assign). Validates the target doctor and patient belong to the same tenant. Reactivates archived connections if one exists.
/v2/doctor/patients/unassign POST Removes a therapist from a patient by soft-archiving the active connection. Body: { patientId, targetDoctorId? }. If targetDoctorId is omitted, removes the caller. The backend rejects removal of the last active therapist.

All assignment endpoints are guarded by the therapistPatientAssignment feature flag and return 403 if the flag is not enabled.

The existing getAllTenantPatients endpoint was also modified to return connectedTherapists (array of { id, firstName, lastName }) and isConnectedToMe (boolean) for each patient. The getPatientsSummary ("My Patients") endpoint conditionally includes the same fields when the therapistPatientAssignment flag is enabled for the tenant. Since 2026-10-06 every route under /v2/doctor requires the DOCTOR role (requireDoctor on each route of src/routes/doctor/index.ts), and so do the legacy GET /active-patients (the patient-search page's list) and GET /doctor/patients/:patientId/workouts; a patient account is refused with 403. Before, several of these (the patient summary, workout sessions, analysis, HEP management, AI settings, notes, plan creation and editing, assign and unassign, tenant doctors) checked only the patient-access helper, which in a clinic-wide tenant lets any signed-in caller through. Workout recordings (GET /doctor/recordings/:recordingId/url, GET /workout-recording/:workoutId, GET /workout-recordings/patient/:patientId) are for the recording's patient and for a therapist with access to that patient (a workout without a patient: its own therapist); anyone else gets 403 or 404. POST /workout-recording/upload-url follows the same rule and takes only an exercise of the given workout.

Frontend Components

Component Location Purpose
AssignTherapistModal components/doctor/dashboardV2/AssignTherapistModal.tsx Modal with searchable therapist list for single-select assignment
TherapistBubbles components/ui/TherapistBubbles.tsx Compact avatar bubbles showing assigned therapists with initials
TherapistMultiSelect components/ui/TherapistMultiSelect.tsx Searchable multi-select dropdown used during invite (>5 therapists)

Store Actions

The doctorDashboard Zustand store (lib/stores/doctorDashboard.ts) has two new actions:

  • fetchTenantDoctors() — calls GET /v2/doctor/patients/tenant-doctors and caches the result in tenantDoctors
  • assignPatientToDoctor(patientId, targetDoctorId?) — calls POST /v2/doctor/patients/assign and performs an optimistic update of connectedTherapists on the patient in both patients and allTenantPatients arrays
  • unassignTherapistFromPatient(patientId, targetDoctorId?) — calls POST /v2/doctor/patients/unassign and removes the therapist from cached connectedTherapists; self-removal also clears isConnectedToMe

Removal uses the same soft-archive fields as patient archiving. A patient must always retain at least one active therapist connection, so the server returns 400 if the request would remove the last therapist.

Types

TherapistInfo (lib/types/patient.ts):

interface TherapistInfo {
  id: number;
  firstName: string;
  lastName: string;
}

PatientSummaryV2 gained two optional fields:

  • connectedTherapists?: TherapistInfo[]
  • isConnectedToMe?: boolean

Key Files

File Role
OktaPT-API/src/routes/doctor/controller.ts getTenantDoctors, assignPatientToDoctor controllers; modified getAllTenantPatients
OktaPT-API/src/routes/doctor/index.ts Route definitions for new endpoints
OktaPT-API/src/routes/user/onboarding.controllers.ts Modified invitePatientWithMagicLink for additionalTherapistIds
OktaPT-FE/components/doctor/dashboardV2/AssignTherapistModal.tsx Assign therapist modal
Okta-Mobile/components/doctor/AssignTherapistModal.tsx Mobile assign therapist modal
OktaPT-FE/components/ui/TherapistBubbles.tsx Therapist avatar bubbles
OktaPT-FE/components/ui/TherapistMultiSelect.tsx Searchable multi-select
OktaPT-FE/components/InviteNewPatientModal.tsx Modified invite modal
OktaPT-FE/components/doctor/dashboardV2/PatientManagementModal.tsx Modified management modal
OktaPT-FE/components/doctor/dashboardV2/PatientManagementTable.tsx Modified patient table
OktaPT-FE/lib/stores/doctorDashboard.ts Store with fetchTenantDoctors, assignPatientToDoctor
OktaPT-FE/lib/types/patient.ts TherapistInfo type, extended PatientSummaryV2
OktaPT-FE/pages/doctor/dashboard.tsx Dashboard wiring for assign handlers
Okta-Mobile/app/(doctor)/patient/[id].tsx Mobile patient detail care-team assignment
Okta-Mobile/services/doctorPatientsService.ts Mobile patient assignment API wrapper