A modern, high-performance e-commerce storefront template built with Next.js 16 (App Router), React 19, Tailwind CSS v4, and Jotai.
- Modern stack — Next.js 16, React 19, TypeScript 6 (strict), Tailwind CSS v4.
- Server Components by default — interactivity is isolated to small client leaves (e.g. add-to-cart), so listings render on the server.
- Single source of truth for data — products/categories live in
data/, are validated by zod schemas, and are read through an async accessor layer inlib/data/. - Type-safe domain model —
Product/Categorytypes are derived from zod schemas; prices are integer cents formatted withIntl.NumberFormat. - Shopping cart — persistent Jotai store with hydration-safe rendering, quantity clamping, and accurate line/subtotal math.
- Instant search — ⌘K command palette, indexed automatically from the catalog.
- Dark mode —
next-themeswired to OKLCH design tokens, with a header toggle. - SEO — per-page metadata + canonical/OpenGraph, Product & BreadcrumbList JSON-LD, dynamic sitemap (incl. product routes), robots, and a PWA manifest.
- Accessibility — skip link, reduced-motion support, labelled controls, keyboard-friendly dialogs.
- Validated forms — contact form built with react-hook-form + zod.
- Tested & CI-ready — Vitest unit tests and a GitHub Actions workflow (lint, typecheck, test, build).
- Production Docker — multi-stage build, standalone output, non-root user, working health check.
- Next.js 16 — React framework with App Router
- React 19 — UI library
- Jotai — atomic state management
- Tailwind CSS v4 — utility-first CSS with OKLCH tokens
- shadcn/ui (base-nova) on Base UI — accessible component primitives
- Motion — animation (404 page only)
- Tabler Icons, Sonner, zod, react-hook-form
- TypeScript 6 — strict mode
- Vitest — testing
Requires Node 24 (see .nvmrc) and pnpm 9+.
pnpm install
cp .env.example .env # set NEXT_PUBLIC_DOMAIN_NAME
pnpm devOpen http://localhost:3000.
| Script | Description |
|---|---|
pnpm dev |
Start the dev server |
pnpm build |
Production build (also type-checks) |
pnpm start |
Start the production server |
pnpm lint / pnpm lint:fix |
ESLint |
pnpm typecheck |
tsc --noEmit |
pnpm test / pnpm test:run |
Vitest (watch / once) |
pnpm format / pnpm format:check |
Prettier |
make build && make up # or: docker compose up -d --build
make logsNEXT_PUBLIC_DOMAIN_NAME is a build-time value (inlined into the client bundle), so changing it requires a rebuild. See DOCKER.md.
app/ # routes (RSC); pages compose features, no inline data
api/health/ # health endpoint for container checks
products/[id]/ # SSG product detail (+ loading / metadata / JSON-LD)
(men|women|accessories|sale)/ # category routes (real filtering)
data/ # single source of truth: products.ts, categories.ts
lib/
schemas/ # zod schemas (source of the domain types)
data/ # async data accessors + search index
config/site.ts # brand / SEO / nav config
store/cartStore.ts # Jotai cart atoms
hooks/ # useIsHydrated
env.ts # validated NEXT_PUBLIC_DOMAIN_NAME -> siteUrl
format.ts # formatPrice(cents)
seo.ts # pageMetadata() helper
types/ # Product, Category, CartItem (barrel)
components/
ui/ # shadcn/ui primitives (add more with `pnpm dlx shadcn add`)
layout/ sections/ products/ cart/ forms/ providers/
public/ # og-image, logo, brand icons, placeholder art
- Data flow:
data/*(validated) →lib/data/*(async accessors) → RSC pages → presentational components. Swaplib/data/products.tsfor a real backend without touching the UI. - Types: import domain types from
@/types; they derive fromlib/schemas/. - State: Jotai atoms in
lib/store/.useIsHydratedguards persisted state to avoid hydration mismatches. - Styling: Tailwind v4
@themetokens (OKLCH) inapp/globals.css; merge classes withcn().
See DOCKER.md for deployment and CONTRIBUTING.md for conventions. AUDIT.md documents the audit this template was hardened against.