Sail Tracker
Type: Software Status: In Progress Deadline: TBD Created: 2026-06-02
What is this?
A training and practice tool for sailors. GPS speed, heading, locked-heading deviation (shift indicator), CSV logging, heat maps, and session replay. Used between races and during practice sessions — explicitly not designed for use during a race. Sibling app to race-timer (see race-timer decision 002 for the split rationale).
Motivation
The features that are unsafe under one-design class rules during racing — GPS speed, heading, logging — are genuinely useful for training and post-session debrief. Splitting them into a separate app sidesteps every class-rules issue and produces a cleaner product on both sides. The original single-app scope kept colliding with ILCA Rule 22(d) and the various class-permission gates; this app exists to give those features a clean home.
What does success look like?
- Sailors reach for it during practice sessions and after races to review the day’s data
- Post-session debrief surface (heat maps, speed-by-heading, splits, replay) that’s better than RaceQs and the rest of the field
- Paid App Store listing; cross-promote from race-timer
Technical
- Stack: SwiftUI, watchOS 10+, iOS 17+. Paired iOS + watch distribution model (decision 010 reverses decision 005’s standalone-watch technical claim — Apple’s tooling no longer accepts standalone watchOS uploads). User-facing the iPhone surface is a 35-line “Open the app on your watch” placeholder; the watch app is the whole product. Sessions reach race-timer’s iPhone Training tab (M-3 home, per decision 005) via shared CloudKit container.
- Repo:
~/projects/sail-tracker/—djt53/sail-tracker(private) on GitHub - Build: XcodeGen →
SailTracker.xcodeproj;./build.sharchives theSailTrackerCompanioniPhone scheme (embeds watch viaembed: true) → uploads to App Store Connect - Team:
8HZAKZWFY8(Enigma Studio Inc., shared with race-timer) - Bundle IDs:
- iPhone (carrier):
com.davidtingle.sailtrackerwatch— the ASC record’s primary bundle ID - Watch (embedded):
com.davidtingle.sailtrackerwatch.watchkitapp
- iPhone (carrier):
- CloudKit container:
iCloud.com.davidtingle.sailtracker(linked to watch App ID) - ASC API key:
V79677KG8Aat~/.appstoreconnect/private_keys/AuthKey_V79677KG8A.p8(Issuerb72fb376-0438-48ac-bf15-59c4dd7b3928, team-wide, also used by race-timer) - Deploy target: App Store (iPhone listing with companion watch app, internally). v0.1 free (parity timer only); paywall arrives in M-2 gating GPS features
- Intended users: sailors looking to improve — overlap with race-timer demo, different use mode
- Debrief surface: lives as a Training tab inside race-timer’s iPhone app (M-3), not in sail-tracker’s iPhone carrier
Spec snapshot (v1.0 — see decisions/)
- Parity baseline (decision 002): feature-equivalent to race-timer’s watch app, with one deliberate omission — no BLE fleet-sync receive. Class-rules guardrail: sail-tracker is never to be used in a real race.
- Inherited watch features: pre-start countdown (5-4-1-Go default, 10-5-1-Go big-boat, 3-2-1-Go dinghy), sync nudge ±1s + sync-to-nearest-gun, haptic schedule (30/10/5/4/3/2/1/Go), race-state handling (Reset / Postpone / Resume / Abandon), race flag lookup (14 flags),
WKExtendedRuntimeSessionso timer + haptics survive screen sleep, polished UI (OLED black, SF Pro Compressed Heavy clock, tap-reveal action menu). - Visual divergence (decision 004): identical chassis, electric blue accent (~
#0099FF-range) replacing race-timer’s electric yellow throughout. - Code sharing (decision 003): fork-and-strip from race-timer into new repo. No shared package or monorepo until divergence patterns warrant.
- App shape (decisions 005 + 010): paired iPhone+watch for distribution (forced by Apple removing standalone watchOS uploads from every tool — see decision 010), but watch-first for product (iPhone surface is a 35-line “Open the app on your watch” placeholder). Debrief surface still lives in race-timer’s iPhone Training tab (M-3), with session sync via CloudKit. Decision 005 marked Superseded by 010.
- Unique training features (post-parity): GPS speed (live + recorded), heading / COG, locked-heading deviation (shift indicator), magnetic compass, session recording on watch; debrief (heat maps, replay, CSV export) inside race-timer iPhone.
Milestones
| ID | Name | State | Notes |
|---|---|---|---|
| M-1 | Watch v1.0 — parity with race-timer minus broadcast, electric blue | Hardware-verified (build 11) | Build 11 installed via TestFlight; first interactive hardware test on 2026-06-10 returned “everything worked pretty well :)” across the M-1 timer surfaces (home → countdown → race-state transitions). Granular per-surface enumeration not done; broad-positive confirmation. Haptic pattern (gun = burst vs .failure) deferred for on-water feel test. Remaining M-1 items reduce to listing copy + privacy labels + Apple Feedback Assistant report on the standalone-watchOS upload regression (low priority). |
| M-2 | Training features on watch | In progress (heading redesign per decision 011 shipped, build 12 on TestFlight) | Foundation + UI shell (sessions 1-3, see prior log entries) shipped Countdown/Speed/Heading paged container, GPS trial gate, paywall, persistence. Session 4 (2026-06-10): heading page redesigned end-to-end per decision 011 after first hardware feedback. CompassDial reversed from north-up + locked-up-rotation to heading-up frame (arrow fixed at top, bezel rotates with COG, GMT-style 30°/10° ticks, brand-anchor blue accent pulled OUT of the rotating layer). Center number turns green (lift) / red (header) signed by current tack, outside a ±3° dead-band. S/P tack chip lower-right (single tap → flipTack() + .click haptic); auto-tack detector (rate 15°/s sustained 3s, delta 70°-170°, 30s cooldown) inside appendTrackPoint. Numbers-only speed glance lower-left replaced the originally-asked mini sparkline. Tack persisted on SessionRecord + each TrackPoint for per-tack debrief splits. 11 new tests (72/72 pass). Build 12 archived + uploaded. Remaining: hardware verify the redesign + battery audit (3 suspects flagged: GPS always-on accuracy, scenePhase/.background ExtendedSession teardown, HKWorkoutSession .ended verification) + heading smoothing EMA + sparkline 3-min window. See decisions 006-011 + spike-findings + battery-audit-001. |
| M-3 | Debrief surface as race-timer iPhone Training tab | Future | Lives in race-timer’s iPhone app, not standalone. Reads sail-tracker watch sessions from shared CloudKit container. Map track, speed-by-heading, heat maps, replay, CSV export. Requires coordination with race-timer M-2.1 CloudKit work. |
| M-4 | Interop with race-timer | Future | Shared identity (Sign in with Apple), cross-launch from race-day → training debrief, race-context inheritance. |
| M-5 | Social / fleet comparison | Future | Compare tracks across sailors. Deferred — solo vs social decision still open. |
Open questions
- Solo training tool, or fleet/social training tool (compare with friends)?
- Interop with race-timer — shared identity? Cross-launch? Or fully independent ecosystems?
- Monetization model — defer until race-timer paywall (decision 003) reveals what works.