← Projects

MedVault

Photograph a paper lab report and get a searchable, lifelong medical record. Gemini extracts the structured data; Supabase keeps it private to you.

2026SoloNext.jsTypeScriptSupabaseGemini
MedVault screenshot

Medical history in Bangladesh lives on paper. Reports get lost, tests get repeated, and the next doctor starts from zero. MedVault turns a photo of a report into a structured row you can search across every field, including individual test names.

The home screen above is the vault: every report as a card with its type, the hospital or doctor, the date, how many tests were pulled out of it, and a one-line summary. The search box at the top matches against all of it, so "thyroid" finds a report whose only mention of thyroid is a TSH row buried in a results table.

How it works

  1. You photograph a lab report or prescription (JPG/PNG).
  2. The original image goes to a private Supabase Storage bucket. The browser only ever receives short-lived signed URLs, never a public object URL.
  3. Gemini reads the image and returns structured JSON: report type, date, doctor/hospital, a plain-language summary, and a table of test results.
  4. The row lands in Postgres behind row-level security, so only the owner can read it.
  5. The dashboard lists and searches across every field.

Extraction failure is not data loss: the row is still saved with extraction_status: "failed" and the original image is always retrievable.

A lipid panel report in MedVault: summary, extracted results with normal ranges and status badges, original scan

A single report. Each extracted test carries its value, unit, the reference range from the report, and a status badge (Normal, Watch, High) computed from that range. The original scan sits alongside for verification.

Trends

Once two or more reports contain the same test, MedVault charts it. The Trends page finds every test name that repeats across your vault and draws its values over time with the reference range, so a slowly climbing ESR or a cholesterol reading that has drifted over three years is visible at a glance rather than buried in three separate PDFs.

The Trends page charting test values over time

Trends. Anything that appears in two or more reports gets a line.

Decisions

  • Supabase for auth, storage and database. One free-tier project covers all three, and RLS means the security model is a database policy rather than application code I have to get right on every route.
  • Service-role key only on the server. Uploads use the admin client so they bypass storage policies; signed URLs are minted with the caller's session client so the read policy is enforced. The admin client is imported from exactly one server-side file.
  • Mock extraction switch. USE_MOCK_EXTRACTION=true skips the live Gemini call and returns a fixed record, so the demo survives a quota outage.
  • Deletion is real deletion. Deleting the account removes every report file from storage and the account record. No soft delete, no retention.

The profile page: vault size, the encryption note, account actions and the delete zone

Profile: how many reports are stored, how they are stored, and the one button that removes all of it.

Not a medical device. MedVault stores and organizes records; it does not diagnose or give medical advice.