Back to all posts
·4 min read·scheduling

Scheduling 60 Workouts in One Click: Apply-to-Group, Atomic

Most platforms let you assign a program to one athlete at a time. SWEATX schedules 12 weeks × 5 athletes in a single atomic transaction. Here's why that matters and what 'atomic' actually means for coaches.

Assigning a 12-week block to a group of 5 athletes is 60 workouts. Doing that one-by-one takes ~30 minutes of clicking, and if the coach's session times out halfway through, half the athletes have a program and half don't.

SWEATX treats this as a single operation. Pick a start date, map program days to weekdays, resolve any conflicts, hit apply. 60 workouts land on 60 athlete calendars in one transaction. Either all of them, or none of them.

What "atomic" means, and why it matters

In database terms, atomic means the whole operation succeeds or the whole thing rolls back. No half-states.

The practical coaching consequences:

Before atomic scheduling (other platforms):

  • You assign program to athlete 1 — success
  • Athlete 2 — success
  • Athlete 3 — network hiccup, partial failure
  • Athlete 4 — you don't know if it went through
  • Athlete 5 — browser froze
  • Now you have to audit which athletes actually have the program, and reassign the ones that failed, without double-scheduling

With atomic scheduling:

  • You submit the apply
  • Either all 5 athletes have the 12-week block or none of them do
  • If anything fails, the coach gets a clear error naming the conflict, nothing partial
  • Coach fixes the conflict, resubmits, done

The latter is ~30 seconds of coach time. The former is a Tuesday night.

What the apply flow actually does

  1. Pick target — individual athlete or group
  2. Pick start date — with smart defaults (Monday of next week)
  3. Map program days to weekdays — program Day 1 → Monday, Day 2 → Tuesday, etc. The default now detects weekday labels from the program (so "Jour 1 - Lundi" maps to Monday automatically); coach can override any day from a dropdown
  4. Set conflict resolution — if an athlete already has a workout on one of the target dates, what happens?
    • skip — don't schedule the conflicting day
    • replace — overwrite the existing workout
    • add-both — put both on the calendar (athlete picks)
  5. Review the preview — actual calendar dates for every session, scrollable
  6. Apply

Step 5 is the cheapskate's favorite. It's not a summary of "what will happen" — it's the exact dates that will be created, computed client-side using the same logic the server uses. No surprises.

How we prevent partial writes

Under the hood, the apply route does three things before creating any schedule rows:

  1. Validates every day can be scheduled — checks the dayMap is complete, start date is valid, athlete belongs to the coach
  2. Detects all conflicts up front — loads all existing ScheduledWorkout rows for the target athletes across the planned date range, flags any collision
  3. Creates all rows in a single MongoDB transaction — so if the DB writes fail midway, everything rolls back

The coach never sees "3 of 5 athletes got scheduled" — they see success or a clear reason for failure.

The timezone thing we just fixed

A coach on iPhone in Morocco reported last week that a program day he'd labeled "Lundi" was getting scheduled on Thursday. Traced it to two bugs that overlapped:

  1. The client (his browser) and server (Vercel UTC) computed weekday from the start date using different timezones — new Date("2026-04-20").getDay() returns different values depending on where the runtime is. For negative-offset timezones (America, São Paulo) the server and client disagreed and the offset arithmetic drifted by 1–3 days.

  2. The default day-to-weekday mapping ignored the program day titles. If the parser produced days in an unexpected order (Jeudi at dayIndex 0, Lundi at dayIndex 3), the default map assigned Lundi → Thursday because it filled sequentially starting from Monday.

Both are fixed. The timezone calc is now done in UTC at both ends (always agrees), and the default map parses each day's title for EN/FR/ES weekday names before falling back to sequential. If your day is labeled "Monday" or "Lundi" or "Lunes", it gets Monday.

This is the kind of bug you only catch when a real coach uses the product on a real phone in a real timezone. Keep those messages coming.

Try it

Import any program (even a 4-week test block), create a group of 2–3 test athletes, and hit apply-to-group. You'll see the conflict detection and atomic write behavior in action.

If your workflow has an edge case this flow doesn't handle, email help@sweatx.app. The apply route is one of the most-modified files in the codebase because every coach's team has a slightly different rhythm.

Scheduling 60 Workouts in One Click: Apply-to-Group, Atomic | SWEATX