# 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/.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/.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?).