Project Overview & Full-Stack JS Setup

Food Tracker (React + Express)

Chapter 1 · Project Overview & Full-Stack JS Setup

This is one of four courses building the exact same app in four genuinely different architectures — Food Tracker (FastAPI), Food Tracker (Django), and Food Tracker (React + Firebase) are its siblings. Every one of them scans a barcode, tracks a use-by date, and alerts you before something goes to waste. This course's own angle is the most straightforward of the four to describe, and one of the most common in real professional practice: the same language, front and back.

What the App Actually Does

Before any architecture talk, the shared spec every course in the quartet is building toward:

  • Scan a barcode with a phone or webcam camera, look it up against Open Food Facts (free, open, no API key) to fetch the product's name and details automatically.
  • Record a use-by date for the item, and see it flagged once it's expiring soon.
  • Keep a full history of every item ever added — some still active with a real expiry date, some already marked used with no expiry date at all — searchable in real time as you type, so re-adding something you've bought before is fast.
  • Look up recipes via TheMealDB (also free, no key) that use ingredients close to expiring.

A weekly meal planner is explicitly out of scope for all four courses — named future work, not something any of them will build.

Why "One Language, Both Ends" Is a Genuine Case, Not Just Convenience

Food Tracker (FastAPI) and Food Tracker (Django) both write their backend in Python and their frontend in JavaScript — a real, unavoidable context switch every time work crosses that boundary. This course removes that switch entirely: React on the client, Node running an Express server, both written in JavaScript. The practical payoffs are concrete, not just aesthetic:

  • One shared data format, natively. JSON is JavaScript's own native object literal syntax on both sides — no serializing a Python dict into JSON on the way out and parsing it back into a dict on the way in. A JS object built on the server and a JS object consumed on the client are structurally the same kind of thing.
  • One package ecosystem. npm serves both halves of the app — no separate pip/requirements.txt world to keep in sync with a separate JS toolchain.
  • One team, fewer context switches. A developer fixing a bug that spans "what the API returns" and "how the UI renders it" can stay in one language the entire time.

The honest caveat, named here so it doesn't need repeating later: sharing a language doesn't automatically mean sharing types across the network boundary. Without extra tooling (shared TypeScript interfaces, a schema-validation library), the Express server and the React client can still silently drift out of sync about what shape a response actually has — this course builds without that extra layer, matching its own realistic scope, and names the tradeoff honestly rather than pretending "same language" solves it for free.

The Architecture Contrast, Precisely

CourseBackendWhere business logic lives
Food Tracker (FastAPI)A FastAPI process you write, run, and deployPython code, running on a server you manage
Food Tracker (Django)A Django process you write, run, and deployPython code, running on a server you manage
Food Tracker (React + Express)A Node/Express process you write, run, and deployJavaScript code, the same language as the frontend, running on a server you manage
Food Tracker (React + Firebase)No server process you write or deployMostly Security Rules (configuration) plus a few Cloud Functions
The one-sentence version of this whole course
In the other three Food Tracker courses, the frontend and backend are written in two different languages (Python/JS) or the backend barely exists as code at all (Firebase). In this one, the exact same language runs on both sides of the network boundary — the genuine "full-stack JavaScript" case, with its real benefits (one data format, one package ecosystem) and its one honest limitation (no automatic type-sharing across that boundary without extra tooling this course doesn't add).

Scaffolding the Project

Two separate processes, kept in one repository: a Vite-powered React client, and a plain Express server.

# the React client npm create vite@latest client -- --template react cd client && npm install # the Express server, in a sibling folder cd .. mkdir server && cd server npm init -y npm install express cors dotenv

A minimal server, confirming the setup works end to end before any real feature exists:

// server/index.js import express from "express"; import cors from "cors"; const app = express(); app.use(cors()); app.use(express.json()); app.get("/api/health", (req, res) => { res.json({ status: "ok" }); }); const PORT = process.env.PORT || 3001; app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
CORS is not optional during development
Vite's dev server runs on its own port (typically 5173); Express runs on its own (3001 here). From the browser's perspective, those are two different origins, and without cors() the browser blocks every request from the React app to the Express API outright. This is a genuinely common first-hour stumbling block for anyone new to a two-process full-stack setup — worth understanding now rather than debugging blind later.
Auto-restart the server during development
node --watch server/index.js (built into modern Node, no extra dependency needed) restarts the Express process automatically on every file save — the same convenience Vite already gives the React side for free.

Where This Course Is Headed

Data modeling and Express API routes, barcode lookup, the camera-scanning React component (shared almost verbatim with Food Tracker (React + Firebase)), the add-item flow, expiry alerts, item history with live search, marking items used, recipe lookup, cross-cutting state management once every feature needs to talk to every other feature, deployment, and a capstone tying every chapter into one complete, working app.

Hands-On Exercises

Exercise 1

In one sentence, state this course's own core architectural claim. Then explain what specifically breaks (or doesn't break) that claim once network requests are involved, using this chapter's own honest caveat about type-sharing.

📄 View solution
Exercise 2

Explain why the React dev server and the Express server being on different ports causes a real problem in the browser, and what cors() actually does about it.

📄 View solution
Exercise 3

Using this chapter's own comparison table, explain how this course's "where business logic lives" column differs from both Python siblings' own column and from the Firebase sibling's own column.

📄 View solution

Chapter 1 Quick Reference

  • The shared app — barcode scan (Open Food Facts) → expiry tracking → alerts → searchable history → recipe lookup (TheMealDB); no meal planner
  • This course's own throughline: the same language, JavaScript, runs on both the client and the server
  • Real payoff: one native data format (JSON), one package ecosystem (npm)
  • Honest limit: same language does not mean shared types across the network without extra tooling this course doesn't add
  • Setup: Vite scaffolds the React client; a plain Express server with cors() and express.json() is the backend
  • Next chapter: Data Modeling & Express API Routes