hoangsonww/SymptomSync-Health-App

FHIR Export (meds / appointments / logs) + Provider-share session

Open

#34 opened on Oct 30, 2025

 (1 comment) (0 reactions) (1 assignee)TypeScript (8 forks)auto 404
documentationduplicateenhancementgood first issuehelp wantedquestion

Repository metrics

Stars
 (30 stars)
PR merge metrics
 (PR metrics pending)

Description

Summary

Let a user click “Share with my doctor” and generate a short-lived, read-only view of their key health data (medications, appointments, health logs) and optionally download it as FHIR (R4) so it can be dropped into an EHR. This makes SymptomSync way more useful in real clinical convos (“here’s my meds + symptoms for the last 30 days”).


Why

  • Right now data lives in Supabase and is great for the user, but it’s awkward to hand to a provider.
  • Clinics speak FHIR. We don’t have to support all of it — just the minimum useful resources.
  • Short-lived, scoped sharing avoids “give me your login” nonsense.

Scope (MVP)

  1. Export surface

    • Meds → MedicationStatement
    • Appointments → Appointment
    • Health logs (symptom, mood, severity, notes) → Observation
  2. Period filters

    • “Last 7 days”, “Last 30 days”, “All”
  3. One-click download

    • JSON bundle (FHIR R4 Bundle of the above)
  4. Share session

    • Create a row like shared_sessions in Supabase:

      • id (uuid)
      • user_id
      • expires_at
      • scopes (e.g. ["meds","appts","logs"])
    • Generate share URL: /share/{id}

    • RLS: row must be readable without auth but only if now() < expires_at

  5. Read-only page

    • Next.js route that shows meds / appts / logs nicely
    • Banner: “Data shared by {first_name} – expires in X minutes”
    • No edit/delete buttons

Non-Goals (for later)

  • Bi-directional FHIR (import)
  • OAuth2 / SMART on FHIR
  • HIPAA BAA story

Data model changes (Supabase)

create table public.shared_sessions (
  id uuid primary key default gen_random_uuid(),
  user_id uuid not null references auth.users(id) on delete cascade,
  scopes jsonb not null default '["meds","appts","logs"]'::jsonb,
  expires_at timestamptz not null,
  created_at timestamptz not null default now()
);

RLS (outline):

  • policy 1 (owner): user can insert/select own sessions
  • policy 2 (public read): using (expires_at > now()) for anonymous to read just the shared session + related views (you can materialize a view that joins meds/appts/logs filtered by user_id and time window)

UI/UX

  • In Dashboard → “Export & Share”

    • [Select period] [Select data types]
    • Button: Generate share link
    • Button: Download FHIR JSON
  • After generate → toast with copyable link


FHIR Mapping (minimal)

  • MedicationStatement

    • status: active
    • subject: Patient/{user_id}
    • effectiveDateTime: medication_reminders.start_time
    • medicationCodeableConcept.text: medication_reminders.med_name
    • dosage.text: medication_reminders.dosage
  • Appointment

    • status: booked
    • start/end: from appointment_reminders
    • description: notes / provider
  • Observation

    • status: final
    • code.text: SymptomSync Log
    • valueString: symptom / mood / notes
    • effectiveDateTime: log timestamp

Dump them into:

{
  "resourceType": "Bundle",
  "type": "collection",
  "entry": [ /* MedicationStatement | Appointment | Observation ... */ ]
}

Acceptance Criteria

  • User can generate a share link that works in an incognito window.
  • Link stops working after expires_at.
  • User can download a FHIR JSON file; file contains at least 1 resource per existing record in the chosen window.
  • Docs updated (README.md + maybe ARCHITECTURE.md) to explain data flow + RLS note.
  • Jest test for the FHIR serializer (given mock meds/logs → expect valid bundle shape).
  • Lint & CI pass.

Nice-to-have (later)

  • Add ICS to the same screen so providers can drop appts into their calendar.
  • Add a “share again” button to re-extend expiry.
  • Add field-level masking (don’t include notes if user unchecks it).

Contributor guide