Exercise: App Router boundaries (server vs client)
Goal
Build a small Next.js App Router feature that forces correct server/client separation and good UX states.
Scenario
Create a “Users” page with:
- a server-rendered list (data loaded server-side)
- a client-side form to add a user (interactive)
- loading + error states
Requirements
- Routing/layout:
- Use App Router (
app/). - Add a shared layout for the section (title + nav).
- Use App Router (
- Server/client separation:
- The list is rendered from a Server Component.
- The form is a Client Component.
- UX states:
- Show a loading state while data is loading.
- Show a user-friendly error state if loading fails.
- After creating a user, the list updates (strategy is up to you).
Data rules (for now)
- You may use an in-memory “fake” data source on the server side (module-level array) to keep this exercise focused.
- Do not call a “microservice” from the browser. Pretend the server data source is the microservice boundary.
Acceptance criteria (entry)
- No
"use client"at the page level unless it’s strictly required (it shouldn’t be). - Data access is server-side only.
- Form is interactive and handles disabled/loading/error states.
Stretch goals (mid)
- Add Zod validation for the form:
- client-side UX mapping
- server-side boundary validation (even if the “server” is a fake layer)
- Add optimistic UI (with rollback on error) or a clear refresh strategy.
Stretch goals (senior)
- Write down a boundary decision for when to use:
- Server Components
- Client Components
- Route Handlers
- tRPC procedures in this scenario.
Last updated on