Course navigationPhase 03
Volume 02 · Phase 03

Next.js Fundamentals

Build the Next.js application shell while understanding App Router routing, layouts, Server Components, Client Components, environment boundaries, and rendering behavior.

12lessons + labs
7klesson words
7source references
What you will ship

Phase outcome and project increment

Learning outcome

Build the Next.js application shell while understanding App Router routing, layouts, Server Components, Client Components, environment boundaries, and rendering behavior.

Concrete deliverable

A navigable TaskFlow web shell with route groups/layouts, server-first composition, selective client interactivity, and verified environment handling.

Figure 3.1 — Where this phase lives in TaskFlow
Route request
App Router match
layout/page Server Component
optional server fetch
Client Component island
browser interaction
Trace the flow left-to-right for implementation and right-to-left for debugging. At every arrow, ask what data crosses the boundary and what proves it is trustworthy.
Instructor mental model

Principles to keep while coding

01

Use Server Components by default and introduce Client Components only where browser interactivity requires them.

02

Treat the App Router file system as application structure, not as a place to hide business rules.

03

Keep secrets and privileged data access on the server side of the Next.js boundary.

04

Understand caching and rendering behavior before trying to fix stale UI with ad-hoc client state.

Code-along path

Guided phase lab

Do these in order. Each step should end with evidence before the next one starts.

  1. 01

    Generate the web app in the monorepo and verify the development server from the correct workspace.

  2. 02

    Create nested routes and a shared layout, then predict which layouts persist across navigation.

  3. 03

    Build one component as a Server Component and identify exactly why it can remain server-only.

  4. 04

    Add one Client Component for interaction and explain what 'use client' changes in the dependency graph.

  5. 05

    Add server-only and public environment values and prove which can reach the browser bundle.

  6. 06

    Use browser DevTools and terminal logs to distinguish server rendering from client execution.

TerminalVerification commands
pnpm --filter web dev
pnpm --filter web build

Predict what each command proves before running it. A command is useful only when its output answers a question.

Debugging studio

Failures you should know how to diagnose

Failure drill 1

Adding 'use client' too high in the tree

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 2

Accessing browser APIs from Server Components

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 3

Leaking secrets through NEXT_PUBLIC variables

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 4

Using effects for work that belongs in server rendering or a data layer

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Watch-order style

Lessons

The source chapters come first. Every phase now ends with a guided build, a debugging workshop, and an independent challenge so reading turns into transferable skill.

Practice ladder

Exercises that increase independence

Guided

Generate the web app in the monorepo and verify the development server from the correct workspace.

Practice

Build one component as a Server Component and identify exactly why it can remain server-only.

Debug

reproduce and diagnose — Adding 'use client' too high in the tree.

Independent

deliver A navigable TaskFlow web shell with route groups/layouts, server-first composition, selective client interactivity, and verified environment handling.

Explain-back

Can choose server vs client intentionally and Can explain layout/page routing.

Mastery gate

Do not leave the phase only because you reached the bottom

Phase exit criteria

Knowledge check

Scenario and concept quiz

These questions test engineering choices rather than whether you remember a lesson title.

0/0 correct · 0/8 answered
01Which practice best matches Phase 03's engineering goal?
02Which practice best matches Phase 03's engineering goal?
03Which practice best matches Phase 03's engineering goal?
04Which practice best matches Phase 03's engineering goal?
05You are working through the Phase 03 lab. Which next action is the most disciplined step?
06You are working through the Phase 03 lab. Which next action is the most disciplined step?
07You are working through the Phase 03 lab. Which next action is the most disciplined step?
08You are working through the Phase 03 lab. Which next action is the most disciplined step?
Source snapshot

Reference files

Attempt the work first. Use snapshots to compare a checkpoint, not as a substitute for understanding.

reference/TaskFlow_Web_Snapshot/package.json
{
  "name": "web",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint"
  },
  "dependencies": {
    "next": "16.3.3",
    "react": "19.3.0",
    "react-dom": "19.3.0"
  }
}
reference/TaskFlow_Web_Snapshot/src/app/globals.css
:root {
  --background: #f6f8fa;
  --surface: #ffffff;
  --text: #17212b;
  --border: #d8e0e6;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--background);
  color: var(--text);
  font-family: Arial, sans-serif;
}

main {
  width: min(1100px, calc(100% - 2rem));
  margin: 0 auto;
  padding: 2rem 0;
reference/TaskFlow_Web_Snapshot/src/app/layout.tsx
import type { Metadata } from "next";
import Link from "next/link";
import "./globals.css";

export const metadata: Metadata = {
  title: "TaskFlow",
  description: "Project and task management for focused teams",
};

export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
  return (
    <html lang="en">
      <body>
        <header>
          <Link href="/">TaskFlow</Link>
          <nav aria-label="Primary navigation">
            <Link href="/projects">Projects</Link>
            <Link href="/settings">Settings</Link>
          </nav>
        </header>
reference/TaskFlow_Web_Snapshot/src/app/page.tsx
export default function HomePage() {
  return (
    <section>
      <p>TaskFlow</p>
      <h1>Keep work visible and moving.</h1>
      <p>Projects, tasks, ownership, and progress will grow here throughout the course.</p>
    </section>
  );
}
reference/TaskFlow_Web_Snapshot/src/app/projects/page.tsx
const projects = [
  { id: 1, name: "Website refresh", status: "Active" },
  { id: 2, name: "Inventory rollout", status: "Planning" },
];

export default function ProjectsPage() {
  return (
    <section>
      <h1>Projects</h1>
      {projects.map((project) => (
        <article key={project.id}>
          <h2>{project.name}</h2>
          <p>{project.status}</p>
        </article>
      ))}
    </section>
  );
}
reference/TaskFlow_Web_Snapshot/src/app/settings/density-toggle.tsx
"use client";

import { useState } from "react";

export function DensityToggle() {
  const [compact, setCompact] = useState(false);
  return (
    <button onClick={() => setCompact((value) => !value)}>
      Density: {compact ? "Compact" : "Comfortable"}
    </button>
  );
}
reference/TaskFlow_Web_Snapshot/src/app/settings/page.tsx
import { DensityToggle } from "./density-toggle";

export default function SettingsPage() {
  return (
    <section>
      <h1>Settings</h1>
      <DensityToggle />
    </section>
  );
}