Patient Workout Completion, Resume & Quick-Finish¶
Overview¶
August 2026 rebuilt how patients finish workouts on both the web app and the mobile app around one goal: the fewest possible taps, with nothing lost if the patient walks away mid-session. The design bar was "a 90-year-old can get through it."
Three capabilities work together:
- A 2-tap exercise loop — arriving at an exercise means it has started (video playing, timer running). One tap finishes it, one tap on a single consolidated feedback screen moves to the next exercise, which is already running.
- Quick-finish ("Mark as finished") — every session card on the patient dashboard has a button for patients who did the workout outside the app. It opens one optional feedback screen (overall pain, effort, note, expandable per-exercise details) and marks the whole session complete.
- Server-backed resume — progress is saved to the server at every exercise boundary. Closing the app, refreshing the browser, or tapping ✕ is always safe; the dashboard card switches to "Resume · exercise N of M" and works across devices.
Completion is also automatic: the moment the congratulations screen appears, the session is persisted as complete in the background. The "Done" button only leaves the screen (or retries if the save failed) — a patient who never taps it still gets credit.
The in-session flow¶
Without recording (the common path)¶
- Patient taps Start workout on the dashboard card. If there is no circuit choice to make and no camera to offer, the setup screen is skipped entirely.
- The exercise is immediately active: looping demo video, running timer (time-based exercises also show the target, e.g.
0:12 / 0:30), and one big Finish exercise button. An optional "How does it feel?" control lets eager patients log pain/exertion mid-exercise; it pre-fills the feedback screen and never blocks anything. Under the dose, every screen that shows the exercise (setup, the active and video screens, the info sheet, the list) reads the rest of the prescription when the therapist gave it: "hold 5 s · rest 60 s · left side · tempo 3-1-3 · 200 m · as needed · every 2 h" (distance in metres for OKTA clinics, feet for OTERA). As needed and every N hours are labels; the exercise is still done and ticked off in the session like any other. - One feedback screen: sets completed (pre-selected to the planned count — a patient who did everything changes nothing), pain 0–10, exertion 0–10, and a collapsed "Add a note" row. The single Next exercise button records everything and drops straight into the next exercise, already running. On the last exercise it reads Finish workout.
Minimum taps per exercise: two.
Finishing feels like something¶
In the app, however the session is finished (the guided flow's summary, Mark as finished, or the logbook's Finish workout), the phone marks the moment: a short burst of confetti out of the check or the summary, over about a second, and a quick rhythm of taps (a firm tap, the success chime, two soft taps). It never blocks a tap and is silent to screen readers; with reduced motion on, only the taps play. In the logbook the finish sheet turns into a "Workout logged!" view for the burst and then returns to the dashboard on its own. The web app finishes sessions the same way it did before, without the burst.
With recording¶
The workout-level "record or not" choice is made once at setup. Each exercise then shows a single Start recording button (the camera should not auto-start while the patient is still positioning the phone), and Finish exercise stops the recording and finishes in one tap. Recordings queue for upload in the background; the congratulations screen tracks upload progress and holds "Done" until uploads settle.
Circuit mode¶
Circuit sequencing (one set per visit, rotating within a block) is unchanged. Intermediate visits are one tap — "Finish set" auto-advances with no feedback screen. Only the final visit to an exercise shows the feedback screen, without the sets question.
Quick-finish ("Mark as finished")¶
Available on every incomplete session card, regardless of scheduled date. Submitting:
- marks all not-yet-completed exercises as done at their planned values (exercises already completed in-app keep their real numbers),
- stores session-level pain/exertion/note on the workout itself, plus any per-exercise details the patient expanded,
- runs the full completion pipeline — streaks, RTM billing day, therapist feedback notification, and AI next-plan generation all fire exactly as if the guided flow was used,
- flags the workout as
quickCompletedso clinicians and analytics can distinguish it from a fully tracked session.
Because the app never observed the session, the start time is backdated by a conservative estimate (clamped to 5–60 minutes, derived from planned sets/reps/durations) so weekly streak minutes are credited sensibly instead of zero.
Everything on the quick-finish screen is optional — open it and tap Save & finish and the session is logged with no feedback at all.
Resume¶
At every exercise boundary the client sends a progress envelope to PATCH /v2/workouts/:id/progress:
- the step pointer (
currentStepIndex, step-indexed because circuit mode interleaves sets), the playback mode, completed sets so far, and whether the camera is on, - a
currentExerciseInWorkoutIdchecksum — if the therapist edits the plan mid-week, a stale pointer is detected and the session restarts fresh instead of resuming into the wrong exercise, - optionally, the just-finished exercise's actuals, duration, and feedback — so feedback reaches the server incrementally instead of one fragile batch at the very end.
The first progress write is also the authoritative "session started" signal (timeWorkoutStart), replacing the old page-load timestamp that inflated durations on bounce visits.
Writes are fire-and-forget with a retry queue: a network failure never blocks the patient. Queued writes retry at the next boundary; anything still undelivered when the session completes is drained through the batch feedback endpoint as a safety net. Both completion paths clear the envelope.
The dashboard (GET /v2/workouts/patient-upcoming) returns the envelope with each workout, so cards can render "Resume · exercise N of M" plus a "Start over" escape hatch that resets progress after confirmation.
Session-level feedback¶
Quick-finish (and any future session-level surface) stores pain/exertion/notes on the workout row rather than an exercise. The therapist feedback notification treats it with the same thresholds as exercise feedback (pain ≥ 7, exertion ≥ 9, or any note) and includes it in the chat summary — see Patient–Therapist Feedback.
The workout logbook¶
Clinics with the workoutLogbook flag replace the guided flow with one screen listing the whole session, logged set by set. It saves through the same progress endpoint with a third playback mode, LIST, its own completedExercise.loggedSets and a sessionFeedback object, and completes through the same POST /workouts/:id/complete. See Workout Logbook.
Endpoints¶
| Endpoint | Purpose |
|---|---|
POST /v2/workouts/:id/quick-complete |
Mark the whole session done + optional session/per-exercise feedback. 409 if already completed. Patient-owner only. |
PATCH /v2/workouts/:id/progress |
Save the resume envelope + optionally the just-finished exercise. Sets timeWorkoutStart on first write. 409 once completed. Patient-owner only. Since 2026-10-13 also playbackMode: "LIST", completedExercise.loggedSets (the logbook's sets, replacing the exercise's CompletedExerciseSet rows and deriving actualSets / actualReps) and sessionFeedback (pain, effort, note on the workout row). |
POST /workouts/:id/complete |
Legacy completion, unchanged contract — old app versions keep working. Now authorized (patient or connected doctor) and idempotent: retries return the existing result without re-running side effects. |
All completion paths share one server-side service so the six completion side-effects (app-entrance cancellation, streaks, celebration notifications, AI plan generation, RTM recalculation, therapist feedback notification) fire exactly once per session.
Key Files¶
| File | Role |
|---|---|
OktaPT-API/src/services/workoutCompletionService.ts |
Shared completion service: side effects, quick-complete transaction, duration estimate |
OktaPT-API/src/routes/workouts/patientSession.ts |
quick-complete and progress endpoints |
Okta-Mobile/hooks/useWorkoutFlow.ts |
Mobile flow state machine, resume hydration, auto-completion |
Okta-Mobile/services/workoutProgressService.ts |
Mobile progress queue (retry, eviction protection, feedback recovery) |
Okta-Mobile/app/(patient)/(workout)/quick-finish/[id].tsx |
Mobile quick-finish screen |
OktaPT-FE/hooks/useWorkoutFlow.ts |
Web flow state machine, progress queue, resume hydration |
OktaPT-FE/components/patient/QuickFinishSheet.tsx |
Web quick-finish sheet |
OktaPT-FE/components/patient/ExerciseDetailModal.tsx |
Exercise preview from the dashboard (works for exercises without video) |