medOS ultra

Ever Patient Wallet

Patient-owned health-data integration: migration + edge function + miniapp UI + scanner widgets.

10 min read diagramsUpdated 2026-05-25docs/integrations/ever-patient-wallet.md

Status: Phase 0 — migration + edge function written, pending deploy. Phase 1 = miniapp UI + scanner widgets.

What it is: Integration between medOS-ultra and the Ever Sovereign Wallet mobile app for patient-owned health data. Unlike the room-stick integration (ever-wallet.md, which handles nurse-call alerts for nursing homes), this integration gives patients true ownership of their clinical files — X-rays, imaging, wound photos, scans — encrypted with keys only the patient controls.

Key principle: The patient’s private key is the ultimate decider. Hospitals are grantees, not owners.

Companion docs:

  • docs/integrations/ever-wallet.md — room-stick pairing (different use case)
  • docs/products/identity-vpn.md — VPN key custody (different layer)

1. Architecture

┌─────────────────────────────────────────────────────────────┐
│  Patient's device (phone/tablet)                            │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Ever Sovereign Wallet (mobile app)                   │  │
│  │  • X25519 keypair (patient-owned, never leaves device)│  │
│  │  • Ed25519 signing key (for grant envelopes)          │  │
│  │  • Generates per-file AES-256-GCM CEKs                │  │
│  │  • Wraps CEKs via nacl.box to hospital pubkeys        │  │
│  │  • Presents QR / NFC at clinic touchpoints            │  │
│  └────────────────────────┬──────────────────────────────┘  │
└───────────────────────────┼─────────────────────────────────┘
                            │ QR scan / NFC tap
                            │ (pubkey + grants + signature)
                            ▼
┌─────────────────────────────────────────────────────────────┐
│  medOS-ultra (this repo)                                    │
│                                                             │
│  ┌── PatientWalletScanner widget ────────────────────────┐  │
│  │  Mounted in: registration / bedside / nurse-assisted  │  │
│  │  Reads QR → POSTs to ever-patient-wallet-pair edge fn │  │
│  └──────────────────────┬────────────────────────────────┘  │
│                         ▼                                   │
│  ┌── Edge Fn: ever-patient-wallet-pair ──────────────────┐  │
│  │  1. Verify Ed25519 envelope signature                 │  │
│  │  2. Verify intake nonce (5-min, hospital-issued)      │  │
│  │  3. Upsert patient_wallet_identities                  │  │
│  │  4. Insert hospital_grants (sealed-box wrapped CEKs)  │  │
│  │  5. Consume nonce, audit, return hospital pubkey      │  │
│  └──────────────────────┬────────────────────────────────┘  │
│                         ▼                                   │
│  ┌── Supabase tables ───────────────────────────────────┐   │
│  │  patient_wallet_identities — wallet pubkey per patient│   │
│  │  hospital_grants — per-scope sealed-box CEK wraps     │   │
│  │  patient_drive_pins — IPFS CIDs (bucket A + B)        │   │
│  │  patient_wallet_intake_nonces — anti-replay tokens    │   │
│  │  patient_wallet_audit — append-only event log         │   │
│  └──────────────────────┬────────────────────────────────┘  │
│                         │ realtime subscription             │
│                         ▼                                   │
│  ┌── patient-drive-v2 miniapp ──────────────────────────┐   │
│  │  DynamicContentRenderer module on patient profile     │   │
│  │  • Bucket A tab: ops docs (stickers, barcodes, forms) │   │
│  │  • Bucket B tab: patient assets (imaging, wounds)     │   │
│  │  • Upload → encrypt → IPFS pin → grant record         │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                             │
│                    ever network replication (Bucket B only)  │
│                         │                                   │
└─────────────────────────┼───────────────────────────────────┘
                          ▼
          ┌──── Ever Network (company-operated → hospital consortium) ────┐
          │  Decentralized IPFS pin federation                           │
          │  Patient CIDs replicated across network nodes                │
          │  Patient wallet is the discovery mechanism (no directory)     │
          └──────────────────────────────────────────────────────────────┘

2. Two Buckets — Different Ownership, Same Pipeline

Bucket A: Hospital Operations Bucket B: Patient Assets
Examples Surgery stickers, barcodes, OR labels, internal forms, scanned consents X-ray, MRI, CT, wound photos, lab images, FHIR bundles
Encrypted with Facility DEK (AES-256-GCM) via existing health_history_key_store Wallet-issued CEK, sealed-box wrapped to hospital pubkey via hospital_grants
Key authority Hospital Patient
Pin scope Local IPFS only Local IPFS + ever network
Lifecycle Retention-policy purged Patient-owned forever
Wallet involvement None Required
Bucket assignment Declared at upload widget compile time (source_module config) Declared at upload widget compile time

The upload widget decides the bucket. Surgery sticker module = always A. Imaging upload = always B. Wound photo = always B. No user-facing toggle.


3. Files

File Purpose
infrastructure/medbase/migrations/20260525d_patient_wallet_identity.sql 5 tables + RLS + audit triggers + realtime publication
infrastructure/medbase/functions/ever-patient-wallet-pair/index.ts NaCl-based pairing handshake edge function
web/packages/service-kit/src/patient-wallet/PatientWalletScanner.tsx QR/NFC scanner widget (TODO: Phase 1)
web/packages/service-kit/src/patient-wallet/AssistedCreationLauncher.tsx Deep-link to wallet app for nurse-assisted onboarding (TODO: Phase 1)
web/packages/miniapps/patient-drive/ Patient drive v2 miniapp — DynamicContentRenderer module (TODO: Phase 1)
docs/integrations/ever-patient-wallet.md This file

4. Merge Contracts with the Wallet App

Four contracts between medOS-ultra and the Ever Sovereign Wallet mobile app. These must be agreed bilaterally.

Contract 1: QR / NFC Payload (Patient → Hospital)

The patient’s wallet app generates this payload and encodes it as a QR code or NFC NDEF record.

{
  "patient_id": "<local Mongo ObjectId>",
  "wallet_pubkey": "<base64 32B X25519>",
  "wallet_signing_pubkey": "<base64 32B Ed25519, optional if same as X25519>",
  "grants": [
    {
      "scope_kind": "bucket",
      "scope_value": "bucket_b",
      "wrapped_cek": "<base64 nacl.box ciphertext>",
      "wrapped_cek_nonce": "<base64 24B>",
      "cek_alg": "aes-256-gcm",
      "valid_until": "2027-01-01T00:00:00Z"
    }
  ],
  "envelope_signature": "<base64 Ed25519 detached sig over canonical payload>"
}

The canonical payload for signing is:

{
  "patient_id": "...",
  "facility_id": "...",
  "wallet_pubkey": "...",
  "intake_nonce": "...",
  "grants": [{ "scope_kind": "...", "scope_value": null, "cid": null, "valid_until": null }]
}

The intake_nonce and facility_id are injected by the hospital scanner widget after reading the QR. The wallet app does NOT need to know the hospital’s identity in advance — the nonce is provided by the scanner UI at scan time.

For nurse-assisted wallet creation when the patient doesn’t have the app yet.

everwallet://create
  ?return_to=https://medos.local/api/wallet-pair-callback
  &intake_nonce=<short-lived nonce>
  &hospital_pubkey=<base64 X25519>
  &hospital_label=<UTF-8 facility name>
  &patient_intake_id=<opaque reference>

The wallet app:

  1. Walks the patient through wallet creation (identity, biometric, etc.)
  2. Generates the keypair
  3. Creates an initial grant wrapping a CEK to the hospital_pubkey
  4. POSTs back to return_to with the Contract 1 payload

Contract 3: Grant Post-Back (Wallet App → Hospital, async)

For grants issued after the initial pairing (e.g., patient shares a specific file later).

POST {SUPABASE_URL}/functions/v1/ever-patient-wallet-pair
Content-Type: application/json

<same body as Contract 1, with a fresh intake_nonce>

The edge function is idempotent on (patient_id, wallet_pubkey) for identity, and additive for grants.

Contract 4: Revocation Broadcast (Wallet → Network → Hospitals)

When the patient revokes a hospital’s access:

  1. Patient wallet sends revocation to the ever network gateway
  2. Gateway fans out to affected hospitals
  3. medOS-ultra receives via ever-patient-wallet-revocations edge function (TODO)
  4. Sets hospital_grants.revoked_at + revoked_reason
  5. Hospital can no longer decrypt — but existing local pin stays for audit defensibility

This contract is network-layer mediated. medOS-ultra’s role is to honor the revocation, not to implement the broadcast protocol.


5. Data Model

patient_wallet_identities

One row per patient-wallet binding. Captured when patient presents QR/NFC.

Column Type Notes
id UUID PK
patient_id TEXT Local Mongo ObjectId
wallet_pubkey TEXT Base64 32B X25519
wallet_signing_pubkey TEXT Base64 32B Ed25519 (nullable if same as X25519)
leading_hospital_id TEXT Patient’s designated escrow hospital (nullable)
paired_via ENUM qr / nfc / nurse_assisted / bedside_scan
status ENUM active / rotated / revoked

hospital_grants

What the patient granted this hospital, per scope. Contains sealed-box-wrapped CEK.

Column Type Notes
id UUID PK
patient_wallet_id UUID FK → patient_wallet_identities
hospital_pubkey TEXT Which hospital X25519 pub the CEK was wrapped to
scope_kind ENUM all / bucket / folder / single_cid
scope_value TEXT e.g. bucket_b, folder:imaging
wrapped_cek BYTEA nacl.box ciphertext
grant_signature BYTEA Ed25519 sig by patient
valid_until TIMESTAMPTZ Null = no expiry
revoked_at TIMESTAMPTZ Set on revocation

patient_drive_pins

One row per uploaded file. CHECK constraint enforces bucket semantics.

Column Type Notes
bucket ENUM A (hospital ops) or B (patient assets)
cid TEXT IPFS content ID of ciphertext
source_module TEXT Which upload widget created this pin
facility_dek_id UUID FK Bucket A only → health_history_key_store
grant_id UUID FK Bucket B only → hospital_grants
pinned_local / pinned_ever BOOL Replication status

patient_wallet_intake_nonces

Short-lived anti-replay tokens, 5-minute window.

patient_wallet_audit

Append-only event log. Auto-populated by triggers on grant/pin lifecycle.


6. Pairing Flows

Flow A: Registration Desk

  1. Registration staff opens patient intake form
  2. `` widget is mounted in the form
  3. Staff clicks “Scan wallet” → hospital generates intake_nonce (5-min TTL)
  4. Patient opens Ever Wallet app → presents QR code
  5. Scanner reads QR → injects facility_id + intake_nonce → POSTs to edge fn
  6. Edge fn: verify sig, verify nonce, upsert identity, insert grants, return hospital_pubkey
  7. UI shows “Wallet paired” confirmation

Flow B: Bedside Doctor

Same flow, but `` is mounted in the bedside chart header. Doctor initiates the scan. paired_via = 'bedside_scan'.

Flow C: Nurse-Assisted Onboarding

  1. Patient doesn’t have the wallet app
  2. Nurse clicks “Create wallet for patient” in ``
  3. Deep-link opens: everwallet://create?return_to=...&intake_nonce=...
  4. If patient has a personal device: hand them the tablet / show QR to open wallet app
  5. If not: nurse helps on a shared device, patient completes onboarding
  6. Wallet app posts back to return_to with Contract 1 payload
  7. Edge fn processes as normal

7. Encryption Flow for File Upload (Bucket B)

Patient wallet (on device)                    medOS-ultra (hospital)
─────────────────────────                     ──────────────────────
1. Generate CEK (AES-256-GCM, 32B random)
2. Encrypt file: AES-GCM(CEK, IV, plaintext)
3. Wrap CEK: nacl.box(CEK, nonce,
   hospital_pubkey, wallet_privkey)
4. Sign grant envelope (Ed25519)
5. Present QR with: {wrapped_cek,
   nonce, scope, signature}
                                              6. Scanner reads QR
                                              7. POST to edge fn
                                              8. Verify sig + nonce
                                              9. Store grant (wrapped CEK)
                                              10. Upload ciphertext to IPFS
                                              11. Record pin in patient_drive_pins
                                              12. (async) Replicate to ever network

To decrypt (hospital reads an imaging file):

  1. Look up hospital_grants row by CID
  2. Unwrap CEK: nacl.box.open(wrapped_cek, nonce, wallet_pubkey, hospital_privkey)
  3. Fetch ciphertext from IPFS by CID
  4. Decrypt: AES-GCM.decrypt(CEK, IV || ciphertext)

To decrypt (patient on personal device):

  1. Patient’s wallet already has the CEK (it generated it)
  2. Fetch ciphertext from ever network by CID
  3. Decrypt locally

8. Relationship to Existing Systems

System Relationship
health_history_key_store (20260524d) Bucket A still uses facility DEK from this table. Bucket B supersedes with wallet-issued CEK.
health-history-cache edge fn Will be modified (Task #3) to consume wallet grants for Bucket B bundles instead of generating DEKs.
ever-wallet-pair edge fn Sibling, not replacement. Room-stick pairing for nursing home alerts is a separate use case.
patient-drive (service-kit) Will be replaced by patient-drive-v2 miniapp (Task #4). Old patient-drive stays for backwards compat until migration is complete.
ever_network_patient_identity (20260524d) Pre-existing cross-hospital identity mapping. patient_wallet_identities is the patient-presented equivalent — no directory lookup needed.

9. Security Model

  • Patient is the key authority. Hospital cannot decrypt without a grant. Grant is revocable.
  • Envelope signature prevents forgery. Every grant is Ed25519-signed by the patient’s wallet.
  • Intake nonce prevents replay. 5-minute TTL, single-use, facility-scoped.
  • Audit trail is append-only. All lifecycle events (pair, grant, revoke, pin, unpin) are recorded.
  • RLS = service_role only. No direct browser access to these tables.
  • Hospital pubkey is per-Supabase-project. Generated once, stored as env var. Rotation = new keypair + re-wrap existing grants (migration job).
  • Recovery is network-layer. Patient designates a “leading hospital” for airgapped key escrow. medOS-ultra stores the designation but does not implement the escrow.

10. Phased Rollout

Phase Scope Status
0 Migration + edge function + this doc Done
1 PatientWalletScanner + AssistedCreationLauncher + patient-drive-v2 miniapp Pending
2 Flip health-history-cache to consume wallet grants for Bucket B Pending — blocked on Phase 1
3 Ever network replication for Bucket B pins Pending — needs wallet app team coordination
4 Revocation edge function (ever-patient-wallet-revocations) Pending — network-layer dependency
5 Hospital consortium federation (hospitals join as peers) Future — company-operated first
Ask Anything