Making the invisible workload of healthcare visible.
CareLoad is a patient-centered healthcare research prototype. It does not diagnose disease or prescribe treatment — it helps patients and healthcare teams understand the practical workload of managing healthcare: medications, appointments, travel, cost, information, monitoring, time, and caregiver dependence.
This repo implements all eight phases of the master prompt's build plan end to end — the full patient loop, the professional side, and the polish pass — with real (not superficial) implementations verified by 52 automated tests plus live manual end-to-end runs.
- Backend (
backend/): FastAPI + SQLAlchemy + Alembic + JWT auth.- Auth:
POST /auth/register,POST /auth/login— patients and healthcare professionals both register through the same endpoint with arolefield. - Patient:
GET /patients/me,GET /patients/me/dashboard - Check-ins:
POST /checkins,GET /checkins - Friction map:
GET /friction-map,GET /friction-map/history - Insights:
GET /insights - Care team:
POST /patients/me/care-team(a patient links a professional by their account email — explicit, patient-initiated consent, not admin-assigned),GET /patients/me/care-team - Professional dashboard:
GET /professionals/me/patients(only patients who've linked them),GET /professionals/me/patients/{id}/friction-mapand/friction-map/history— a professional who isn't linked gets a 403, never the data - A real AI Analysis Engine (
AIAnalysisService+MockAIProvider): deterministic, offline, keyword/sentence-level extraction that maps free text and selected areas to the eight friction dimensions, always with a stored evidence excerpt. Every raw provider output is schema- validated (Pydantic) and passed through a safety filter before anything is persisted — if either check fails, the check-in is still saved but shown as "we couldn't analyze this check-in yet," never fabricated. - Trend detection: compares each new assessment against the
patient's prior one for that dimension and generates
NEW_FRICTION,INCREASING_FRICTION, orPERSISTENT_FRICTIONinsights. - 48 passing pytest tests, including the master prompt's exact acceptance scenario (travel + financial detection with evidence) and the professional-access authorization boundary.
- Auth:
- Frontend (
frontend/): Next.js 16 + TypeScript + Tailwind 4.- Landing page; login/register with a patient-vs-professional role picker; role-aware routing (each role is redirected away from the other's pages, not just hidden from nav)
- Patient dashboard (real data, recent-insights preview, nav to every other page)
- Check-in flow (
/check-in): a 4-step progressive stepper (overall difficulty → areas → free text → review) that submits to the real AI pipeline and shows results — summary, Friction Map, insights, and an "areas to discuss" note — inline. - Healthcare Friction Map (
/friction-map): all 8 dimensions at a glance; tapping one opens an evidence panel showing exactly what was reported and why it was classified that way. - History (
/history): a timeline of every check-in with its per-dimension results, plus a running list of trend insights. - Profile (
/profile): a patient manages their care team here — add a professional by email, see who currently has access. - Professional dashboard (
/professional/dashboard+/professional/patients/[id]): a professional sees only patients who've linked them, with a read-only Friction Map + history per patient — no editing, no raw check-in text beyond the quoted evidence. - Fully typed API client, auth context, React Query, RHF + Zod.
- 22 passing Vitest + React Testing Library tests covering the API
client's error handling, the
cn()utility, role-based routing, and key components (Button,FrictionDimensionCard).
cd backend
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # defaults to a local SQLite file, no setup needed
alembic upgrade head
uvicorn app.main:app --reload --port 8000API docs available at http://localhost:8000/docs once running.
cd frontend
npm install
cp .env.local.example .env.local
npm run devVisit http://localhost:3000.
docker compose up --buildThis starts Postgres, the FastAPI backend (:8000), and the Next.js frontend (:3000).
CareLoad deploys as two separate Vercel projects from this one repo — one
for frontend/, one for backend/. Both have been verified to build and
serve correctly through the exact entrypoints Vercel uses.
Vercel's backend functions are stateless serverless containers — SQLite (the local dev default) won't persist between requests there, so you need a real hosted Postgres. Any managed Postgres works; Neon and Supabase both have generous free tiers built for serverless (connection pooling, scale-to-zero). Copy the connection string — you'll need it in step 2.
- In Vercel, "Add New Project" → import this repo → set Root Directory
to
backend. - Vercel auto-detects
backend/vercel.json, which points the build atapi/index.py(a one-line re-export of the FastAPI app inapp/main.py— Vercel's Python runtime serves ASGI apps like FastAPI directly, no adapter needed). - Set these environment variables on the project:
Variable Value DATABASE_URLyour Postgres connection string from step 1, in SQLAlchemy form: postgresql+psycopg2://user:pass@host/dbJWT_SECRET_KEYa long random string — generate with openssl rand -hex 32ENVIRONMENTproductionCORS_ORIGINS["https://your-frontend-project.vercel.app"]— must be valid JSON, including the brackets and quotes, since it's parsed as a JSON list. You can widen this later once you know your frontend's final domain.AI_PROVIDERmock - Deploy. Before (or right after) the first deploy, run the Alembic
migrations against that same
DATABASE_URLfrom your machine:(Production intentionally does not auto-create tables on startup — seecd backend DATABASE_URL="postgresql+psycopg2://user:pass@host/db" alembic upgrade head
ARCHITECTURE.md— so this step is required once, and again after any future migration.) - Confirm it's live:
https://your-backend-project.vercel.app/healthshould return{"status": "ok", ...}.
- "Add New Project" → import this repo again → set Root Directory to
frontend. Vercel auto-detects Next.js, no config file needed. - Set one environment variable:
Variable Value NEXT_PUBLIC_API_URLhttps://your-backend-project.vercel.app(no trailing slash) - Deploy.
NEXT_PUBLIC_*variables are inlined into the client bundle at build time, so if you change this later you need to redeploy, not just update the variable. - Go back to the backend project's
CORS_ORIGINSvariable and set it to this frontend's real URL, then redeploy the backend so the browser is actually allowed to call it.
- The
MockAIProvider(Phase 4, not yet built) needs no API key and works identically in serverless. A real LLM provider would need its own API key added as a Vercel environment variable and read server-side only — the master prompt's "never expose API keys to the frontend" rule holds regardless of host. - Cold starts: the first request to an idle backend function will be a bit
slower while it boots and opens a DB connection (mitigated by
NullPool+pool_pre_ping, which avoid holding onto dead connections between cold starts — seeapp/database/session.py). - This is a research prototype, not a HIPAA-eligible deployment. Don't put real patient data in it, on Vercel or anywhere else.
# Backend (48 tests)
cd backend
source venv/bin/activate
pytest
# Frontend (22 tests)
cd frontend
npm testSee backend/.env.example and frontend/.env.local.example. Notably:
DATABASE_URL— defaults to local SQLite; set to a Postgres URL for docker-compose / production.JWT_SECRET_KEY— change this before deploying anywhere real.AI_PROVIDER—mock(default, deterministic, no API key needed) oranthropiconce the real AI Analysis Engine is implemented.
- A real LLM-backed
AIProvideralongsideMockAIProvider, gated byAI_PROVIDER=anthropic(or similar) with the API key read server-side only — the interface (AIProvider.generate) is already there for it, seeARCHITECTURE.md. - Professional-side notifications (a professional currently has to be told their email out of band and check their own dashboard — there's no "you've been added to a care team" email).
- Admin role: modeled in the database (
UserRole.ADMIN) but has no routes or UI — out of scope for a patient/professional-focused MVP.
CareLoad does not diagnose disease, predict disease, prescribe treatment,
recommend medication changes, or make emergency decisions. Every friction
classification the system ever shows must be traceable to evidence the patient
actually reported — never an unexplained score. See ARCHITECTURE.md for the
AI safety rules this is enforced by.