The Mac app tracks what you do on your computer. The iOS app tracks everything else — your body, your movement, and your environment. Together, they give xeve the full picture of your day.
Six HealthKit Data Types
The iOS app queries Apple HealthKit for six data types:
- Steps — daily step count with hourly breakdown
- Active Energy — calories burned from movement
- Resting Energy — basal metabolic calories
- Heart Rate — continuous samples from Apple Watch or paired monitors
- Sleep — sleep stages (awake, core, deep, REM) with duration
- Workouts — exercise sessions with type, duration, and energy
HealthKit queries are async and surprisingly slow. Fetching a week of heart rate data (which can be thousands of samples) takes 2-3 seconds. The app batches all six queries in parallel and caches results in SwiftData for offline access. Each sample has an isSynced flag — the app syncs to Supabase in the background and only uploads new data.
Home, Work, and Check-Ins
The location system does not track GPS coordinates continuously — that would destroy battery life. Instead, it uses iOS significant location changes to detect transitions between known places.
You set your home and work coordinates once. The app then detects when you arrive at or leave either location and logs the transition. Everything else is a "check-in" — a named place you visited, with arrival time and duration.
Location data feeds into the web dashboard's Locations page, where you can see time spent at home vs. work, commute patterns, and a timeline of your movements. The correlation engine uses location data too — it can tell you whether working from home correlates with more or less productive coding sessions.
Three Widget Types
The app includes a WidgetKit extension with three widget types:
- Small: Productivity Score — a single number showing your focus percentage for the day, with a color-coded ring (green/yellow/red)
- Medium: Today Overview — screen time, coding time, steps, and heart rate in a compact four-metric layout
- Lock Screen — three inline variants showing productivity score, coding time, or step count on your lock screen
Widgets share data with the main app via App Groups. A SharedData module writes a JSON file to the shared container, and the widget extension reads it. The widget timeline refreshes every 15 minutes (Apple's minimum).
SwiftUI + Combine Gotchas
Two SwiftUI patterns worth noting for anyone building a similar app:
Nested ObservableObjects do not propagate changes. AppState contains HealthKitManager, LocationManager, and SyncManager as nested objects. When HealthKitManager updates its published properties, the views observing AppState do not re-render. The fix: forward .objectWillChange events from child to parent using Combine's .sink.
Numeric text transitions are free polish. Adding .contentTransition(.numericText()) to any Text view that displays a number gives you a smooth digit-rolling animation when the value changes. It takes one line and makes the app feel significantly more polished.
What Feeds the Dashboard
All iOS data syncs to the same Supabase tables the web dashboard reads. Health samples go to health_samples, location events to location_logs, and daily summaries get computed by the daily rollup edge function. The web dashboard does not know or care whether the data came from an iPhone, an Apple Watch, or a manual entry — it is all the same schema.