Files
Keysat 3a5b929284 v1.1.0:1 — Programs UI (manual create / save / follow)
Schema
- Workout.programDayId added (nullable FK to ProgramDay) so a
  Workout logged from a program day can be tied back to the planned
  session for adherence analytics. Compat ALTER in entrypoint adds
  the column + index to existing /data; ON DELETE SET NULL so
  deleting a program doesn't remove historical workouts logged
  against it.
- Back-relation `workouts: Workout[]` added to ProgramDay.

API (proof-of-work/app/api/programs/...)
- GET    /api/programs                       — list user's programs
- POST   /api/programs                       — create with full nested
                                                 weeks/days/exercises
                                                 tree in one transaction
- GET    /api/programs/[id]                  — full tree
- PATCH  /api/programs/[id]                  — update metadata AND/OR
                                                 replace entire weeks
                                                 tree (same shape as
                                                 POST). UI editor + AI
                                                 apply flow share this.
- DELETE /api/programs/[id]                  — cascading
- POST   /api/programs/[id]/days/[dayId]/start
                                              — creates a Workout
                                                 pre-populated with
                                                 empty SetLogs (one per
                                                 planned set), tagged
                                                 with programDayId.

UI (proof-of-work/app/main/programs/...)
- /main/programs               — list with cards, today's-session
                                  callout, "active" badge
- /main/programs/new           — create form using ProgramEditor
- /main/programs/[id]          — detail + edit using same editor;
                                  today's-session card + Start button
                                  if program is active
- ProgramEditor component (components/programs/ProgramEditor.tsx) —
  expandable tree editor for weeks -> days -> exercises with
  per-row sets/reps/RPE/rest/notes fields + library exercise picker
- ProgramActions: delete button
- StartSessionButton: POSTs to start endpoint, redirects to new
  workout

Navigation
- "Programs" link added to bottom nav + sidebar (between Workouts
  and Exercises).
- /main/programs page itself shows the today's-session card; the
  same component pattern can be lifted into the dashboard later
  if we want.

lib/db/programs.ts
- getPrograms, getProgramById, getActivePrograms,
  computeTodaysSessionForProgram, getTodaysSession helpers.
- Today's session math: floor((todayUTC - startDateUTC) / 1day),
  weekNumber = floor(.../7) + 1, dayOfWeek = today.getUTCDay().
  Returns null if not started, past durationWeeks, or no day
  matching today's slot (= rest day).

Tests (tests/routes-programs.test.ts)
- 11 new tests covering: 401 unauthenticated, full-tree create
  with nested weeks+days+exercises, cross-user exerciseId
  rejection, list scoped to actor, GET detail returns 404 for
  another user's program, PATCH replace-tree atomicity,
  cascading DELETE, start-day Workout creation with the right
  number of empty SetLogs + programDayId stamped, start-day
  refused for cross-user program day.
- Total: 96 tests across 11 files.

This is the foundation for v1.1.0:2's AI-generated programs —
the AI will produce the same JSON shape POST /api/programs
already accepts, so the apply path is `editor.tsx + POST
/api/programs` with no new API surface.
2026-05-10 07:15:31 -05:00

53 lines
2.3 KiB
TypeScript

import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
/**
* v1.1.0:1 — Programs (manual create / save / follow).
*
* The Program / ProgramWeek / ProgramDay / ProgramExercise schema
* has existed since the legacy `workout-log` package but had no
* UI to use it. This release ships:
*
* - /main/programs (list) with a today's-session card if any
* program is active.
* - /main/programs/new (create form) with the full nested
* editor: program metadata -> weeks -> days -> exercises.
* - /main/programs/[id] (detail + edit) using the same editor,
* plus today's-session callout + "Start this session"
* button when applicable.
* - API: GET/POST /api/programs, GET/PATCH/DELETE
* /api/programs/[id]. PATCH replaces the entire weeks tree
* in one transaction (same shape POST accepts) — keeps the
* UI editor and the upcoming AI apply flow on the same code
* path.
* - "Start this session" wires through
* POST /api/programs/[id]/days/[dayId]/start which creates a
* Workout pre-populated with empty SetLogs from the planned
* ProgramExercises (one row per planned set), tagged with
* Workout.programDayId so we can later compute adherence.
*
* Schema change
* - Workout.programDayId (nullable FK to ProgramDay) added.
* - Compat ALTER in docker_entrypoint.sh adds the column +
* index to existing /data on first boot. ON DELETE SET NULL
* so deleting a program doesn't catastrophically remove
* historical workouts logged against it.
*
* This release is the foundation for v1.1.0:2's AI-generated
* programs — the AI will produce the same JSON shape that POST
* /api/programs already accepts.
*
* No data migration. /data on existing installs is untouched
* apart from the new column.
*/
export const v_1_1_0_1 = VersionInfo.of({
version: '1.1.0:1',
releaseNotes: {
en_US:
'Programs UI shipped. Build a multi-week training plan, mark it active, and follow it day by day from a new "Today\'s session" card. Includes a full nested editor (program -> weeks -> days -> exercises), starts a session as a pre-populated workout you fill in as you go, and tracks Workout.programDayId for upcoming adherence analytics. Foundation for v1.1.0:2 (AI-generated programs).',
},
migrations: {
up: async () => {},
down: IMPOSSIBLE,
},
})