Learning Paths

Full-Stack Web

HTML, TypeScript, React, Node and databases — in the order that lets each one earn the next, ending in a product on a real domain with real users' data in it.

Finish this and you can take a product from an empty folder to a deployed, authenticated, tested application — and explain every layer of it in an interview without hand-waving.

Starts at
Beginner
Topics
6
Projects
5
Of material
212 h
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • React
  • Node.js
  • SQL
Level
Format
  1. 01

    Web fundamentals

    Beginner

    HTML that means something, CSS that survives a redesign, and the browser mechanics underneath both. Skipping this is why most self-taught developers plateau at the framework layer.

    Build this

    A multi-page site with no framework and no CSS library

    A three-page site — hand-written HTML and CSS, no framework, no CSS library, no build step — that scores 100 on Lighthouse accessibility and is fully operable from the keyboard.

    1. Use the real elements. header, nav, main, article, footer, one h1 per page, headings that descend in order. Check each element's purpose in the MDN element reference before reaching for a div.
    2. Lay it out with modern CSS. Grid for the page, flexbox for components, custom properties for the palette and spacing scale, clamp() for type. No float layouts and no breakpoint per device.
    3. Make the navigation work without JavaScript. If it needs a menu toggle, that toggle is a real <button> with aria-expanded, reachable by Tab, closed by Escape.
    4. Prove the contrast. Every text-on-background pair through the WebAIM contrast checker at AA or better, plus a focus ring you designed deliberately rather than suppressed.
    5. Do a keyboard-only pass. Unplug the mouse and complete every task on the site. Add a skip link, and fix every place where focus order jumps or focus disappears entirely.
    6. Measure, then explain. Lighthouse on mobile: accessibility 100, performance above 95. Then list what the audit caught that you had not noticed — that list is the actual learning.

    Scope guard: no framework, no Tailwind, no npm at all. Everything a framework will later do for you, do once by hand here.

    Done when: A deployed three-page site at Lighthouse accessibility 100, completed mouse-free, with a written list of what the audit caught.

  2. 02

    JavaScript, properly

    Beginner

    Closures, the event loop, promises and modules. The four things that separate someone who can copy a React tutorial from someone who can debug one.

    Build this

    An interactive app in vanilla JavaScript

    One interactive app — a task list, a quiz, a small game — with state you manage yourself, persistence to localStorage, and no libraries at all.

    1. State is one object. A single source of truth plus a render(state) that redraws from it. Never read the DOM to find out what the app currently thinks.
    2. Route every change through one function. update(action) mutates state and calls render. The moment you set textContent anywhere else, you have two sources of truth.
    3. Delegate events. One listener on the container using event.target.closest(), not one per item. Add an item afterwards and confirm it works with nothing rebound.
    4. Persist and rehydrate. Save on change, load on start, both wrapped in try/catch because private mode throws. Handle stored data written by an older version of your own shape.
    5. Cover empty, error and first-run. Nothing saved yet, a failed save, invalid input. Each gets real copy on screen, not a console message.
    6. Record where it hurt. The exact moment your own state handling became painful — a full redraw for one changed row, a listener firing twice. That paragraph is why frameworks exist.

    Scope guard: zero dependencies, one HTML file and one JS module, no bundler. Reach for a framework only after you can name the problem it solves for you.

    Done when: A deployed dependency-free app with single-source state, working persistence, and a written account of where manual state handling broke down.

  3. 03

    TypeScript deep dive

    Intermediate

    Types as documentation that cannot go stale. Start where the compiler helps most — function boundaries and API responses.

  4. 04

    React and state

    Intermediate

    Components, the rules of hooks, and the harder question underneath: where each piece of state should actually live.

    Build this

    A React front end against a real, unreliable API

    A React client for the Open-Meteo forecast API — a real service you do not control, free and keyless — that behaves correctly on a slow, failing connection rather than only on the happy path.

    1. Model four states explicitly. idle, loading, error and empty are distinct renders. A boolean isLoading cannot express "loaded, but zero results" or "loaded, then the refetch failed".
    2. Fetch properly. AbortController on unmount and on superseded requests, a timeout, retry with backoff for 5xx and never for 4xx. Fire two searches in quick succession and prove the older response cannot win.
    3. Handle real input. Debounce the location search at 300ms, keep the last good result on screen while the next loads, and keep the query in the URL so a refresh restores the view.
    4. Force every failure. DevTools on Slow 3G and Offline, a rewritten path for a 404, and a malformed response. Screenshot each state as you produce it.
    5. Stay accessible while content changes. Announce loading and errors through aria-live, keep focus stable when content swaps, and leave a keyboard-reachable retry after a failure.
    6. Cache on purpose. TanStack Query with stale times you can justify, or your own cache — either way, write down the staleness rule and why it suits weather data specifically.

    Scope guard: one API, one screen, four states. Most portfolio React apps only ever render the happy path; screenshots of the other three are the differentiator.

    Done when: A deployed app with screenshots of loading, empty, error and offline states, plus a demonstrated race condition where the stale response is discarded.

  5. 05

    APIs and databases

    Intermediate

    The server half: HTTP as it actually works, a real relational schema, and auth you have not invented yourself.

    Build this

    A REST API with sessions, roles and migrations

    A REST API with registration, sessions, role-based authorisation and versioned migrations — schema designed on paper first, and tests that prove an ordinary user cannot reach another user's records.

    1. Draw the schema before any code. Tables, keys and the cardinality of every relationship. Decide now what is nullable and what is unique; both are painful to change later.
    2. Migrations from the first commit. Every schema change is a numbered up/down migration in the repository. Prove it by dropping the database and rebuilding from migrations plus a seed script.
    3. Authenticate by the book. Argon2id or bcrypt at a sensible cost, httpOnly SameSite session cookies or short-lived JWTs with refresh, rate limiting on login, and identical timing and wording for "wrong password" and "no such user" — see the OWASP authentication cheat sheet.
    4. Authorise per object, not per route. A user reads their own records and not somebody else's. Write the test that tries it — broken object-level authorisation is the most common real API vulnerability there is.
    5. Answer the concurrency question. Two clients editing one record: last write wins, optimistic locking on a version column, or a 409. Implement one and document why that one.
    6. Document and validate at the boundary. An OpenAPI spec generated from the code, request validation on entry, a consistent error shape, and pagination on every list endpoint.

    Scope guard: one resource with full CRUD, two roles, no GraphQL, no microservices. The authorisation tests matter more than the endpoint count.

    Done when: An API rebuilt from migrations alone, with an OpenAPI spec, a documented concurrency strategy, and tests proving cross-user and cross-role access is denied.

  6. 06

    Testing, CI and deploying to the cloud

    Intermediate

    The half of the job that turns a project into a product: tests worth having, a pipeline that runs them, and a deploy you can repeat.

    Build this

    Ship it: your app, your domain, your pipeline

    The API and front end you already built, live on your own domain, behind a pipeline that blocks a bad merge, with error tracking that tells you about a failure before a user does.

    1. One command from clone to running. Docker Compose or a documented script that gets a stranger the whole stack locally. Test it on a machine that has never seen the project.
    2. A pipeline that can say no. On every pull request: lint, type check, unit tests, and one Playwright end-to-end run through the real login flow. Branch protection on, so a red build cannot merge.
    3. Deploy on merge. Main deploys automatically, migrations run as a separate gated step, and there is a rollback procedure you have actually executed once.
    4. Configure like production. Secrets from the environment, never the repository. HTTPS with HSTS, security headers, CORS restricted to your own origin, then confirm the result with Mozilla Observatory.
    5. See failures without being told. Error tracking with source maps and release tagging, one uptime check, and structured logs carrying a request ID that ties a user's report to a log line.
    6. Five real users. Hand the URL to five people who do not know how it works, watch without helping, and write down everything they broke or could not find. Fix the top three; record what you chose not to fix.

    Scope guard: one domain, one environment plus preview deploys. The list of what five strangers broke is the most valuable artefact on this path — do not skip it because the deploy already works.

    Done when: A live URL on your own domain, a pipeline that has blocked a failing merge, a rollback you performed, and a written post-mortem of five real users.

Not sure this is your direction?

A three-minute counselling sample is free.

Try counselling
Full-Stack Web · Learning Paths · CareerOS