# TabataGo — iOS Tabata Workout App > Tabata interval training app for iOS + watchOS with HealthKit integration. ## Agent Context This project is part of the **Millian Team** — an AI agent engineering team. When working here, agents should load the relevant skill: - `senior-ios` — SwiftUI, Xcode, iOS/watchOS development - `senior-backend` — Supabase backend - `senior-devops` — Deploy infrastructure - `po-pm` — Product vision, specs, validation ## Tech Stack | Layer | Tech | |-------|------| | App | SwiftUI, iOS 26.0+ | | Watch | SwiftUI, watchOS 11.0+ | | Widget | WidgetKit, Live Activities | | Language | Swift 6.0 (strict concurrency) | | Architecture | MVVM, @Observable, AppState central | | Backend | Supabase (PostgreSQL, Auth, Storage) | | Subscriptions | RevenueCat 5.x | | Analytics | PostHog 3.x | | Health | HealthKit (heart rate, calories, workouts) | | Music | Apple Music integration + YouTube worker | | Build | XcodeGen (project.yml → .xcodeproj) | | Package Manager | Swift Package Manager | ## Project Structure ``` tabatago/ ├── tabatago-swift/ # Main Xcode project │ ├── project.yml # XcodeGen spec │ ├── Config/ │ │ ├── Secrets.xcconfig # API keys (not committed) │ │ └── Secrets.xcconfig.example │ ├── TabataGo/ # iOS App │ │ ├── App/ # App entry, state, root view │ │ │ ├── TabataGoApp.swift │ │ │ ├── RootView.swift │ │ │ └── AppState.swift │ │ ├── Views/ │ │ │ ├── Tabs/ # MainTabView, Home, Activity, Programs, Profile │ │ │ ├── Player/ # Workout player (PlayerView, NowPlaying) │ │ │ ├── Programs/ # ProgramDetail, BodyZone │ │ │ ├── Onboarding/ # Onboarding flow │ │ │ ├── Paywall/ # RevenueCat paywall │ │ │ ├── Complete/ # Workout completion screen │ │ │ ├── Settings/ # Settings, policies │ │ │ └── Components/ # Shared UI components │ │ ├── ViewModels/ # HomeVM, HealthVM, PlayerVM, PurchaseVM, MusicVM │ │ ├── Models/ # WorkoutProgram, WorkoutSession, UserProfile, etc. │ │ ├── Services/ # Supabase, HealthKit, Music, Audio, Purchase, Analytics │ │ ├── Theme/ # App theme │ │ ├── Utilities/ # Strings, Environment │ │ └── Resources/ # Assets, Localizable, entitlements │ ├── TabataGoWatch/ # watchOS App │ │ ├── Views/ # WatchRoot, WatchIdle, WatchActivity, WatchPlayer │ │ ├── Services/ # WatchConnectivity, WatchPlayerEngine │ │ ├── Complications/ # Watch face complications │ │ └── Resources/ │ ├── TabataGoWidget/ # iOS Widget + Live Activities │ ├── TabataGoTests/ # Unit tests │ └── TabataGoUITests/ # UI tests ├── supabase/ # Supabase config │ ├── schema.sql │ ├── seed.sql │ ├── setup-admin.sql │ └── migrations/ # SQL migrations (001-006) └── youtube-worker/ # Node.js worker for YouTube music ├── server.js ├── package.json └── Dockerfile ``` ## Dependencies (SPM) - **Supabase** 2.5+ — Backend SDK (Auth, Database, Storage) - **RevenueCat** 5.0+ — In-app purchases - **PostHog** 3.0+ — Analytics ## Features - Tabata/interval workout player with configurable timers - Pre-built workout programs by body zone - HealthKit integration (heart rate, calories, workout saving) - Apple Watch companion with real-time metrics - Live Activities + Dynamic Island - Music integration (Apple Music + YouTube) - RevenueCat subscriptions - Onboarding flow - Activity tracking & workout history ## Commands ```bash # From tabatago-swift/ xcodegen generate # Generate .xcodeproj open TabataGo.xcodeproj # Open in Xcode # In Xcode Cmd+R → Run on simulator Cmd+U → Run tests ``` ## Configuration - `Config/Secrets.xcconfig` contains API keys (not committed) - Template: `Config/Secrets.xcconfig.example` - Env vars: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, `REVENUECAT_API_KEY`, `POSTHOG_API_KEY` ## Current State - **Version**: 1.0 (build 2) — not yet released - **State**: App functional, needs finishing work - **Platforms**: iOS 26.0+, watchOS 11.0+ - **Requires**: macOS with Xcode 26+ to build ## Supabase Schema Tables: `profiles`, `workout_sessions`, `workout_programs`, `download_jobs`, `music_genre`, etc. See `supabase/schema.sql` and `supabase/migrations/` for full schema. ## Team Rules 1. **Swift Concurrency** — async/await everywhere, no completion handlers 2. **@Observable** — not @ObservableObject 3. **No force unwrap** — `guard let` always, never `!` 4. **SwiftUI only** — no UIKit unless unavoidable 5. **XcodeGen** — project.yml is source of truth, not .xcodeproj 6. **Secrets** — never commit Secrets.xcconfig 7. **French** — all user-facing strings in French (Localizable.xcstrings) ## Project Context - **User**: Millian LMX (CEO) - **Gitea**: https://gitea.1000co.fr/millianlmx/tabatago - **Supabase**: Managed instance (URL in secrets) - **App Store**: Not yet published