Next.js Dashboard App
Full-stack dashboard with secure authentication, PostgreSQL database management, and robust schema validation using Zod.

Problem
I wanted a serious reference implementation of the full Next.js App Router stack — not just a marketing page, but a real CRUD dashboard with auth, a typed database, schema-validated forms, and the streaming/Suspense patterns that Next 14+ enables. Most tutorials stop at the API-route layer; this one had to go all the way through to a deployed Postgres database.
Approach
App Router throughout, with server components doing the data fetching directly against Postgres via parameterised SQL. Forms are mutations via server actions, with Zod schemas catching invalid input before it touches the database. Auth.js v5 handles credentials-based login with JWT sessions and middleware-level route protection. Loading and error states use the App Router conventions (`loading.tsx`, `error.tsx`) so each route segment streams independently.
Stack & rationale
- Next.js App RouterServer components let the dashboard pages fetch and render database data without a separate API tier — fewer hops, lower latency, no client-side waterfall.
- TypeScriptTypes flow from Zod schemas through server actions into components, so a mismatched form field surfaces as a build error rather than a runtime 500.
- PostgreSQLRelational data (customers, invoices, revenue) maps cleanly to SQL joins. Parameterised queries keep input-validation honest.
- Auth.js v5JWT sessions + middleware route protection is the path of least resistance for a single-user dashboard; no session store to operate.
- ZodSingle schema covers both form-side validation and the server-action payload check — one definition, two enforcement points.
Highlights
- ▸Server components fetch directly from Postgres — no internal REST/RPC layer
- ▸Server actions for create/update/delete with Zod-validated payloads
- ▸Middleware-level auth gating: unauthenticated requests redirect before any handler runs
- ▸Per-segment streaming with `loading.tsx` so the dashboard shell appears instantly while data fills in
- ▸Search and pagination handled via URL search params (back/forward buttons just work)