Mariner Health
Planning documents

Draft ยท v0.1

Technical Architecture

1. Stack

  • Frontend + SSR: TanStack Start (React 19, Vite 7) on Cloudflare Workers.
  • Backend: TanStack createServerFn handlers โ€” no separate API service.
  • Data + Auth + Storage: Lovable Cloud (managed Supabase).
  • AI: Lovable AI Gateway (vision model for OCR/extraction, text model for insight synthesis).
  • Observability (planned): structured server logs, no PHI, hashes only for prompts/completions.

2. Tenancy model

The unit of tenancy is a family. A family owns one or more children. Access to a child is granted via caregiver_access rows keyed on (child_id, user_id, role) . Every row-level security policy on child-scoped tables calls a SECURITY DEFINER function has_child_access(_user, _child, _min_role)to avoid recursive policy issues.

3. Data model (initial sketch)

families        (id, name, created_by, created_at)
profiles        (user_id PK/FK auth.users, display_name, created_at)
caregiver_roles (id, name enum: owner | co_parent | caregiver | viewer)
caregiver_access(id, child_id FK, user_id FK, role FK, invited_by, expires_at?)
children        (id, family_id FK, given_name, dob, dx_tags[], created_at)
documents       (id, child_id FK, uploader FK, storage_path, mime, sha256, status)
document_pages  (id, document_id FK, page_number, text, embedding vector?)
timeline_events (id, child_id FK, event_date, kind, summary, source_doc_id?)
insights        (id, child_id FK, source_doc_id FK, conclusion, why jsonb,
                 next_step, confidence, created_by_model, prompt_hash, created_at)
consents        (id, granter_user_id, subject_child_id, grantee_user_id,
                 data_type, granted_at, revoked_at?)
audit_log       (id, actor_user_id, action, target_table, target_id,
                 child_id, ip, ua, created_at)

4. Service boundaries

  • Public routes (marketing, docs) โ€” SSR, no auth.
  • Authenticated routes โ€” under _authenticated/, gated by managed layout.
  • Server functions โ€” all writes, all AI calls, all cross-child logic. RLS enforced as the calling user via requireSupabaseAuth.
  • Admin operations (rare) โ€” dynamic import of the service-role client inside the handler, after a role check.
  • No Edge Functions. No custom Node servers.

5. AI pipeline

upload
  โ”‚
  โ–ผ
[server fn] OCR page-by-page      โ”€โ”€ vision model, min-necessary excerpts
  โ”‚
  โ–ผ
[server fn] structured extraction โ”€โ”€ strict JSON schema (Zod)
  โ”‚
  โ–ผ
[server fn] insight synthesis     โ”€โ”€ prompt template versioned + hashed
  โ”‚
  โ–ผ
insights row  { conclusion, why, next_step, confidence, prompt_hash }
  โ”‚
  โ–ผ
InsightCard   refuses to render if any field is missing

Prompts and completions are not stored raw. We persist a prompt_hash and the model id so we can reproduce behavior without keeping PHI in logs. The source-document citation lives in insights.why and links back to the exact document_pages row.

6. Integrations (future, not MVP)

  • SMART on FHIR for Epic MyChart, Athena, Cerner โ€” per-user OAuth via App User Connectors.
  • Calendars: Google, Apple (CalDAV), Microsoft โ€” appointment context for prep packets.
  • School: IEP PDFs first; direct SIS connectors later where APIs exist.
  • E-fax / secure email inbound for records intake from providers.

7. Authentication & 2FA

  • Primary sign-in: email + password, plus Google OAuth via the Lovable broker.
  • Two-factor authentication (required for all accounts): a second factor at every sign-in and before sensitive actions (adding a caregiver, exporting records, changing consent).
  • Supported second factors:
    • TOTP authenticator app (Authy, 1Password, Google Authenticator) โ€” the preferred factor, works offline.
    • SMS one-time code โ€” delivered via a BAA-covered SMS provider; rate-limited and locked to the enrolled phone number.
    • Email one-time code โ€” fallback when SMS is unavailable; delivered via a BAA-covered transactional email provider.
    • Recovery codes โ€” one-time-use, generated at enrollment, shown once.
  • SMS autofill on iOS / macOS Safari (Apple's SMS Passcodes AutoFill): the 2FA input uses <input autocomplete="one-time-code" inputMode="numeric" />, and every SMS OTP message follows the domain-bound format Apple requires, e.g.:
    Your Mariner Health code is 123456.
    
    @marinerhealth.app #123456
    The trailing @domain #code line binds the code to our domain so iOS suggests it above the keyboard on the correct site only, matching the Apple docs. Android's Chrome/WebOTP API is supported by the same input attribute and message shape.
  • Session hardening: short-lived access tokens, rotating refresh tokens, idle timeout (15 min) with a re-auth prompt, and device sign-out from Account settings.

8. Environments

  • Planning (now): no Cloud enabled, no data.
  • Demo: Cloud enabled, synthetic data only, banner on every screen.
  • Production: gated on BAA execution, penetration test, and a written HIPAA risk assessment.