# LiftFlow onboarding and Starter Plan v1 Implementation reference for the first activation vertical slice. The product and training-rule rationale remains in [onboarding-starter-plan-rulebook-v1.md](onboarding-starter-plan-rulebook-v1.md). ## Product flow An authenticated user with `viewer.requiresOnboarding = true` enters a server-backed first-run boundary and chooses one of two equal paths: 1. **Build one for me** — four short screens collect the five approved required inputs, then show a read-only server preview, safe replacements and activation. 2. **Create my own** — skips the questionnaire and opens a simplified Training Plan builder using the normal manual create/activate mutations. There is no paywall, AI, body-profile questionnaire or defer-to-empty-home path. Existing users whose onboarding was migrated complete bypass this flow. ## Inputs and defaults | Input | Values | Default | Effect | | ---------------- | --------------------------------------------------------------- | --------------------- | -------------------------------------------------------------- | | Experience | Starting or returning / Some experience / Training consistently | Starting or returning | Exercise complexity, sets and RIR | | Goal | Build muscle / Get stronger / Muscle + strength | Muscle + strength | Rep ranges, first-exercise order/rest and volume-band position | | Days | 2–6 | 3 | Split, cadence and `days × 8` workout target | | Session duration | 30 / 45 / 60 / 75 minutes | 45 | Exercise/set budget and deterministic duration validation | | Environment | Gym / Home with equipment / Minimal equipment | Gym | Hard candidate eligibility | | Priorities | At most two of chest/back/shoulders/arms/legs/glutes | None | Selection/order first, at most modest volume | | Exclusions | Stable Starter exercise IDs | None | Hard exclusion constraint | Partial answers and stable retry identifiers are stored in account-scoped AsyncStorage under the onboarding store. They survive refresh/restart but never become the source of truth for completion or plan data. A different authenticated user cannot inherit the previous user's draft. ## Versioned deterministic boundary - Rulebook: `STARTER_RULEBOOK_V1` - Catalog: `STARTER_CATALOG_V1` - Full system exercise catalog after the migration: 108 stable exercises - Reviewed Starter candidate count: 33 - Randomness: none - AI: none The backend normalizes input and deterministically ranks candidates by priority contribution, reviewed rank and stable UUID. The same normalized answers, replacements and versions produce the same training prescription. Polish changes stored display names only; it does not change exercise selection or prescription. ## Reviewed candidate catalog The v1 subset is: 1. Leg Press 2. Goblet Squat 3. High-Bar Squat 4. Reverse Lunge 5. Bodyweight Squat 6. RDL / Romanian Deadlift 7. Dumbbell Romanian Deadlift 8. Machine Hip Thrust 9. Glute Bridge 10. Bench Press 11. Flat Dumbbell Bench Press 12. Dumbbell Floor Press 13. Push-Up 14. Incline Push-Up 15. Overhead Press 16. Seated Dumbbell Overhead Press 17. Dumbbell Overhead Press 18. Pike Push-Up 19. Lat Pulldown 20. Assisted Pull-Up 21. Seated Cable Row 22. Single-Arm Dumbbell Row 23. Prone Reverse Snow Angel 24. Leg Curl 25. Standing Calf Raise 26. Cable Lateral Raise 27. Dumbbell Biceps Curl 28. Triceps Pushdown 29. Dumbbell Overhead Triceps Extension 30. Plank 31. Side Plank 32. Pallof Press 33. Farmer's Carry Twelve simple candidates were added to the system catalog because the prior 96-exercise catalog did not provide honest bodyweight/basic-home coverage. This is not a general exercise-enrichment pass. Each Starter candidate has reviewed code-side metadata for stable ID/code, display identity, primary and explicit secondary area, movement pattern, environment compatibility, minimum experience, compound/accessory role, substitution group, rep role, rest class, equipment concept, loaded/bodyweight behavior and deterministic rank. Metadata is not inferred from exercise names. Human review should revisit the minimal-equipment horizontal-pull fallback (Prone Reverse Snow Angel), the broad assumptions behind “Home with equipment”, and display naming of legacy `RDL` before the catalog is expanded. These are transparent v1 product/training decisions, not claimed physiological facts. ## Frequency structures | Days | Internal structure | | ---- | --------------------------------------------------------- | | 2 | Full Body A / B | | 3 | Full Body A / B / C with a stable shared core | | 4 | Upper A / Lower A / Upper B / Lower B | | 5 | Upper A / Lower A / concise Full Body / Upper B / Lower B | | 6 | Push A / Pull A / Legs A / Push B / Pull B / Legs B | All cadences use a seven-position queue pattern. Higher frequency redistributes work; the validator caps direct-equivalent major-area volume at 12 sets rather than treating extra days as permission to grow weekly volume indefinitely. ## Prescription model - Starting/returning uses mostly two working sets and 3 RIR. - Some experience uses two or three sets and 2–3 RIR. - Training consistently uses mostly three sets and 2 RIR. - Strength main work uses 6–8 reps for Starting/Some and selected 4–6 work for Consistent. - Balanced main compounds use 6–8, secondary compounds 8–12. - Muscle compounds use moderate 6–10 ranges; accessories use 10–15. - Bodyweight movements use a scalable 8–20 target. - Compound rest is normally 120 seconds and never below 90; main strength work may use 180. - Accessory rest is 75 seconds and never below 60. - No 0 RIR/failure prescription or fabricated starting kilograms exist. The approximate duration estimator includes setup, per-exercise transition, set execution and rest. The validator allows at most the selected duration plus 10%. The generator first reduces nonpriority sets above two, then removes the lowest-value nonrequired accessory; it never solves duration by cutting rest below the safe boundary. ## Coverage, priorities and exclusions Every generated week must cover knee-dominant lower body, hinge, horizontal push and horizontal pull. Major chest, back, shoulders, legs and glutes direct-equivalent volume must remain between four and twelve sets. Secondary contribution counts as half a set for this conservative v1 validator. Priorities affect deterministic selection and ordering before volume. At most one modest extra set is added when duration permits, and global volume caps remain authoritative. Exclusions are hard. If environment plus exclusions cannot cover a required movement, the backend returns `STARTER_PLAN_IMPOSSIBLE` and writes nothing. ## Preview and replacement contracts `starterPlanPreview(input:)` normalizes, generates and validates, then returns stable exercise IDs, workouts, prescriptions, estimated duration, reason codes, versions and a short list of replacement options. It performs no persistence. Replacement input contains only a workout position, exercise position and stable replacement ID. The backend accepts a replacement only when it is an eligible curated candidate with the same movement pattern, primary area and compound/accessory role, is not excluded and is not duplicated in the workout. Preview is regenerated and revalidated after every replacement. The frontend never submits an authoritative generated plan payload. ## Create, activation and provenance `createStarterTrainingPlan(input:)` requires the preview's expected rulebook/catalog versions and a stable `clientOperationId`. Inside one database transaction it: 1. claims idempotency and locks the user; 2. rejects completed onboarding or an existing active plan; 3. verifies every catalog ID exists as a system exercise; 4. normalizes, regenerates and validates from the structured answers; 5. creates an active normal `TrainingBlock`, `TrainingPlan`, `PlanExercise`, cadence and state; 6. records `creation_source=starter_rulebook`, rulebook and catalog versions; 7. sets `onboarding_completed_at`; 8. stores the idempotent result and commits. Any failure rolls back all writes. A retry of the same operation returns the original normal block. The target workout count is `trainingDays × 8`; queue skips/misses do not consume it. ## Manual path The onboarding manual builder uses normal Training Plan APIs. It defaults the title, start date, seven-day cadence, colors, prescriptions and eight-training-week workout target. Users can add up to six workouts, search the exercise catalog, add/remove/reorder exercises and edit a compact prescription. Onboarding completes only after the normal activation mutation succeeds. A lost response is recoverable because create and activate use separately persisted operation/resource IDs. ## Errors and user education The UI maps network, impossible-plan, active-conflict and version-conflict failures to localized, typed recovery states; raw GraphQL messages are not shown. Generation says “Building your Training Plan” without fake AI delay. Preview explains the stable eight-training-week approach and introduces RIR in plain language before terminology. “Why this plan?” uses deterministic schedule, environment and priority reason codes only. ## Validation evidence Local validation on 2026-08-28: - Frontend Docker validation: Prettier, ESLint, strict TypeScript and **328/328 Jest tests** passed across 72 suites. - Backend Docker validation: Ruff format/check, strict mypy for 164 source files, **195/195 pytest tests**, coverage above the 85% gate and **13/13 Behave scenarios** passed. - Generator matrix: all 540 combinations of 3 experiences × 3 goals × 5 frequencies × 4 durations × 3 environments passed deterministic invariants; priority/exclusion/replacement and rollback paths have separate assertions. - Django system check and `makemigrations --check --dry-run` passed. - Production backend image build passed. - Expo web production-style export passed when supplied explicit development environment values. - Clean Expo CNG prebuild generated iOS and Android projects, the development identifiers, Sign in with Apple entitlement and expected URL schemes. Generated native directories were not retained because CNG owns them. - Expo Doctor: 17/21 checks passed. The four known pre-existing release issues are SDK 57 patch misalignment/duplicate Expo modules, affected Hermes V1 version, Nitro metadata warning and `react-native-screens` minor mismatch. This task intentionally did not mass-upgrade dependencies. Rendered browser QA used real local frontend/backend builds and disposable onboarding users rather than mocked provider or plan payloads. Twenty-one captured states cover the start choice, all four question screens, beginner adherence hint, exercise exclusions, honest deterministic generation, preview, expanded explanations, replacement, automatic activation/Home handoff, manual builder, exercise picker, prescription editor, manual activation and a forced server-failure recovery state. The matrix includes the desktop 1280 × 1024 iPhone preview, narrow 375 × 667 mobile web and 430 × 932 light-mode mobile web. Automatic activation produced a normal three-workout active Training Plan with a 24-workout target; the manual path produced an eight-workout target. No browser runtime error remained after excluding the deliberately forced 503 used to inspect recovery UI. Visual inspection triggered two final corrections: generation now visibly and truthfully says that LiftFlow is building the Training Plan instead of showing an unexplained skeleton, and the Home handoff uses “Active Training Plan”/“Aktywny Plan Treningowy” rather than exposing internal block terminology. The current production QA captures are temporary review artifacts outside the repository under `/tmp/liftflow-onboarding-production-qa`. ## Deployment and production verification The validated frontend commit `6ee464e1` and backend commits `4894980` plus the compatibility fix `abad86b` were integrated into each repository's remote `main` and deployed through the allowlisted live deployment scripts. The backend was deployed first. The deployment created database backups, applied migration `0017_starter_plan_foundation`, passed readiness checks and left the API and PostgreSQL containers healthy. The web deployment then passed its health check on `https://liftflow.carpentestudio.com`. Production browser QA used only `codex.technical@liftflow.app`, never the protected daily-use account. The first live preview exposed an important historical-identity mismatch: six exercises seeded by the already-applied `0002` migration retained their original `liftflow.app` UUID namespace in production, while the repository copy of that historical migration had drifted to `app.app`. The validator rejected the incomplete 27-of-33 catalog and persisted nothing. Commit `abad86b` restores the released migration identity, explicitly preserves the original ten exercise UUIDs and locks both old and later namespaces with regression tests; it does not rewrite workout history. After that fix, a fresh real-browser run on the deployed domain passed both paths without browser runtime errors: - automatic Starter Plan preview, deterministic replacement and activation produced an active three-workout plan with `0 of 24` completed workouts; - the 375 × 667 light-mode manual path added Bench Press, activated a normal manual Training Plan and produced `0 of 8` completed workouts; - the manual plan's primary Home action opened the first workout, and opening Bench Press created a persisted `in_progress` session with its executable prescription without guessing a starting load; - the final persisted technical-account state has onboarding complete and exactly one active manual block with target eight. The disposable automatic block was removed by the QA reset between the two independent scenarios. Nine production captures cover the start choice, generated preview, replacement sheet, automatic Home handoff, empty and filled manual builder, manual Home handoff, first-workout selection and the first exercise editor. The generated preview and automatic Home were checked in the desktop 1280 × 1024 iPhone-frame presentation; the manual flow and first workout were checked at 375 × 667 in light mode. ## Known v1 limitations - Starter taxonomy is reviewed only for 33 candidates; it is not persisted as general exercise metadata and does not enrich all 108 exercises. - Home-with-equipment deliberately assumes basic weights without a detailed inventory, so Replace is the recovery path for unavailable movements. - Exercise display names are canonical system names; full catalog localization is not implemented. - Starting load is user-selected from the RIR guidance; no numeric load recommendation exists. - Manual create and activate are two idempotent normal mutations, not one combined backend command. - Native runtime/device visual QA remains distinct from successful CNG generation and will require development builds on iOS and Android.