Skip to main content
The ORbit iOS app is a SwiftUI companion that connects to the same Supabase backend as the web application. It uses MVVM architecture with a repository pattern.
The iOS app shares the same database, same RLS policies, and same data model as the web app. Any database migrations created for the web automatically apply to iOS since both platforms use the same Supabase project.

Stack

  • UI: SwiftUI, iOS 18+
  • Architecture: MVVM + Repository pattern
  • Backend: Supabase (same project as web app)
  • Auth: Supabase Auth with Keychain token storage

Architecture pattern

View (SwiftUI) → ViewModel (@Observable/@MainActor) → Repository → SupabaseClient

Critical rules

  • Only Repositories import PostgREST — Views and ViewModels must never import it
  • All ViewModels are @MainActor — never use DispatchQueue.main.async
  • Use @EnvironmentObject injection, not .shared singletons
  • Pass accessToken and facilityId as init params

Project structure

ORbit/
├── ORbitApp.swift              → App entry point
├── ContentView.swift           → Root TabView
├── Theme.swift                 → Design tokens
├── Core/
│   ├── Auth/AuthManager.swift  → @Observable auth state
│   ├── Network/SupabaseClient.swift
│   └── Error/ORbitError.swift
├── Models/                     → Codable data structs
├── Repositories/               → Supabase query layer
├── ViewModels/                 → Business logic + state
├── Features/
│   ├── SurgeonHome/            → Surgeon dashboard
│   ├── Cases/                  → Case list + detail
│   ├── Rooms/                  → Room status board
│   ├── Profile/                → User profile
│   └── DeviceRep/              → Device rep tray tracking
└── Components/                 → Shared UI components

Feature parity matrix

FeatureWebiOS
Case managementFull CRUDView + milestone recording
Room status boardFullFull
Surgeon home dashboardFullFull
Device rep tray trackingFullFull (differentiator)
ORbit ScoreClient-side calculationPlanned (via surgeon_scorecards)
Analytics dashboards6 viewsNot started
Block schedulingFullNot started
Admin featuresFullNot planned for mobile

Shared principles

The iOS app follows the same platform-wide principles as the web app:
  • Same database, same RLS — identical Row-Level Security policies
  • Milestone v2.0facility_milestone_id is the FK, never milestone_type_id
  • Median over average — all analytics use median, not mean
  • Soft deletes — filter is_active = true on soft-delete tables
  • Facility scoping — every query filters by facility_id

Auth flow

User → Login → Supabase Auth → Session token → Keychain → RLS enforces access
Token storage was migrated from UserDefaults to Keychain for security.

Critical development rules

These rules prevent common bugs in the iOS codebase. Violating them causes runtime issues.
  • Only Repositories import PostgREST — Views and ViewModels must never import it directly
  • All ViewModels are @MainActor — never use DispatchQueue.main.async
  • Use @EnvironmentObject injection, not .shared singletons
  • Pass accessToken and facilityId as init params to repositories

FAQ

Yes. Both apps use the same Supabase project. Point the iOS app’s configuration to your Supabase URL and anon key. RLS ensures data isolation per facility.
The scoring engine currently runs client-side in TypeScript. The iOS plan is to read from the surgeon_scorecards table (pre-cached results) rather than re-implementing the scoring algorithm in Swift.

Next steps