Stop Training Around Your Weaknesses.
CorrectiveRehab is a mobile-first gym biomechanical audit tool. It records loaded movement from multiple angles, analyzes form and asymmetry, tracks change over time, and maps movement findings to training drills.
The primary delivery target is an HTTPS/PWA link opened in iPhone Safari or Android Chromium. App Store, TestFlight, EAS, and separate native releases are not required for this MVP.
- Phases 0-5 are complete.
- Phase 6 MVP is complete: movement-mapped training suggestions, the ranked Prescription Rail, completion tracking, and honest exercise placeholders are implemented.
- Prescription Rail entries are training suggestions, not a medical diagnosis or treatment.
- Exercise catalog images are illustrative. Licensed, expert-reviewed exercise images and videos are still pending.
- Credential-free demo mode is complete and runs the primary journey without Supabase or Cloud Run.
- Connected Supabase, Cloud Run analysis, optional secure AI-summary endpoint, and optional server-side PostHog paths remain available when configured.
- PWA metadata, standalone manifest, icons, mobile viewport behavior, and camera/file fallback are implemented. Physical-device installation has not been accepted, and there is no service worker or offline-install claim.
- Open the HTTPS link on a phone.
- Enter credential-free demo mode automatically, or authenticate by email OTP in connected mode.
- Choose a lift and record the requested angles with the browser camera.
- Preview, retake, or choose an existing video when camera recording is unavailable.
- Run deterministic local demo analysis, or upload to Supabase Storage and call Cloud Run.
- Review per-angle scores, findings, skeleton keyframes, coaching, and the Prescription Rail.
- Revisit history, trends, arbitrary comparisons, and habit-to-score correlations labelled as correlation, not causation.
Demo mode persists seeded and newly created records in browser localStorage. It does not upload video. Connected mode uses Supabase Auth, Postgres, Storage, and row-level security.
The connected analysis service uses FastAPI, FFmpeg, OpenCV, and MediaPipe Pose to process approximately 15 keyframes per angle and return:
- a 0-100 symmetry score;
- movement findings with severity and measurements;
- 33-landmark keypoints for skeleton rendering;
- angle-specific results for comparison and trend tracking.
Automatic findings are limited to seven reviewed issue IDs: forward lean, lateral hip shift, hip hike, knee alignment deviation, shoulder shrug, bar rotation, and wrist asymmetry. Stable IDs remain hip_shift and ankle_cave, but absolute geometry does not claim a side or inward/valgus direction. Butt wink is not automatically detected because shoulder-hip-knee angle measures hip flexion, not pelvic or lumbar tilt; it remains available only as a user-observed habit and drill mapping.
| Lift | Angle | Automatic findings |
|---|---|---|
| Squat | Side | Forward lean |
| Squat | Front | Lateral hip shift, hip hike, knee alignment deviation |
| Deadlift | Side | Unsupported |
| Deadlift | Front | Lateral hip shift, hip hike |
| Bench press | Side | Unsupported |
| Bench press | Above | Bar rotation, wrist asymmetry |
| Overhead press | Side | Forward lean |
| Overhead press | Front | Shoulder shrug |
| Barbell row | Side | Unsupported |
| Lunge | Front | Lateral hip shift, hip hike, knee alignment deviation |
| Lunge | Side | Forward lean |
Required capture remains unchanged, but client analysis uses each category's separate analysisAngles: deadlift analyzes front only, bench analyzes above only, and known unsupported captured angles are skipped rather than recorded as failures. Row has no supported automatic route; it saves with analysis_status='not_supported', no score/results/failures, and remains visible in History as not analyzed. A direct unsupported server request still fails before media download with typed analysis_not_supported. Forward lean is the shoulder-to-hip torso angle from upward vertical, so shoulder-over-hip is approximately 0 degrees.
Connected analysis streams private video to disk in bounded chunks and rejects media over 100 MiB or 120 seconds. Source dimensions may be at most 3840x2160 in either landscape or portrait orientation; retained frames fit 1280x720. FFmpeg is limited to 30 seconds, blocking FFmpeg/OpenCV/MediaPipe work runs off the event loop under bounded concurrency, and client requests abort after 120 seconds. Unsupported-route, no-pose, insufficient-pose-quality, and unsafe/unreadable failures return typed safe codes (analysis_not_supported, pose_not_detected, pose_quality_insufficient, video_too_large, video_too_long, video_resolution_too_high, analysis_timeout, or video_unreadable) and are never stored as successful scores.
Connected POST /analyze requests require Authorization: Bearer <Supabase user access token>. The server verifies that token against Supabase, derives the authenticated user ID, rejects a different body user_id, requires the decoded storage path to have exactly user/session/file segments, and verifies one exact owned video row across ID, user, session, category, angle, and path. Only after those checks does the service use its server-side service key to download the private video. The app writes returned results through the user's Supabase session so RLS remains in force.
Server telemetry activates only when both POSTHOG_API_KEY and POSTHOG_HASH_SALT are configured. Distinct IDs are HMAC-SHA256 pseudonyms, and event properties are limited to an optional coarse error code; session/video IDs, category, angle, scores, severity, counts, paths, and exception details are not sent. This is a data-minimization contract, not a user-consent claim. Retention, processing region, notice/opt-out behavior, and production enablement remain deployment policy gates.
The optional AI-summary endpoint is available only in connected Supabase mode. Requests require Authorization: Bearer <Supabase user access token> and contain only { categoryLabel, results }, with each result limited to angle, symmetry_score, and coaching-safe issue fields (id, label, severity, detail). The endpoint must verify the bearer token with Supabase before processing and must keep provider credentials server-side.
A production endpoint also requires distributed rate limiting and abuse controls at the edge or service layer; an in-memory per-instance limiter is not sufficient. This repository defines the client contract and local fallback only. It does not claim that an AI-summary endpoint has been deployed.
Initial history, session-detail, and comparison failures render visible generic alerts with labelled retry actions. Detail retry remains bound to the failed session; comparison retry retains the exact base/target pair and keeps the picker open until navigation succeeds. These connected failure states are covered by production-helper tests, not claimed as browser-live connected acceptance.
Plain YYYY-MM-DD history values are parsed as local calendar dates, preventing western time zones from displaying the prior day. Timestamp values retain instant semantics. The shared formatter covers visible dates, trend labels, comparison labels/options, and accessibility labels.
| Capability | Configuration | Behavior |
|---|---|---|
| Demo | Supabase client configuration absent or invalid | Guest identity, browser-local records, deterministic analysis and coaching |
| Connected data | Supabase URL and anon key | Real auth, database, RLS, and private Storage |
| Connected analysis | Connected data plus analysis server URL | Authenticated Cloud Run /analyze path |
| Optional AI summary | Connected data plus secure AI-summary endpoint URL | Supabase-authenticated enhanced coaching with deterministic local fallback |
| Optional telemetry | Server PostHog key and hash salt | Pseudonymous coarse server events; no-op unless both are present |
Capabilities degrade independently. No provider secret belongs in the browser bundle.
Names only are shown here. Do not commit values.
EXPO_PUBLIC_SUPABASE_URLEXPO_PUBLIC_SUPABASE_ANON_KEYEXPO_PUBLIC_ANALYSIS_SERVER_URLEXPO_PUBLIC_AI_SUMMARY_URL
SUPABASE_URLSUPABASE_ANON_KEYSUPABASE_SERVICE_KEYPOSTHOG_API_KEYPOSTHOG_HASH_SALTPOSTHOG_HOSTANALYSIS_MAX_CONCURRENCYALLOWED_ORIGINS
SUPABASE_ANON_KEY is optional when the server is configured to use SUPABASE_SERVICE_KEY for token verification. POSTHOG_API_KEY and POSTHOG_HASH_SALT are optional but must be configured together; POSTHOG_HOST has a code default. ANALYSIS_MAX_CONCURRENCY defaults to 1 and accepts values from 1 through 32. ALLOWED_ORIGINS is comma-separated with localhost-only code defaults; deploy.sh requires explicit HTTPS production origins. Service, telemetry, and salt values are server-only.
Cloud Run source deployment accepts Secret Manager resource names through
SUPABASE_ANON_KEY_SECRET, SUPABASE_SERVICE_KEY_SECRET, and optional paired
POSTHOG_API_KEY_SECRET/POSTHOG_HASH_SALT_SECRET; these are deployment inputs,
not runtime secret values.
npm install
cp .env.example .env
npm run webWithout valid Supabase settings, the app starts in demo mode. Camera APIs require a secure context in production; localhost is allowed for development.
Useful verification commands:
npm test
npm run lint -- --max-warnings=0
npx expo export -p webThe analysis server is under server/. Its local deployment environment file is gitignored. Deployment is intentionally not part of this documentation update.
Expo Web client
demo: localStorage -> deterministic analysis -> local coaching
connected: Supabase Auth/Postgres/Storage
|
| Supabase user Bearer token
v
FastAPI /analyze on Cloud Run
verify user + storage ownership
|
v
FFmpeg/OpenCV/MediaPipe
|
v
scores + issues + keypoints
src/screens/ Product screens and mobile-web flows
src/components/ Skeleton, charts, and reusable UI
src/lib/ Runtime modes, demo store, analysis, correlation, plans
server/ FastAPI/MediaPipe analysis service and tests
public/ Web shell, manifest, and PWA icons
tests/ Vitest suites
docs/ Design and implementation plans
The verified credential-free browser MVP is not the same as a production release. Production still requires:
- distributed rate limiting for
/analyzeat the edge or Cloud Run; an in-memory per-instance limiter is not sufficient; - a credentialed staging smoke covering Supabase auth/data/storage, signed media, Cloud Run analysis, and optional integrations;
- an enforceable deadline for native OpenCV/MediaPipe processing and restricted runtime egress;
- an approved telemetry retention period, processing region, notice, and opt-out policy before enabling telemetry;
- physical iPhone Safari and Android Chromium camera, file fallback, playback, and PWA home-screen installation acceptance;
- licensed, expert-reviewed exercise images and videos.
There is currently no service worker, offline cache, native binary, store release, push, or deployment claim.
| Phase | Status | Scope |
|---|---|---|
| 0 | Complete | Identity and performance-focused visual language |
| 1 | Complete | Supabase auth, persistence, RLS, and demo-capable boundaries |
| 2 | Complete | Gym-specific habit tracking |
| 3 | Complete | Multi-angle recording, preview, and upload/local save |
| 4 | Complete | Pose analysis, skeleton keyframes, and session comparison |
| 5 | Complete | History, trends, arbitrary comparison, and correlation |
| 6 | MVP complete | Prescription Rail training suggestions and placeholders; production media pending |
Latest verification: 420 JavaScript tests and 52 server tests passed, with zero-warning lint and a successful credential-free web export. This supersedes earlier totals.
See ROADMAP.md for phase detail, PROGRESS_REPORT.md for current verification evidence, and .superpowers/sdd/final-supported-analysis-report.md plus .superpowers/sdd/final-habit-idempotency-report.md for the supporting final reports.