-
-
Sign in as a synthetic donor, courier, recipient or operator. AI describes, humans verify, the backend enforces.
-
Operator dashboard: live server state for every donation. Unmatched food is held, never dispatched on a guess.
-
Claimed pickups: every field, from allergens to discard-by time, is donor verified before it can be claimed.
-
Item eligible for dispatch from operator dashboard
-
Rejected: the safety gate blocks unknown cold holding, missing temperature logs and unknown allergen cross-contact.
Inspiration
Commercial kitchens, caterers and campus dining halls end events with surplus prepared food, and community pantries need it, but the link between them is a phone tree. The hard part is not logistics, it is trust: what exactly is in the tray, was it held cold, and who may receive it. We built the part that is usually skipped: a workflow where the food's facts come from a person, a deterministic gate decides whether the donation may be offered at all, and the offer to a courier is time-limited and fair.
What it does
- An approved donor kitchen sends a photo of surplus food (by iMessage through Photon when the live line is on, or by web upload).
- An AI model writes an uncertain, editable guess (what it looks like, rough servings, allergens it might contain). It is labeled as a guess and never fills in a fact.
- The donor opens a one-time checklist and confirms every fact themselves: ingredients, all nine major allergens, cross-contact, how the food was prepared and held, temperature log, pickup cutoff.
- A deterministic gate returns
eligible,needs_revieworrejectedwith plain-language reasons. Unknown stays unknown. There is no "dispatch anyway" button. - An eligible donation is offered to one cold-capable courier at a time by message, with a deadline. The first valid
YES <code>wins. Late, duplicate or stale replies lose cleanly. - An operator dashboard shows the server's truth: status, reasons, offers, the audit timeline, and a clearly labeled simulated collected/delivered handoff.
The safety design (why this is not a food-safety claim)
- AI describes, humans verify, the backend enforces. A photo cannot show ingredients, hidden allergens, cross-contact or holding temperature, and we say so in the product.
- Fail closed. If temperature history, allergens, handling, recipient suitability or the pickup cutoff is unclear, the donation goes to human review. Invalid AI output falls back to the manual form.
- Separate concepts. Food safety facts and the donor's pickup cutoff are different things; unmatched (no courier available) is shown neutrally and never as a safety finding.
- Honest labels everywhere. A persistent banner shows which providers are real or fake; the simulated phone says it is not iMessage; handoff steps say they are simulated; all people and organizations are synthetic.
- This weekend prototype is not certified or reviewed for any food-safety regulation and must not be used for real food without qualified local review and partner agreements.
How we built it
- Next.js 16 (App Router), React 19, TypeScript, Tailwind 4 with shadcn/ui components.
- Zod-validated contracts shared by four developers working in isolated lanes (vision/intake, gate/matching/state, messaging/workflows, dashboard/integration) through typed fixtures and thin routes.
- Drizzle ORM over Postgres (Supabase) with an in-process PGlite store for tests and local runs.
- Gemini through
@google/genaibehind a vision adapter that has a real and a deterministic fake implementation; Photon behind a messaging adapter with a real and a fake implementation. Neither provider is ever silently replaced by its fake: failures surface in the UI. - Time-sensitive logic is designed around persisted UTC timestamps and server-side checks, never client timers. The UI renders what the server returns and computes no eligibility.
- Test-first development where practical (Vitest, Testing Library) and a documented secret scan before pushes to the public repo.
Challenges
- Making "unknown" a first-class value all the way from the form to the gate, so a missing answer can never read as "none".
- Keeping the AI useful without letting it become a source of facts (strict output validation, claim-word filtering, literal "unverified" flags).
- First-claim-wins and late-reply handling, and being honest about what has and has not been proven under concurrency.
- Coordinating four parallel branches against shared contracts without stepping on each other.
What we are proud of
- The refusal scene: an appetizing tray that the system correctly sends to human review with four plain-language reasons.
- The review culture: every lane's code is reviewed by another lane, and cross-lane review found real defects early (for example a possible phone-handle leak in CLI error output, over-eager opt-out matching, and a missing-cutoff gap). TODO(captain): before submitting, state only the ones that are merged and fixed on
main, with the PR numbers. - TODO(captain): add one verified number only (for example the final automated test count from the last green run on
main, with the commit).
Built With
- drizzle
- gemini
- next.js
- photon
- tailwind
- typescript
- zod