Skip to content

Architecture

Eric Slutz edited this page Aug 20, 2026 · 7 revisions

Architecture

PumpSync is split across a frontend-only iOS repository and a backend-only ASP.NET Core repository. The iOS app owns Apple-platform behavior and App Store assets. The backend owns service tokens, Tandem Source integration, sample normalization, subscription verification, self-hosting, demo mode, storage, and deployment.

Repository Boundary

Repository Owns Does not own
eslutz/PumpSync SwiftUI iOS app, HealthKit writes, StoreKit subscription UI, App Store/TestFlight metadata, screenshots, app legal docs, iOS CI. Backend API projects, Dockerfiles, container publishing, Azure infrastructure, backend deploy workflows, data deletion tooling.
eslutz/PumpSync-Backend / PumpSync.backend ASP.NET Core API, Docker/Compose self-hosting, Azure Container Apps infrastructure, backend deploy workflows, data deletion tooling, hosted/demo operations. iOS app UI, App Store screenshots, iOS project generation, iOS signing.

If an iOS change requires backend behavior or URL changes, update the backend repository first, then update project.yml and iOS docs with the resulting base URL.

iOS App

The iOS app is a SwiftUI application generated from project.yml with XcodeGen. The current source layout is:

PumpSync/
  Resources/       Info.plist, asset catalog, generated app metadata
  Sources/App/     App entry point, app services, diagnostics, shortcuts
  Sources/Auth/    Backend session and access-token handling
  Sources/Health/  HealthKit permission and sample writes
  Sources/Networking/
                   API models and PumpSync backend client
  Sources/Storage/ Keychain, sync metadata, imported-sample ledger
  Sources/Sync/    Sync coordinator, initial import range, background scheduling
  Sources/Tandem/  Tandem credential form/store/value types
  Sources/UI/      Onboarding, sync, settings, privacy, developer/support views

The app uses:

  • SwiftUI for UI.
  • HealthKit for insulin and carbohydrate writes.
  • StoreKit for PumpSync subscription purchase and restore.
  • Keychain for Tandem credentials.
  • BackgroundTasks for daily sync scheduling.
  • MetricKit, OSLog, and local diagnostics for support-safe diagnostics.
  • App Intents for shortcuts.

Backend API

The backend is a plain ASP.NET Core API packaged as a container image. The current source layout is:

src/
  PumpSync.Api/            HTTP API host
  PumpSync.ApiContracts/   Request/response contracts
  PumpSync.Application/    Use cases, mapping, normalization, validation, security
  PumpSync.Domain/         Domain models for auth, billing, samples, sync, Tandem, users
  PumpSync.Infrastructure/ Storage, Tandem, synthetic demo, App Store, secrets, options
tests/
  PumpSync.Tests/
tools/
  PumpSync.DataDeletionRequest/
infra/
  bicep/
  environments/

Hosted service, self-hosting, and synthetic demo use the same API contracts and normalization pipeline.

Sync Flow

  1. The app requests a short-lived session challenge and enrolls a protocol 3 device proof: App Attest for hosted mode, or a Secure Enclave P-256 signature for self-hosted mode.
  2. Hosted enrollment binds the App Attest proof to the protocol domain, operation, /api/v1 path, installation ID, request ID, issuedAt, SHA-256 challenge digest, App Attest key ID, and SHA-256 digest of the signed transaction JWS. The backend fails closed if proof, local receipt validation, request binding, or freshness checks do not pass; optional Apple risk assessment remains observe-only.
  3. For a newly attested hosted key, the backend stores the locally validated App Attest receipt encrypted and may submit it to Apple for a categorical risk outcome used only for service security and fraud prevention. The optional Apple risk exchange is currently disabled, is observe-only when enabled, and does not block an otherwise valid session. Self-hosted enrollment uses the Secure Enclave proof and never enters this Apple-dependent path.
  4. The backend issues a one-hour access token and rotating refresh credential. The plaintext refresh credential remains in the iOS Keychain; the backend stores only a verifier and public-key/replay state.
  5. The user saves Tandem credentials in the iOS Keychain.
  6. During validate or sync, the app sends Tandem credentials — plus the device's IANA time zone, which the backend uses to anchor Tandem's pump-local timestamps — to the configured backend over HTTPS.
  7. The backend validates the active session family and authenticates with Tandem Source, or with the synthetic demo authenticator in demo mode.
  8. The backend clamps the requested history window to Tandem's ~14-day availability boundary and reports the effective window in the response; the app surfaces a data-gap notice when the clamp discarded part of the requested range.
  9. The backend normalizes Tandem pump events into insulin and carbohydrate samples with window-independent external ids (open trailing basal segments are withheld until a later pump event closes them) and returns them to the app.
  10. The app writes authorized samples to Apple Health, records only the confirmed writes in its duplicate-prevention ledger, and advances its sync watermark from the server-reported effective window.
  11. The app and backend discard raw Tandem events and normalized samples after the response/write path completes.

Hosted Routing

project.yml defines hosted API base URLs. Public documentation should describe the environment split without publishing live hosted endpoint values.

Purpose Scheme Configuration Hosted environment
Local Xcode install PumpSync Debug Nonprod hosted API
TestFlight upload PumpSync Beta Beta Nonprod hosted API
App Store release PumpSync Release Production hosted API

Debug and Beta use Apple's sandbox StoreKit environment. Release uses the production App Store transaction environment.

Storage

Hosted mode uses Azure Table Storage for operational state:

  • Subscription entitlements.
  • Installations and installation lookups.
  • Sync attempts.
  • Rate-limit buckets.
  • App Store notification idempotency.
  • Renewable device sessions: refresh-token verifiers, device public keys, counters, expiries, and revocation state.
  • Encrypted App Attest receipts and categorical fraud-risk outcomes for active hosted keys. They are deleted on an applicable data-deletion request and automatically no later than 30 days after the key becomes inactive.
  • Redacted audit/data-deletion events.

Self-host and demo mode use SQLite by default. Self-host users are responsible for backing up and protecting their SQLite database and TLS/reverse-proxy credentials.

Clone this wiki locally