Introduction — Full-Stack Web Development

The Course, the One App, and the Spine

web development
full-stack
introduction
modern web
Lecture
Author
Affiliations

Université de Toulon

LIS UMR CNRS 7020

Published

2026-10-14

Abstract

Orientation for the course: we anchor everything to a single working full-stack app, fullstack-minimal-app — a React + Vite + Tailwind frontend, a Node.js/Express REST backend, and a MySQL database. The 18-hour spine is understand → extend layer-by-layer → capstone (the review layer); a compact web-architecture refresher and a Docker Compose / devcontainer environment round out the session.

About the Lecturer

Emmanuel BRUNO — Associate Professor, University of Toulon (Information System Laboratory, LIS — UMR CNRS 7020).

Contact: course Discord channel (preferred for quick questions) · email emmanuel.bruno@univ-tln.fr.

Course Overview

One app, extended layer by layer, into a full review layer.

Goal. By the end of the course you can build and reason about a complete full-stack web application — a modern React frontend talking to a Node.js/Express REST API backed by MySQL — and you can keep extending it.

Audience. L3 / 3rd-year undergraduate students. A programming background is assumed. If you come from PHP, your server-side instincts (routing, sessions, database queries) transfer directly; we apply them in the JavaScript ecosystem.

Shape: 18 hours = 6 sessions × 3 h. Each session is a mix of short lecture and hands-on work, always on the same application.

Important🤖 AI-first, Day 1

We start with an AI assistant (e.g. GitHub Copilot, Cursor, or similar) and LLMs before refreshing the fundamentals. They accelerate learning and mirror how professional teams work — but they never replace understanding the code. You will always be able to explain what you shipped.

Learning objectives 🎯

  • Build a complete full-stack app with React (frontend), Node.js/Express (backend), and MySQL (persistence).
  • Design and consume a RESTful API that connects the frontend to the backend and the database.
  • Apply client–server architecture to a working product catalog you extend yourself.
  • Use AI tools effectively to develop faster while understanding every line you generate.

Evaluation

  • Final quiz (individual, 30 minutes at the start of Session 5, before capstone wiring).
  • Team project (group): code + README.md + LLM_Usage.md + video demo — due 1 month after the last session.

The One App

TipThe one-app spine

fullstack-minimal-app is the only running example in this course. We do not build a toy app and throw it away, then start another. We take one real, working application and grow it. Understand it → extend it layer by layer → capstone: build the review layer.

What it is. A minimal but complete, production-minded full-stack application:

Frontend (React + Vite + Tailwind)
          ↓ HTTP/JSON
Backend (Node.js + Express)
          ↓ SQL
Database (MySQL 8.0)

It is deliberately small enough to read end to end, but complete enough to be real: a product catalog with categories, pagination and filtering, full CRUD, input validation, SQL-injection protection, health monitoring, and Docker-first development.

The working catalog you will extend. You start from code that already runs. The frontend is a React single-page app; its source is small and fully inspectable:

  • frontend/src/main.jsx — the React entry point (mounts the app).
  • frontend/src/App.jsx — the main component: client-side routing and a backend health check.
  • frontend/src/components/ProductList.jsx — the paginated product listing.
  • frontend/src/components/ProductDetail.jsx — the single-product view.
  • frontend/src/components/ProductForm.jsx — the create / edit form.
  • frontend/src/styles.css — Tailwind imports.

The backend exposes a REST API (/api/products with GET/POST/PUT/DELETE, /api/categories, and a /health endpoint) that reads and writes a MySQL database (minimal_app_db, seeded by db/init.sql).

Your job is to extend this catalog — never to rebuild it from scratch. Every lesson adds one layer on top of what is already working.

The Spine

The course is one arc, in one order: understand the shipped catalog → add the review layer session by session → capstone. The product catalog is the given foundation — you never rebuild it. The course adds a review layer to an existing product catalog, milestone by milestone (S0–S5); connecting that layer to the external review source (the shipped scraper-service) is the home stretch, done after the course — never wired inside the 18 hours.

flowchart TD
    A[🧭 S0: Understand the shipped catalog] --> B[🃏 S1: Static review card]
    B --> C[📋 S2: Vanilla-JS review list]
    C --> D[🧩 S3: React review components]
    D --> E[🧰 S4: Express review routes]
    E --> F[🏁 S5: Capstone: MySQL reviews table]
    F -. home stretch (1 month) .-> G[🔗 scraper-service integration]
    style F fill:#90EE90

Session What you build — the review layer on the shipped catalog
S0 Understand the shipped catalog — the working app and its dev environment (this lecture).
S1 Static review card — one review, presented by hand in HTML/CSS.
S2 Vanilla-JS review list — render and filter reviews from a local JSON file.
S3 React review UI — ReviewCard, ReviewList and ReviewForm built in React, fed with sample data.
S4 Express review routes — GET /api/products/:id/reviews (plus the aggregate endpoint) over an in-memory store.
S5 🏁 Capstone: the MySQL reviews table — full frontend → API → DB wiring, the integration seam for the shipped scraper-service (connected in the home stretch).
WarningThe home stretch is not in the 18 h

Wiring the shipped scraper service into a multi-source review aggregator is the one-month home stretch you do after the course, as part of the team project. During the 18 hours you build the review layer yourself; in the home stretch you connect it to the scraper-service/ shipped with fullstack-minimal-app.

Git in Brief

You will work in a git repository for the whole course. Git — a version control system — is the safety net: every piece of work you commit can be inspected, reverted, or restored, and it doubles as a record of how the app grew. You do not need to master git to take the course, but you do need to be comfortable with the small daily loop below.

  • Repository (repo) — the project folder tracked by git; here, the course app fullstack-minimal-app.
  • Commit — a dated, named snapshot of the files you choose to save; the atomic unit of history.
  • Branch — an independent line of work you can extend without disturbing the main line.

The daily loop is edit → stage → commit → push: you change files, mark the ones you want to keep (git add), record them as a commit, and push the commit to the remote repository so it is backed up and shared.

flowchart TD
    A[Edit a file] --> B[Stage it: git add]
    B --> C[Commit: git commit]
    C --> D[Push: git push]

How this course uses GitHub. The course lives in a single repository. At the end of each session, the work you produced is committed to the course repo — your progress is the commit history, not a pile of loose files. This also closes the AI-first loop: the generate → verify → integrate cycle always ends with a commit, so AI-assisted code enters the app only once it is reviewed and checked in.

Web-Architecture Refresher

A compact, mandatory refresher — just enough to place every concept we will use.

Front-end, back-end, full-stack

  • Front-end — the code that runs in the user’s browser: UI, interactions, client-side state. Here: React + Vite + Tailwind.
  • Back-end — the server-side logic: business rules, data access, security, and the API. Here: Node.js + Express + MySQL.
  • Full-stack — building (and understanding) both sides, and the connection between them.

Client–server

A web app is a client (the browser) talking to a server over HTTP. The client renders and collects input; the server validates, runs the business logic, and persists data.

graph
  subgraph Client["Client (browser)"]
    A[HTML/CSS<br/>Presentation]
    B[JavaScript<br/>Interaction]
  end
  subgraph Net["Network"]
    D[HTTP/HTTPS]
  end
  subgraph Server["Server"]
    E[Node.js / Express<br/>App logic]
    F[MySQL<br/>Persistence]
  end
  A --> D
  B --> D
  D --> E
  E --> F

Single-Page Application (SPA)

A SPA loads one HTML shell and then updates the UI in place — without full page reloads — by fetching data (JSON) from an API. Our catalog is an SPA: App.jsx sets up the routes, and components like ProductList and ProductDetail swap in as you navigate. SPAs give a smooth, app-like experience; the trade-off is that first load needs JavaScript, which is why SEO matters for public pages.

RECALL / if needed — Full-stack solutions deep-dive

Optional depth. Read this only if you want the wider landscape before we commit to our stack.

SPA vs SSR vs SEO

  • SPA (Single Page Application) — client-side app that updates the UI without full page reloads. Pros: smooth, fast subsequent navigation, app-like UX. Cons: slower initial load, content requires JS, SEO needs work.
  • SSR (Server-Side Rendering) — the server renders the HTML for the initial request. Pros: faster first meaningful paint, better SEO, predictable initial HTML. Cons: more server logic, higher server cost/latency.
  • SEO (Search Engine Optimization) — search engines and social previews rely on server-provided HTML for the best results. Prioritize it for marketing pages, public content, and product landing pages. SPA mitigations: pre-rendering (SSG), dynamic rendering, or server-side snapshots.
  • Hybrid & static — SSG (Static Site Generation) builds HTML at build time (great for blogs and docs); ISR / on-demand revalidation sits between SSG and SSR for fresh content.

Common solution patterns

  • Client–server (React + REST API) — decoupled, scalable, ubiquitous. This is our course stack.
  • SSR / hybrid (e.g. Next.js) — SEO and fast first paint.
  • Full-stack React (e.g. Remix) — server-first routing and data loading.
  • Enterprise SPA (e.g. Angular) — TypeScript-first, opinionated, for large long-lived teams.
  • Serverless functions — easy scaling, less infra to manage.
  • Monolith (Express + templating) — simple for small projects.

Choosing a stack (quick guideline)

  • SEO + fast first paint → SSR/hybrid (Next.js-style).
  • Large, strictly-structured enterprise app → Angular.
  • Rapid API-driven SPA → React + Express (ours).
  • Small / simple site → server-rendered pages (templating).

Our minimal full-stack stack

  • Frontend: React + Vite (Tailwind for styling).
  • Backend: Node.js + Express.
  • Database: MySQL (structured data).

Why this stack for learning. One language (JavaScript) across front and back reduces context-switching; it is JSON-native and API-first; and it maps to a large job market. Once you understand React + Express + a relational database, moving to TypeScript, SSR/hybrid frameworks, or a different backend is mostly translation.

Dev Environment

We develop inside a devcontainer — a Docker container that gives everyone the same tooling — and we run the app with Docker Compose. The compose file starts the services the app needs; for daily development you open the project in the container and use npm run dev.

Get the app

git clone https://github.com/ebpro/fullstack-minimal-app.git
cd fullstack-minimal-app

Clone the default branch; do not add -b develop to the command.

Services

Service What it is Host port
mysql MySQL 8.0 database (minimal_app_db, seeded by db/init.sql) 3306
backend Express REST API (Node.js) 4000
frontend React + Vite dev server 5173
scraper Mock external review API (home stretch only — use the shipped service) 5000

Bring it up

  • Quick check (no setup): from the app root, docker compose up --build.
  • Daily development (recommended): open the project in VS Code → Reopen in Container (accept the prompt) → in the terminal run npm install (if needed) then npm run dev. Hot reload is on: save a file, see the change.

Where the catalog renders

  • Frontend (the catalog): http://localhost:5173 — this is where you will see and extend the UI.
  • Backend API: http://localhost:4000 (health check at http://localhost:4000/health).
  • Scraper (home stretch only): http://localhost:5000.
TipTwo common hiccups
  • Frontend shows no content: inside the container, Vite must bind to 0.0.0.0, not localhost. Check VITE_HOST=0.0.0.0 in frontend/.env.
  • Port already in use: free ports 5173, 4000, or 3306 (stop a local MySQL or other container) or change the mappings in docker-compose.yml.