Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesDaily ProgrammingDaily programming

Daily programming

What this is

Daily programming is the class-type × date → workouts join. Coaches use it to publish the “WOD board” for a given class type on a given day: “WOD on 2026-06-03 = Fran”. One row in daily_programming per (class_type, date, workout). Status is draft or published; members only see published rows. This is the broadcast/whiteboard surface — orthogonal to workout-assignments, which are per-user. Schedule-mode program-templates materialize daily-programming rows alongside class_sessions on apply.

Who uses it

PersonaRole
Coach / Admin / OwnerSets the day’s programming for each class type, toggles draft↔published.
MemberReads via findByWeek / findByDate. Sees only status='published' rows.
Class sessions surfaceClassSessionsService reads via findByDateRange(publishedOnly=true) to surface the day’s workouts on a session card.

Persona impact

  • Coach writes once per class type per day; the same prescription is visible to every member booked into any session of that class type on that day.
  • Member sees the day’s programming on the class card before booking, and on the whiteboard / class session view.
  • Owner uses schedule templates to fill weeks of programming in one apply.

Capabilities

  1. SetPUT /daily-programming with { classTypeId, date, status?, workouts:[{ workoutId, sortOrder }] }. Whole-day replace: deletes existing rows for (classTypeId, date) and inserts the new set in one transaction.
  2. Read by weekGET /daily-programming?weekStart=YYYY-MM-DD. Returns [{ classTypeId, classType, date, status, workouts[] }] grouped per (classType, date).
  3. Read by dateGET /daily-programming?date=YYYY-MM-DD.
  4. Toggle statusPATCH /daily-programming/status { classTypeId, date, status }. Affects all rows for that slot.
  5. RemoveDELETE /daily-programming?classTypeId&date. Physical delete (no soft-delete column).
  6. Member visibility — members see only status='published' (service filters after the SQL fetch).

Relationship to other features

  • workoutsdaily_programming.workout_id references a library workout. Service validates org ownership before insert.
  • program-templatesapplyToSchedule writes both class_sessions and daily_programming rows in one transaction.
  • scheduling/class sessionsClassSessionsService.findByDateRange(publishedOnly=true) reads daily programming so a class session card shows the day’s workouts.
  • workout-assignments — completely orthogonal. Assignments are per-user; daily programming is per-class-type. A schedule-mode program drives daily programming; a coaching-mode program drives assignments.

Current status

Shipped. Whole-day replace pattern, draft/published flip, week/date reads, schedule-template-driven materialization. ~510-line service.

Known gaps / open Linear issues

  • No soft delete — DELETE physically removes rows. Historical accountability lost (if a coach unpublishes/edits the day, prior content is gone).
  • No daily_programming.organization_id denormalization — every query joins through class_types → programs.organization_id to scope (getOrgClassTypeIds). Adequate at current scale; potential index target later.
  • No audit trail for daily-programming edits. Different from workout_assignments bulk ops, which write audit_logs.
  • Status enum is a plain varchar(20) — only draft / published accepted in practice; not enforced at DB level. The controller’s SetStatusDto enforces it via class-validator.
  • findByWeek member filter is JS-side after the SQL fetch — readable but loads draft rows the member won’t see.