Fix: rotate template workouts across all program weeks (Bug 2)

Catalog stores only the template (typically week 1) but programs span
many weeks. The schedule endpoint was returning only the literal stored
rows, so after day 3 of StrongLifts a user would see no upcoming
workout despite being mid-program.

Changes:
- Add week_number column to workout_logs (migration in main.py) so the
  same template workout can be completed once per real week
- Synthetic workout IDs: '{template_uuid}::{real_week}' — frontend
  treats opaquely, backend parses on every endpoint
- get_program_schedule rotates the template across catalog.duration_weeks
  real weeks and returns synthetic IDs
- today_workout: first uncompleted non-rest entry in current real week
  (more flexible than literal day-of-week match)
- complete_workout / get_workout_detail parse synthetic IDs and track
  completion per (template_id, real_week) pair
- check_weekly_bonus filters by workout_logs.week_number for the real week
- check_completion_bonus and progress endpoint compute total as
  template_per_week * total_weeks, not just template count
This commit is contained in:
claude 2026-04-09 15:55:22 +00:00
parent 67b539f68a
commit dddd308ff7
3 changed files with 176 additions and 105 deletions

View file

@ -94,6 +94,7 @@ class WorkoutLog(Base):
catalog_workout_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("catalog_workouts.id"), nullable=False
)
week_number: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
completed_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)