A personal training journal for iPhone, iPad & Apple Watch.
repo: StepTrackerTCA
A multi-platform fitness ecosystem built with SwiftUI and The Composable Architecture. What started as a TCA learning exercise (inspired by Sean Allen's course) grew into a modular system of two products sharing one foundation of local Swift packages.
Build a personal-yet-extensible fitness platform that:
- Treats your workouts as data you own — local-first SQLite storage with CloudKit sync across your devices, no third-party cloud or analytics.
- Bridges the consumer-grade Apple Health ecosystem with serious training tools — CrossFit / strength athletes get per-WOD score tracking, training readiness, per-exercise analytics, heart-rate zones and on-device AI plan parsing, all on top of HealthKit primitives.
- Scales from solo athlete to group gym — the same domain core powers a personal iPhone+Watch journal and an iPad coach dashboard that monitors a roomful of athletes over Bluetooth.
- Demonstrates modern iOS architecture in production — strict Swift 6 concurrency, TCA composition, Strategy/Client patterns, modular SPM packages with CloudKit sync, and a SwiftUI "view facade" convention separating structure from styling.
A personal companion for tracking workouts, recovery and progress.
- Live workouts with heart-rate tracking — a single session started and controlled
from either iPhone or Apple Watch, mirrored across both devices
(
HKWorkoutSession+WatchConnectivity). Watch-primary and iPhone-primary modes with BLE HR sensor support (iOS 26 native). - Plan scanning with on-device AI & OCR — photograph a training plan / WOD and the app extracts the exercises. Three pluggable strategies (Strategy pattern): Apple Foundation Models, Claude API, and a custom parser.
- Post-workout structured journal — per-WOD score tracking (forTime / AMRAP / forLoad / completed), per-exercise weight & reps with set-by-set detail for strength workouts, scaling levels (Rx / Scaled / Rx+), PR flag.
- Heart-rate zones with selectable formula — choose from Tanaka, Nes, Gulati, Fairbarn (sex-aware) or Classic. Per-workout snapshot freeze: your zones stay consistent even if you change the formula later.
- Analytics & trends — training readiness score, heart-rate zone distribution, weight trend, training volume per category, per-exercise PR / 1RM analytics.
- Manual entry escape hatch — re-attach a plan to a workout retroactively from History, useful when the live save flow misses (e.g., WatchConnectivity drops).
- Health journal — weight, goals, HealthKit metrics, home-screen widgets and Live Activities for active workouts.
Drop the screenshot files into
docs/screenshots/using the names below and they'll render automatically.
The dashboard adapts to your daily recovery state. Two snapshots from the same week:
Left: low-readiness day (RHR / HRV / sleep flagged red). Right: high-readiness day (full green across all metrics).
Every metric on the Today dashboard (HRV, sleep, activity, RHR, ...) opens its own detail screen with a weekly chart, score points, average and an explanation of what the metric means and how to act on it:
Same layout per metric: current value + status + score chip on top, weekly chart with average dashed line in the middle, contextual explanation on the bottom.
Training volume bars per workout category + weight trend line (left), exercise balance pie per movement type (right).
Workout history list, per-workout detail with heart-rate over time (color-coded by zone) + zone distribution, full WOD plan with warmup / WOD / cooldown and per-exercise scaling.
During a workout the app streams heart rate in real time from either a paired
BLE chest strap (Polar H10, Wahoo TICKR, etc. via HKLiveWorkoutDataSource)
or Apple Watch (HKWorkoutSession mirroring channel — reliable even when
WatchConnectivity is unreachable). The whole UI repaints to the current zone
color so the athlete sees their intensity at a glance:
Four representative tiers across the full spectrum — Resting (gray, 38%), Fat Burning (green, 65%), Threshold (orange, 85%) and Anaerobic (red, 95%). Live BPM, %maxHR, calories, session avg/max and elapsed time — all updated per HR sample, no polling.
A trainer-facing iPad app for running group fitness classes — think a tablet on the gym wall.
- Create & run group classes with class templates, schedule, and live monitoring.
- Real-time heart-rate of every participant — one tile per athlete, color-coded by heart-rate zone, so the coach sees the whole room at a glance.
- Join via QR + BLE peer-to-peer — a participant scans a QR code and streams heart rate to the iPad over Bluetooth, no cloud required (custom GATT protocol + peer identity handshake with reconnect grace).
- Class history with charts — per-athlete HR ranges (BarMark per minute, color gradient by zone), donut for class-wide time-in-zones, calories distribution, long-press scrub with RuleMark + popup.
- Connection robustness — BLE peer resume on reconnect (no duplicate athletes when someone runs outside class range), file logging exportable through the Files app.
Top: live class monitoring — one tile per athlete (left) and full class with QR pairing for new participants (right). Bottom: post-class analytics — combined HR over time, per-athlete BarMark ranges by minute, and stacked time-in-zones.
The two apps share a foundation of local Swift packages, so domain logic, models and services are reused across iPhone, iPad and Watch:
| Package | Responsibility |
|---|---|
| SharedModels | Shared domain models, enums and constants (multi-platform) |
| HealthHub | HealthKit, WatchConnectivity, Bluetooth, workout parsing, training calculations |
| AppDatabase | SQLite persistence (SQLiteData) with CloudKit sync — users, sessions, exercise logs, HR snapshots |
| PeerMirror | BLE peer-to-peer heart-rate streaming (host/peer, GATT, peer identity) |
| Commons | Shared utilities, no external dependencies |
- TCA composition — reducers for all business logic,
@Presents+ Destination for navigation,@Shared(.appStorage)for persisted preferences,IdentifiedArrayOfforEachfor collections of child features.
- Client / Service boundary —
@DependencyClientstructs as injectable boundary,Service(actor/class) as implementation hidden behind the client. Reuse via@Dependency(\.xxxClient). - Strategy pattern — pluggable algorithms (HR formulas, workout parsers, sex-aware variants) selected at runtime via enum + dispatch.
- Snapshot pattern — per-workout HR formula freeze: snapshot table captures
(maxHR, formula, age, sex)at workout-end so historical zones never shift when preferences change. - View Facade — SwiftUI views describe structure at the top (composition of
named subviews), implementation at the bottom (
private var/private funcblocks). Makes diffs reviewable and snapshot-testable per section. - SOLID — single responsibility per reducer / per cell / per service, open-closed for extensions (e.g., adding a new HR formula = one struct + one enum case + one switch branch).
- Swift 6 strict concurrency —
Sendableeverywhere,@Shareddeclared inside closures in TCAliveValueto avoid captured-var concurrency errors, AsyncStream multicast pattern for streams with multiple subscribers (view remount, TCA cancel).
Language & platform: Swift 6.2 · iOS 26 / iPadOS 26 / watchOS 26 · Xcode 16+
(strict concurrency mode, defaultIsolation(MainActor.self)).
Apple frameworks: SwiftUI · HealthKit · WatchConnectivity · CoreBluetooth · WidgetKit · ActivityKit · Charts · Vision (OCR) · MapKit · CloudKit · App Intents.
Third-party (Point-Free): TCA (Composable Architecture) · SQLiteData · SwiftNavigation · Dependencies · Sharing · IdentifiedCollections · CasePaths · Perception · IssueReporting.
AI: Apple Foundation Models (on-device) · Anthropic Claude API (claude-sonnet-4-5).
About / Origins — how this project started
Inspired by Sean Allen's course, I decided to transform his application by adapting it to the TCA (The Composable Architecture) framework. The goal of this project is to gain a deep understanding of TCA by implementing modern design patterns and creating a modular, scalable application following best practices.
The results of my work and the details of each step can be found on GitHub: StepTrackerTCA. This project is not only a technical exercise but also an exploration of possibilities and best practices in the context of modern iOS app development.
- Sean Allen — Sean's GitHub profile
- Sean Allen Teachable — Portfolio Project — direct link to the course
- 📌 Feature Diagram: FeatureDiagram.md
- 📌 Database Schema: CoreDataDiagram.md (historical name — uses SQLiteData)
- 📌 Task backlog: TASKS.md