# UX Redesign — Goals, Schedules & the Today Board

Design direction agreed 2026-07-09/10. This restructures the app from a
single-screen history list into a four-tab app built on three independent
layers — routines, schedules, goals — with a **Today board** as the entry
surface, and rides a full visual refresh along with it. The sync architecture
is untouched; the data-model additions are two small new document aggregates
(Goals, Schedules) on the existing machinery.

## The three layers

```
ROUTINES    the content  — what "Lower Body" or "Evening Meditation" consists of
SCHEDULES   the plan     — "Lower Body · every Mon & Thu · → Strength"
GOALS       the meaning  — stable categories everything rolls up to
```

**You plan with schedules, act on routines, observe by goals.** The three are
deliberately independent:

- **Goals outlive plans.** Switching from a 3-day to a 5-day program rewrites
  schedules, but the Strength *track* in Progress continues unbroken — history
  rolls up to the goal, not to the plan that produced it. The goal is the
  ledger category; a schedule is how you're currently trying to fill it.
- **Goals are optional.** A schedule with no goal tag still appears on the
  board and logs normally; it rolls up as uncategorized. Pure-scheduling use
  works; goals can be adopted later.
- **Scheduling never touches routine files.** The schedule is the join object
  (it references `routineID` and `goalID` from its own document), so
  scheduling an immutable fixed-ULID starter routine never forks the seed.

### Terminology: "Routine" replaces "Split" (user-facing)

"Split" is lifting jargon; the entity is now general — a meditation session, a
mobility flow, a run. UI strings say **Routine** everywhere; starter splits
become starter routines. Code-level type names (`Split`, `SplitDocument`, …)
stay as-is for now — a rename is churn with no user value; revisit only if it
starts to confuse.

### Goals

Just **name + color/icon + order** — no cadence, no machinery. Examples:
Strength, Endurance, Morning Movement, Mindfulness. Persisted as
`Goals/<ULID>.json` (standard three-place data model). Workouts additionally
**stamp the goal at completion** (denormalized `goalID`/`goalName`, same
pattern as the existing `splitID`/`splitName`), so history keeps the
attribution it had when logged even if schedules are re-tagged later.

### Schedules

A schedule = **one routine + a recurrence + an optional goal tag**, persisted
as `Schedules/<ULID>.json`. Recurrence flavors:

1. **Fixed days** — "every Mon & Thu". Deterministic; the board just shows it.
2. **Daily** — e.g. the morning routine or evening meditation.

(A one-off `.once` recurrence also exists for a single-day plan; a "times per
week, whenever" flexible mode was tried and removed — it added planner
complexity nobody used, and fixed days cover the common case just as well.)

Plus an optional **time window** (e.g. morning, default cutoff ~11 am,
tunable) with a per-schedule setting for whether the window gates the streak:
on = only in-window starts feed the streak, though the row stays startable and
completable all day; off = any-time completion counts.

**Missed fixed days get a catch-up nudge**: the schedule reappears next day as
due-with-a-reason ("missed Mon · catch up?"), planner-placed on the best
make-up day before the next fixed slot (recovery-aware in Phase 2), with an
explicit skip. Skipping just waits for the next fixed slot.

Example of the model's reach: *Goal: Mindfulness ← Schedule: "Meditation ·
daily · evening window" ← Routine: one duration-based Meditation exercise*
(`LoadType.duration` already exists; add a `mindAndBody` case to
`WorkoutActivityType` — optional-int wire field, no schema bump — mapping to
HealthKit's mind-and-body session on the watch).

## Information architecture

Four tabs: **Home · Progress · Library · Settings**.

| Tab | Contents | Provenance |
|---|---|---|
| Home | The Today board (new) | New surface |
| Progress | Per-goal tracks + trends + full history + achievements | Absorbs `WorkoutLogsView`, promotes `WeightProgressionChartView` / `ExerciseProgressView` |
| Library | Exercise library | Promotes `ExerciseLibraryView` out of Settings |
| Settings | Slimmed settings + goal/schedule editing + About | Existing, minus Library |

Routine management stays reachable from Home — setup, not a daily
destination. The `SplitDetailView`/`ExerciseListView` duplication is
consolidated during this restructure (ExerciseListView is a pure duplicate).
The watch app is untouched: it remains a thin remote; nothing changes the wire
format until Phase 2's optional location field.

## Home — the Today board

Home is **the today-projection of the user's schedules**: a flat, stable,
time-ordered checklist where each row wears a small colored goal tag. It is
the jumping board for the day, a guide, and a motivational aid — in that
order. Boxes fill up as the day goes on.

```
Thursday, July 10
┌──────────────────────────────────┐
│ ✓ Mobility ·7:04·   [Morning] 🔥12│   done — stays in place, streak ticked
│ ● Lower Body        [Strength]   │   fixed schedule, due today
│   Mon & Thu · ▶ Start            │
└──────────────────────────────────┘
This week ▪▪▪▫▫▫▫  + one encouraging line
```

- **Row states**: *due* (start button, streak at stake — fixed/daily
  schedules on their day, catch-ups after a miss) → *in progress* (resume
  affordance, always wins attention) → *done* (✓, time, bumped streak). Done
  rows stay in place — the agenda's shape is stable and the day visibly fills
  up.
- **Due rows carry reason chips** from the planner ("missed Mon", "5 days
  since legs · you're usually here Thursdays") — never a black box. An
  override is a non-event and becomes signal.
- **Rest is declarable per row**: "make it a rest day" checks a due row off
  guilt-free; adherence treats a declared rest as met, and the board stays
  completable. (The planner can also propose rest when everything scores low.)
- **Sprinkles**: per-row streak flames, the week strip vs. usual pace, a
  clean-sweep moment when the last due row completes, then a small tomorrow
  preview.
- **Degrades gracefully**: no schedules → bootstrap proposal card; one
  schedule → a one-row board, i.e. a classic single-suggestion dashboard.

## The planner — `NextSplitPlanner`

A **pure, unit-testable scorer** (precedent: `SeedReconcilePlanner`). With
explicit schedules, its scope narrows to where inference is genuinely needed:

- **Catch-up placement** — the best make-up day for a missed fixed slot
  before its next occurrence.
- **(Phase 2) Recovery guard** — overlap between a routine's target muscles
  and muscles trained in the last ~48 h downweights it, using the bundled
  library's `Targets:` metadata (already parsed by `ExerciseInfo`). Because it
  looks across *all* recent workouts it is also the cross-goal coordinator
  ("no heavy legs the morning after a long run").
- **(Phase 2) Location affinity** — boost routines historically done at the
  current place; missing/denied location contributes nothing.

Deterministic, hand-tuned weights, fixture-history unit tests.

### Location capture (Phase 2)

- First workout start after the update requests **when-in-use,
  reduced-accuracy** location (place-level is all we need). Denial is
  respected silently forever.
- A coarse fix is stamped on `WorkoutDocument` as an **optional field** — no
  schema bump; older decoders ignore it (same rationale as `activityType`).
- Places are **derived at read time** by proximity clustering (~150 m);
  clusters are never persisted — consistent with the rebuildable-cache
  philosophy.

## Streaks & adherence

- **Computed per schedule**: did "Lower Body" hit Mon & Thu this week; did
  "Meditation" happen daily. Declared rests count as met. Streak state is
  always **derived** from workout documents — never persisted.
- **Rolled up per goal**: a goal's streak = consecutive weeks in which *all*
  its member schedules hit their recurrence. Precise diagnostics ("Upper is
  what's slipping") with an honest rollup.
- Week-based schedules are forgiving by construction: a missed day breaks
  nothing until the week itself is missed.

## Progress

- **Per-goal tracks first**: each goal's adherence over time, fed by
  per-schedule adherence; then aggregate trends — weekly volume, workout
  frequency; muscle-group balance (Phase 2). Time ranges per the
  trend-visualization pattern (7D/30D/90D/1Y/All).
- **Per-exercise drill-down**: the existing weight-progression and exercise
  progress views, promoted and restyled; later pinnable to a goal as an
  optional **outcome metric** (observed, never promised — goals themselves
  stay practice-anchored).
- **History**: the current `WorkoutLogsView` list lives here.
- **Achievements section**: a badge grid within Progress. All achievements are
  **pure derivations** (per-goal streak milestones, PR counts, volume/session
  milestones) — recomputable after any cache rebuild. Persisting earned-dates
  is deferred until we want one-time celebration moments.

## Visual redesign

Rides Phase 1 rather than following it: a shared component set — card, stat
tile, board row (due / ambient / done variants), goal tag, badge, reason chip
— with the iOS 26 glass treatment, applied as each surface is built. Existing
screens (run flow, routine editing) are restyled to the same system as they're
touched. Theming continues through `Color+Extensions`.

## Phasing

- **Phase 1 — goals + schedules + shell + design system**: Goal and Schedule
  document aggregates (documents + cache entities + mappers + editing UI +
  activity-type **bootstrap** that proposes initial goals/schedules from
  existing routines); 4-tab `TabView`; Today board v1 (due/ambient/done rows,
  catch-up nudges, resume, declared rest); planner v1 (recency + even-spacing
  placement, weekday affinity); Progress tab (per-goal tracks + history +
  promoted charts + achievements grid); Library promoted; Settings slimmed;
  "Routine" terminology pass; view-duplication consolidation; component set.
- **Phase 2 — the senses**: location capture + place affinity, recovery guard
  (cross-goal coordination), muscle-balance chart, outcome-metric attachments,
  `mindAndBody` activity type + watch session mapping, richer achievements.
- **Phase 3 — the library grows**: external exercise ingestion — exercises
  become user documents (new aggregate alongside the bundled library; real
  schema work). Library UI is designed now to accommodate this.

## Open questions

- Tab icons/names final pass (Home/Progress/Library/Settings working titles).
- **How declared rest / explicit skip persists.** Purely local UI state won't
  survive device switches or cache rebuilds. Candidate: a `WorkoutDocument`
  with `status: .skipped` for that schedule's routine (the status already
  exists) — cross-device and derivation-friendly. Decide before Phase 1 build.
  Related: distinguish *abandoned* (never started / walked away) from an
  *explicit skip*, possibly carrying an "excuse" ("sick day") that adherence
  treats as met. The board's past-day rows currently show an undifferentiated
  "Skipped" tag as the placeholder for this.
- Where goal/schedule editing lives: Settings vs. from the board (long-press
  a row / "edit plan" affordance) vs. both.
- Clean-sweep celebration + tomorrow-preview treatment (how loud, how playful).
- Default morning cutoff: fixed ~11 am vs. learned from the user's own
  distribution.
- Whether the watch should eventually show the Today board / row states
  (would need the computed projection pushed in the application context —
  cheap; revisit after Phase 1).
- How far the "practice tracker" identity goes (app is named *Workouts*;
  mindfulness fits the model today — does the branding follow eventually?).
