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

  1. An approved donor kitchen sends a photo of surplus food (by iMessage through Photon when the live line is on, or by web upload).
  2. 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.
  3. 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.
  4. A deterministic gate returns eligible, needs_review or rejected with plain-language reasons. Unknown stays unknown. There is no "dispatch anyway" button.
  5. 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.
  6. 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/genai behind 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

Share this project:

Updates

Submission history