Capstone: A Complete, Working Food Tracker
Food Tracker (React + Express)
Chapter 12 · Capstone: A Complete, Working Food Tracker
Marcus keeps his own household pantry tracked with the app this course just spent eleven chapters building — one Express process, one SQLite file, one React app, all deployed and running for real. What follows is one ordinary session with it.
Marcus scans a carton of milk. Chapter 4's useBarcodeScanner hook decodes the barcode entirely client-side, then handleDetected calls fetch("/api/lookup/...") — Chapter 3's route, which checks barcode_cache first and falls back to a live Open Food Facts call, caching whatever it finds.
Chapter 5's AddItemForm pre-fills the name and category from that lookup. Marcus sets the expiry date and submits; the client-side check catches an empty name instantly, but it's Chapter 3's own POST /api/items route — the real gate, by construction — that actually validates and inserts the row, exactly as Chapter 5's finding-box promised it would.
Chapter 6's alerts route surfaces the milk once it's within three days of its (consistently YYYY-MM-DD-formatted) expiry date — a plain SQL range query needing no index at all, at this app's own realistic scale.
Wanting to check if he's bought a particular brand of yogurt before, Marcus types "yog" into the search box. Chapter 7's useDebouncedSearch waits for him to stop typing, then hits the search route's native, case-insensitive LIKE match — no shadow field required, unlike the Firebase sibling's own nameLower.
The milk gets finished. Chapter 8's PATCH /api/items/:id/use — never a plain link — sets status='used', stamps used_at, and clears expiry_date to NULL, guarded by AND status = 'active' so accidentally clicking twice changes nothing the second time.
Marking the milk used calls Chapter 10's notifyChange() — one call, with no knowledge of who's listening. The alerts dashboard disappears the milk from its own list; the recipe suggestions (Chapter 9) stop counting it as an expiring ingredient — both react on their own, independently, exactly as Chapter 10's whole redesign was built to make possible.
With chicken and spinach both nearing expiry, Chapter 9's Promise.all fan-out queries TheMealDB for both concurrently — not sequentially, a real, honest advantage over the Django sibling's own admitted sequential cost — merging and sorting the results by how many expiring ingredients each recipe actually uses.
Marcus's session happens against a real deployment: Express serving the built React app via Chapter 11's own catch-all SPA route (registered after the API routes, never before), pm2 keeping the process alive, nginx terminating HTTPS in front of it, and the SQLite file sitting on a volume that survives a redeploy.
Chapter Attribution
| Step | Chapter(s) applied |
|---|---|
| 1 — Scanning | Chapter 4 (camera scanning), Chapter 3 (lookup route + barcode_cache) |
| 2 — Adding the item | Chapter 5 (AddItemForm, server-side validation), Chapter 2 (schema, INSERT) |
| 3 — Expiry alert | Chapter 6 (date range query, YYYY-MM-DD discipline) |
| 4 — Search | Chapter 7 (debounce hook, native LIKE) |
| 5 — Marking used | Chapter 8 (PATCH route, active-only guard, expiry_date=NULL) |
| 6 — Automatic updates | Chapter 10 (ItemsContext, notifyChange, version) |
| 7 — Recipe suggestion | Chapter 9 (Promise.all fan-out, recipe_cache, relevance sort) |
| 8 — Real deployment | Chapter 11 (static serving, SPA fallback, pm2, TLS, persistent volume) |
Promise.all turning JavaScript's async-first design into a genuine performance advantage, and Chapter 10's Context-based coordination solving a real cross-feature problem with nothing more than React's own built-in tools. None of these payoffs required abandoning the honest limits named along the way — no ORM, no shadow-field-free search that scales infinitely, no free HTTPS — this course's own throughline was never "JavaScript solves everything," just "the same language, both ends, is a real and specific advantage where it actually applies."
Hands-On Exercises
Trace Step 6 in detail: explain exactly what markUsed calls, and how that one call results in both the alerts dashboard and the recipe suggestions updating, without either being called directly.
📄 View solutionPick any two steps from Marcus's session and explain how each one depends on at least two earlier chapters working together, not just one chapter in isolation.
📄 View solutionExplain why this course's honest scope note names the same missing multi-user ownership model as Food Tracker (Django)'s own capstone, while explicitly contrasting that against Food Tracker (React + Firebase), which did build real per-user authentication.
📄 View solutionChapter 12 Quick Reference — Course Complete
- 8 steps, 11 prior chapters — one continuous, realistic session with the finished, deployed app
- This course's own throughline, closed out: the same language, both ends, is a real, specific advantage — not a universal solution
- Honest scope note: no meal planner, no offline/PWA, no multi-user ownership model (same gap as the Django sibling), TheMealDB matching remains best-effort, no automated tests/CI
- Food Tracker (React + Express) is now complete — 12/12 chapters