Here you go — paste-ready Markdown:
Inspiration
Citizen-collected stream observations are inconsistent and error-prone: volunteers describe the same water differently, misclick, or misunderstand scientific terms — and the resulting data is hard to share because it lacks standard structure and provenance. Researchers can't tell how much to trust a record. We wanted to build the tool that makes volunteer data both better and believable: guidance at capture time, honesty about what AI can and can't see, and health-data standards baked in from the start rather than bolted on.
What it does
StreamTrust walks a volunteer through a stream check on their phone — place and time, photos, six plain-language questions about the water, review, submit. An AI vision model suggests what it sees in each photo with visible evidence and self-reported confidence, and it abstains (can't tell from a photo) whenever it can't judge — smell is never guessed from a picture. The human accepts or overrides every value; validation rules flag inconsistencies (a strong smell next to pristine water gets a "double-check?"); and the finished assessment exports as a FHIR R4 Bundle that validates with zero errors, recording the AI suggestion, the human decision, and whether they agreed — provenance in the record itself. An insights page turns those recorded interactions into a real AI-vs-human agreement dashboard.
How we built it
Single Next.js app (App Router, TypeScript strict, Tailwind v4) with a clean domain → server → UI layering. Drizzle ORM over libSQL — a local file in dev, Turso in production, same driver. A provider interface fronts the AI (NVIDIA NIM vision model in production, Gemini alt, deterministic mock for tests/CI so CI never needs a live key). FHIR resources are hand-mapped and validated against the public HAPI server, with custom CodeSystems generated from the same vocabulary file the UI renders. Vitest for unit/integration, Playwright for end-to-end plus automated axe accessibility checks, GitHub Actions CI, hosted on Vercel. The visual identity — a "waterproof field notebook" with creek-wash paper, serif field numerals, and ripple motifs — was designed from the subject matter, not a template.
Challenges we ran into
- Trustworthy AI output. Free-tier vision models truncate, ramble in markdown instead of JSON, omit indicators, and confidently guess smells from photos. We answered with forced structured output, a normalizer that unconditionally abstains on odor, a retry policy, and an eval harness that caught real bugs (fence-stripping, prose extraction).
- A clean FHIR pass. Our project-defined CodeSystems and extensions will never resolve on a public validator. We kept them (they carry the provenance story), documented the expected warnings, and added generated resource narratives to silence everything silenceable: 27 warnings → 12, 0 errors throughout.
- Honest numbers. Our eval set is 22 team-labelled photos — a smoke test, not a benchmark. Agreement measured 34–50% across runs, and we report the range, never the better number.
- Real-world gremlins. An empty dev database that failed silently, an OOM test machine that killed browsers mid-run, rate limits discovered by testing too enthusiastically — each diagnosed with evidence, not guesses.
Accomplishments that we're proud of
A Bundle that validates with 0 errors; an AI with 0 guessed smells across 44 evaluated images; a full assessment that runs on a phone with a screen reader; and an agreement dashboard computed from real human/AI interactions rather than made-up stats.
What we learned
That abstention is a feature, not a failure — the most trustworthy thing our AI does is say "I can't tell." That standards compliance is earned one validator warning at a time. And that the unglamorous work (migration checks in health endpoints, db:migrate scripts, error messages that say the true reason) is what separates a demo from a deployment.
What's next
Calibrated confidence once real override data accumulates, blind-first answering to study anchoring bias, photo object storage with FHIR Media, pushing bundles to live health servers, and offline mode for low-connectivity fieldwork.
Built with an AI coding agent under human direction. Demo data is synthetic and labeled as such.
Built With
- axe-core
- citizen-science
- drizzle-orm
- fhir
- geo-location
- github-actions
- hapi-fhir
- hl7-fhir-r4
- libsql
- next.js
- node.js
- nvidia-nim
- playwright
- pnpm
- react-hook-form
- tailwind-css
- turso
- typescript
- vercel
- vitest
- zod
Log in or sign up for Devpost to join the conversation.