# Workouts App Requirements

## Overview
A workout tracking iOS app with an Apple Watch companion that helps users manage
workout splits, run sessions, and track progress. Data is stored as JSON
documents in the user's iCloud Drive and synced across devices.

## Platform Requirements
- iOS app (iPhone) — iOS 26+
- watchOS app (Apple Watch companion) — watchOS 26+
- Swift 6, strict concurrency; SwiftUI throughout
- Project generated with XcodeGen (`project.yml`)

## Persistence Architecture
- **iCloud Drive JSON documents are the sole source of truth.** One JSON file per
  aggregate root under the app's iCloud container `Documents/`:
  - `Splits/<ULID>.json` — a `SplitDocument` embedding its `[ExerciseDocument]`
  - `Workouts/YYYY/MM/<ULID>.json` — a `WorkoutDocument` embedding its `[WorkoutLogDocument]`
  - `Stubs/<ULID>.json` — soft-delete tombstones (30-day GC)
- **SwiftData is a rebuildable read-through cache.** App code never writes the
  cache directly: every save/delete writes a file; an `NSMetadataQuery` observer
  (and a connect-time reconcile) is the sole cache mutator. The cache is wiped and
  rebuilt on schema-version bump or iCloud-account change.
- **No CloudKit.** Container: `iCloud.dev.rzen.indie.Workouts` (CloudDocuments).
- **iCloud is required** — without it the app shows a blocking "iCloud Required"
  gate (no local-only fallback).

## Data Model
- **Split**: `id` (ULID), `name`, `color`, `systemImage`, `order`, timestamps;
  embeds Exercises.
- **Exercise**: `id`, `name`, `order`, `sets`, `reps`, `weight`, `loadType`
  (none/weight/duration), `durationTotalSeconds`, `weightLastUpdated`,
  `weightReminderTimeIntervalWeeks`.
- **Workout**: `id` (ULID), `splitID`/`splitName` (denormalized), `start`, `end?`,
  `status` (notStarted/inProgress/completed/skipped), timestamps; embeds logs.
- **WorkoutLog**: `id`, `exerciseName`, `order`, `sets`, `reps`, `weight`,
  `loadType`, `durationTotalSeconds`, `currentStateIndex`, `completed`, `status`,
  `notes?`, `date`.

Identity is a ULID string (stable across cache rebuilds). Duration is stored as
integer seconds.

## Apple Watch
The phone is the only device that touches iCloud Drive. The watch keeps its own
local SwiftData cache fed only by WatchConnectivity:
- Phone → Watch: pushes all splits + recent workouts (application context) on
  every cache change.
- Watch → Phone: sends an updated `WorkoutDocument` (keyed by ULID); the phone
  applies it through the file write path (the sole writer of iCloud Drive).
- Starting a workout on the phone launches the watch app into it via HealthKit
  (`startWatchApp(toHandle:)`); the watch runs an `HKWorkoutSession` for foreground
  runtime and ends it when no active workout remains. Requires the HealthKit
  capability and a one-time Health permission on both devices.

## Seed Data
Starter splits (Upper Body / Core / Lower Body) are generated on demand from the
bundled YAML exercise catalogs (`Workouts/Resources/*.exercises.yaml`) — never
auto-seeded. The catalogs also back the in-workout exercise picker.

## Features
- Create/edit/delete/reorder workout splits with custom colors and SF Symbol icons.
- Add exercises to splits (from the bundled catalog or manually); set default
  sets/reps/weight or a duration.
- Start a workout from a split; track per-exercise set/rest/done progress; mark
  complete/skipped; edit the plan during a session (mirrored back to the split).
- Weight-progression charts per exercise across past sessions.
- Apple Watch: starting a workout on the phone launches the watch into it; run the
  session from the wrist (HIIT-style work/rest cycles); changes sync back to the phone.

## Dependencies
- **Yams** — YAML parsing for the exercise catalogs.
- **IndieAbout** — About section in Settings (bundles LICENSE.md / CHANGELOG.md).

## Release
- TestFlight / App Store via `Scripts/release.sh` (xcodebuild archive +
  App Store Connect API upload; credentials in `.env.release`). The iOS archive
  embeds the watch app.
