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
| Persona | Role |
|---|---|
| Coach / Admin / Owner | Sets the day’s programming for each class type, toggles draft↔published. |
| Member | Reads via findByWeek / findByDate. Sees only status='published' rows. |
| Class sessions surface | ClassSessionsService 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
- Set —
PUT /daily-programmingwith{ classTypeId, date, status?, workouts:[{ workoutId, sortOrder }] }. Whole-day replace: deletes existing rows for(classTypeId, date)and inserts the new set in one transaction. - Read by week —
GET /daily-programming?weekStart=YYYY-MM-DD. Returns[{ classTypeId, classType, date, status, workouts[] }]grouped per (classType, date). - Read by date —
GET /daily-programming?date=YYYY-MM-DD. - Toggle status —
PATCH /daily-programming/status{ classTypeId, date, status }. Affects all rows for that slot. - Remove —
DELETE /daily-programming?classTypeId&date. Physical delete (no soft-delete column). - Member visibility — members see only
status='published'(service filters after the SQL fetch).
Relationship to other features
- workouts —
daily_programming.workout_idreferences a library workout. Service validates org ownership before insert. - program-templates —
applyToSchedulewrites bothclass_sessionsanddaily_programmingrows in one transaction. - scheduling/class sessions —
ClassSessionsService.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 —
DELETEphysically removes rows. Historical accountability lost (if a coach unpublishes/edits the day, prior content is gone). - No
daily_programming.organization_iddenormalization — every query joins throughclass_types → programs.organization_idto scope (getOrgClassTypeIds). Adequate at current scale; potential index target later. - No audit trail for daily-programming edits. Different from
workout_assignmentsbulk ops, which writeaudit_logs. - Status enum is a plain
varchar(20)— onlydraft/publishedaccepted in practice; not enforced at DB level. The controller’sSetStatusDtoenforces it viaclass-validator. findByWeekmember filter is JS-side after the SQL fetch — readable but loads draft rows the member won’t see.