@dennisrongo/skills 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +87 -38
  2. package/package.json +1 -1
  3. package/skills/code-review/SKILL.md +270 -0
  4. package/skills/codebase-explainer/SKILL.md +112 -0
  5. package/skills/diagnose/SKILL.md +31 -1
  6. package/skills/dotnet-onion-api/SKILL.md +1 -0
  7. package/skills/nextjs-app-router/SKILL.md +229 -175
  8. package/skills/nextjs-app-router/references/anti-patterns.md +163 -99
  9. package/skills/nextjs-app-router/references/folder-layout.md +79 -46
  10. package/skills/nextjs-app-router/references/good-patterns.md +233 -99
  11. package/skills/nextjs-app-router/references/templates/api-base.md +24 -21
  12. package/skills/nextjs-app-router/references/templates/auth-slice.md +82 -78
  13. package/skills/nextjs-app-router/references/templates/ci-and-hooks.md +58 -6
  14. package/skills/nextjs-app-router/references/templates/db-client.md +48 -0
  15. package/skills/nextjs-app-router/references/templates/env-and-utils.md +90 -23
  16. package/skills/nextjs-app-router/references/templates/feature-slice.md +110 -47
  17. package/skills/nextjs-app-router/references/templates/form-with-zod.md +23 -15
  18. package/skills/nextjs-app-router/references/templates/middleware.md +69 -59
  19. package/skills/nextjs-app-router/references/templates/next-config.md +4 -14
  20. package/skills/nextjs-app-router/references/templates/nextauth-config.md +178 -0
  21. package/skills/nextjs-app-router/references/templates/package.md +35 -5
  22. package/skills/nextjs-app-router/references/templates/prisma-schema.md +162 -0
  23. package/skills/nextjs-app-router/references/templates/providers-and-store.md +35 -21
  24. package/skills/nextjs-app-router/references/templates/root-layout.md +99 -20
  25. package/skills/nextjs-app-router/references/templates/route-group-layouts.md +46 -6
  26. package/skills/nextjs-app-router/references/templates/route-handler.md +168 -0
  27. package/skills/nextjs-app-router/references/templates/testing.md +105 -31
  28. package/skills/plan-and-build/SKILL.md +45 -3
  29. package/skills/pr-review/SKILL.md +50 -3
  30. package/skills/tauri-2-app/SKILL.md +1 -0
@@ -1,24 +1,31 @@
1
1
  ---
2
2
  name: nextjs-app-router
3
- description: Scaffold a new Next.js (App Router) frontend with TypeScript, Redux Toolkit + RTK Query, Tailwind + shadcn/ui (Radix), React Hook Form + Zod, and a curated set of conventions. Use this skill whenever the user asks to "create a new Next.js project", "scaffold a frontend", "new React app", "Next.js app router project", "RTK Query frontend", "shadcn project", or mentions "the frontend patterns I like" / "my Next.js conventions". Three modes — (1) full project scaffold, (2) add a feature slice (route group + page + RTK Query endpoints + form), (3) add an RTK Query API slice for an existing domain. Codifies the good patterns (route groups, injected RTK endpoints, schema-driven forms, per-feature `_components`/`_hooks`, server-side auth middleware) and forbids the common pitfalls (`'use client'` on root pages, `router.push` in `useEffect` for redirects, `serializableCheck: false`, `@ts-ignore`, mixed date libraries, `dangerouslySetInnerHTML` without sanitization, case-sensitive folder dupes, missing tests/CI/middleware).
3
+ description: Scaffold a new Next.js (App Router) fullstack app with TypeScript, NextAuth (Auth.js v5), Prisma + PostgreSQL, Route Handlers, Redux Toolkit + RTK Query, Tailwind + shadcn/ui (Radix), React Hook Form + Zod. Pages are `'use client'` SPA-style — RTK Query talks to in-app `/api/**` Route Handlers; no `fetch()` in server components, no Server Actions, no async `page.tsx`. Use this skill whenever the user asks to "create a new Next.js project", "scaffold a Next.js app", "new Next app with auth", "Next.js + NextAuth", "RTK Query Next.js app", "Next.js + Prisma project", "shadcn project", or mentions "my Next.js conventions". Three modes — (1) full project scaffold, (2) add a feature slice (route + Route Handlers + RTK Query endpoints + Zod schema + form), (3) add an RTK Query API slice for an existing domain. Confirms the database (Postgres + Prisma) and NextAuth providers BEFORE writing any files. Codifies the good patterns (route groups, NextAuth `auth()` in Route Handlers, single base RTK Query + injected endpoints, Prisma singleton, schema-driven forms, per-feature `_components`/`_hooks`) and forbids the pitfalls (`fetch()` / `await db.*` in server components, Server Actions, async `page.tsx`, custom JWT cookies fighting NextAuth, `serializableCheck: false`, `@ts-ignore`, mixed date libraries, `dangerouslySetInnerHTML` without sanitization, multiple `createApi()` instances).
4
4
  ---
5
5
 
6
- # Next.js App Router Frontend Scaffolder
6
+ # Next.js App Router Fullstack Scaffolder (NextAuth + Prisma + RTK Query)
7
7
 
8
- Generate a production-grade Next.js frontend project that keeps the **good** modern-stack patterns (App Router with route-group auth boundaries, single RTK Query API with injected endpoints, shadcn/ui on Tailwind + Radix, React Hook Form + Zod with schema-introspected defaults, per-feature `_components`/`_hooks` co-location, typed Redux hooks, server-side auth middleware) and eliminates the **bad** ones often seen in real-world Next.js codebases (`'use client'` on layouts and root pages, `router.push` in `useEffect` instead of server `redirect()`, `serializableCheck: false`, `@ts-ignore` in the store, mixed `moment` + `date-fns`, leftover `styled-components` in a Tailwind project, case-sensitive duplicate model folders, `dangerouslySetInnerHTML` without sanitization, sessionStorage for non-transient state, tokens in non-`httpOnly` cookies, no `middleware.ts`, no tests, no error/loading boundaries).
8
+ Generate a production-grade Next.js fullstack app where:
9
+
10
+ - **Pages are `'use client'` SPA-style.** All data goes through RTK Query. No `fetch()` in server components. No Server Actions. No async `page.tsx`. The root `app/layout.tsx` is the **only** server component that matters — it renders `<Providers>`. Per-feature `page.tsx` files are client components.
11
+ - **Backend lives in-app as Next.js Route Handlers** under `src/app/api/**/route.ts`. Each handler calls `await auth()` and queries Postgres via Prisma.
12
+ - **Auth is NextAuth (Auth.js v5)**, not a custom JWT-cookie scheme. `src/auth.ts` is the single source of auth truth. `middleware.ts` re-exports `auth` for route-level gating. Login UIs call `signIn()` from `next-auth/react`; logout calls `signOut()`. RTK Query reads the session cookie automatically via `credentials: 'include'`.
13
+ - **Database is PostgreSQL via Prisma.** NextAuth uses the Prisma adapter. The skill **confirms the database choice with the user before writing files** even though Postgres+Prisma is the only supported option — the connection string and host (local Docker, Neon, Supabase, etc.) need to be locked down up front.
14
+
15
+ The skill **forbids** the patterns it used to allow in an earlier frontend-only revision: server-side data fetching, `redirect()` from server pages, custom `httpOnly` JWT cookies, multi-`createApi` setups, and ad-hoc auth slices that duplicate NextAuth state.
9
16
 
10
17
  ## When to use this skill
11
18
 
12
19
  Trigger on any of:
13
20
 
14
- - "create a new Next.js project" / "scaffold a frontend" / "new React app"
15
- - "Next.js App Router project" / "App Router scaffold"
16
- - "RTK Query frontend" / "Redux Toolkit Next.js"
17
- - "shadcn/ui project" / "Tailwind + shadcn + Radix scaffold"
18
- - "use my frontend patterns" / "the Next.js conventions I like"
19
- - "add a feature slice end-to-end" (route + RTK Query endpoints + form) in a Next.js context
21
+ - "create a new Next.js project" / "scaffold a Next.js app" / "new Next app"
22
+ - "Next.js App Router project" / "Next.js + NextAuth" / "Next.js + Prisma"
23
+ - "RTK Query Next.js app" / "Redux Toolkit Next.js"
24
+ - "shadcn/ui project" / "Tailwind + shadcn + Radix scaffold" in a Next.js context
25
+ - "use my Next.js conventions" / "the Next.js patterns I like"
26
+ - "add a feature end-to-end" (route + Route Handler + RTK Query + form) in a Next.js context
20
27
  - "add a new RTK Query API slice for `<domain>`"
21
- - The user pastes a feature spec for a screen and asks you to wire it through routing + state + form
28
+ - The user pastes a feature spec for a screen and asks you to wire it through routing + API + state + form
22
29
 
23
30
  If unsure whether the user wants a brand-new project vs. an addition to an existing one, ask once — don't guess.
24
31
 
@@ -28,28 +35,30 @@ Pick the mode from the user's request. If ambiguous, ask.
28
35
 
29
36
  | Mode | Trigger | Output |
30
37
  |------|---------|--------|
31
- | **`scaffold-project`** | "new project", "scaffold frontend", empty directory | Full Next.js App Router project: route groups, providers, store, base RTK api, auth slice, middleware, shadcn/ui init, Vitest + Playwright config, ESLint/Prettier/Husky, GitHub Actions CI. |
32
- | **`add-feature`** | "add `<feature>` end-to-end", "wire up `<screen>` through routing + state + form" | New route folder under the appropriate group with `page.tsx`, `_components/`, `_hooks/`, `loading.tsx`, an RTK Query endpoint file, a Zod schema, and a form component. |
33
- | **`add-api-slice`** | "add an API slice for `<domain>`", "new RTK Query endpoints for X" | New `src/redux/api/<domain>Api.ts` injecting endpoints into the base `api`, plus its tag types and typed hooks. |
38
+ | **`scaffold-project`** | "new project", "scaffold app", empty directory | Full Next.js App Router project: route groups, server root layout, client pages, NextAuth config, Prisma schema + migration, `/api/auth/[...nextauth]` handler, base RTK Query pointing at `/api`, shadcn/ui init, Vitest + Playwright, ESLint/Prettier/Husky, GitHub Actions CI. |
39
+ | **`add-feature`** | "add `<feature>` end-to-end", "wire up `<screen>` through routing + API + state + form" | New route folder under the appropriate group with a `'use client'` `page.tsx`, `_components/`, `_hooks/`, `loading.tsx`, Zod schema, RTK Query endpoint file, **and a matching `src/app/api/<feature>/route.ts` Route Handler** that calls `auth()` and Prisma. |
40
+ | **`add-api-slice`** | "add an API slice for `<domain>`", "new RTK Query endpoints for X" | New `src/redux/api/<domain>Api.ts` injecting endpoints into the base `api`, plus matching `src/app/api/<domain>/**/route.ts` handlers (one per endpoint) and Prisma model additions if needed. |
34
41
 
35
42
  ## Workflow
36
43
 
37
44
  ### Step 1 — Determine versions (don't hard-code)
38
45
 
39
- The user does **not** want hard-coded package versions baked into the skill. Before writing `package.json`:
46
+ Versions are resolved at scaffold time, never hard-pasted into the skill. Before writing `package.json`:
40
47
 
41
- 1. Check the user's environment first: run `node --version` and `npm --version` (or `pnpm --version` / `yarn --version`) to see what's installed.
42
- 2. Resolve the latest stable versions of the core stack via context7 — never hand-paste:
48
+ 1. Check the user's environment first: run `node --version` and `npm --version` (or `pnpm --version` / `yarn --version`).
49
+ 2. Resolve the latest stable versions of the core stack via context7 (`mcp__plugin_context7_context7__query-docs`) — never hand-paste. Resolve:
43
50
  - `next`, `react`, `react-dom`, `typescript`, `@types/react`, `@types/node`
51
+ - `next-auth` (Auth.js v5 — current beta as of late 2025; verify via context7), `@auth/prisma-adapter`
52
+ - `prisma`, `@prisma/client`, `bcryptjs` (and `@types/bcryptjs`) — or `@node-rs/argon2` if user prefers Argon2
44
53
  - `@reduxjs/toolkit`, `react-redux`
45
54
  - `tailwindcss`, `postcss`, `autoprefixer`
46
- - `@radix-ui/*`, `class-variance-authority`, `clsx`, `tailwind-merge`, `tailwindcss-animate`, `lucide-react`
55
+ - `@radix-ui/*` (only the primitives the templates need), `class-variance-authority`, `clsx`, `tailwind-merge`, `tailwindcss-animate`, `lucide-react`
47
56
  - `react-hook-form`, `@hookform/resolvers`, `zod`
48
57
  - `date-fns` (do **not** also add `moment`)
49
58
  - `vitest`, `@testing-library/react`, `@testing-library/jest-dom`, `jsdom`, `@playwright/test`
50
59
  - `eslint`, `eslint-config-next`, `@typescript-eslint/*`, `eslint-plugin-react-hooks`, `eslint-plugin-jsx-a11y`, `prettier`, `husky`, `lint-staged`
51
60
  3. Quote the resolved versions back to the user before generating, so they can object.
52
- 4. Prefer the latest **stable** Next.js (App Router is GA from 13.4 onward; ensure the chosen version is current at scaffold time).
61
+ 4. Prefer the latest **stable** Next.js (App Router GA from 13.4; resolve current).
53
62
  5. Default to **pnpm** if `pnpm` is present, otherwise **npm**. Match `packageManager` in `package.json`.
54
63
 
55
64
  ### Step 2 — Gather inputs (ask once, in one batch)
@@ -57,35 +66,45 @@ The user does **not** want hard-coded package versions baked into the skill. Bef
57
66
  For `scaffold-project`, use `AskUserQuestion` to collect:
58
67
 
59
68
  - **Project name** (kebab-case, used for the directory and `package.json` `name`).
60
- - **Route groups**: which auth/role boundaries does the app need? Default offer: `(public)` for auth pages + `(app)` for authenticated content. Optionally add `(admin)` for role-gated routes.
61
- - **Auth flavor**: JWT in `httpOnly` cookie (recommended; middleware sets the cookie, server reads it) **or** JWT in JS-accessible cookie + `Authorization: Bearer` header **or** none-yet.
62
- - **API base URL** env var name (default `NEXT_PUBLIC_API_BASE_URL`) and whether requests should go through a Next.js rewrite to hide the backend host.
63
- - **Real-time** (Pusher / WebSocket / SSE / none).
64
- - **Optional extras**: Storybook? i18n? Sentry? Dockerfile? GitHub Actions CI? PM2 ecosystem file? (Default: skip — only add if asked. CI defaults ON.)
65
- - **First feature/route** (optional, e.g. `dashboard`) — if provided, also run `add-feature` for it after scaffold.
69
+ - **Database connection**. Postgres + Prisma is the only ORM the skill emits, but the host varies. Offer: local Docker (the skill emits a `docker-compose.yml` with a `postgres:16` service), Neon, Supabase, Railway, "I'll paste my own `DATABASE_URL`". Confirm before writing `.env.example` and `prisma/schema.prisma`.
70
+ - **NextAuth providers**. Offer: Credentials (email + password, stored in the `User` table with a bcrypt-hashed `password` column), GitHub OAuth, Google OAuth, "all of the above". Default: Credentials. The chosen providers determine which `.env.example` keys get emitted (`AUTH_GITHUB_ID` / `AUTH_GITHUB_SECRET`, etc.).
71
+ - **Route groups**. Default offer: `(public)` for auth pages + `(app)` for authenticated content. Optionally add `(admin)` for role-gated routes (gated via NextAuth role claim in `middleware.ts`).
72
+ - **First feature/route** (optional, e.g. `dashboard`) if provided, run `add-feature` for it after scaffold.
73
+ - **Optional extras**: Storybook? i18n? Sentry? Dockerfile? GitHub Actions CI? (Default: skip — only add if asked. CI defaults ON.)
66
74
 
67
- For `add-feature`: feature name, route group it belongs to, list of fields (name + Zod type + required/optional), whether it has a list view + detail view or just one screen.
75
+ For `add-feature`: feature name, route group it belongs to, list of fields (name + Zod type + required/optional), CRUD shape (list view + detail view, or just one screen). The skill generates **both** the client page/components and the matching Route Handler(s).
68
76
 
69
- For `add-api-slice`: domain name (e.g. `customers`), list of endpoints (verb + path + request type + response type), invalidation tags.
77
+ For `add-api-slice`: domain name (e.g. `customers`), list of endpoints (verb + path + request type + response type), invalidation tags. The skill generates the RTK Query slice **and** the Route Handlers it calls.
70
78
 
71
79
  ### Step 3 — Generate files
72
80
 
73
81
  Use the **templates in [`references/templates/`](references/templates/)** as the source of truth. Apply these rules:
74
82
 
75
- - Use `Write` for new files. Never use `Edit` on files you're creating fresh.
76
- - Replace all `{{ProjectName}}`, `{{Feature}}`, `{{Domain}}` placeholders consistently. `{{ProjectName}}` is kebab-case for files/dirs and PascalCase only where namespacing requires (e.g. tag-type constants).
83
+ - Use `Write` for new files. Never `Edit` files you're creating fresh.
84
+ - Replace all `{{ProjectName}}`, `{{Feature}}`, `{{Domain}}` placeholders consistently. `{{project-name}}` is kebab-case for files/dirs; PascalCase where namespacing requires.
77
85
  - Create directories before files. On Windows shell use PowerShell `New-Item -ItemType Directory -Force`.
78
- - Do **not** run `create-next-app` to bootstrap — write the files directly from templates so the layout matches the conventions in [`references/folder-layout.md`](references/folder-layout.md). Use `npm`/`pnpm install` after the `package.json` is written.
79
- - Initialize shadcn/ui by writing `components.json` from [`references/templates/components.json.md`](references/templates/components.json.md) and `src/components/ui/` components incrementally as needed (button, input, form, label, dialog, toast, etc.) — do not blanket-install every Radix primitive up front.
86
+ - Do **not** run `create-next-app` to bootstrap — write files directly from templates so the layout matches [`references/folder-layout.md`](references/folder-layout.md). Use `npm`/`pnpm install` after `package.json` is written.
87
+ - Initialize shadcn/ui by writing `components.json` from [`references/templates/components-json.md`](references/templates/components-json.md) and `src/components/ui/` components incrementally as needed (button, input, form, label, dialog, toast, etc.) — don't blanket-install every Radix primitive.
88
+
89
+ ### Step 4 — Database setup
90
+
91
+ After `package.json` and `prisma/schema.prisma` are written:
80
92
 
81
- ### Step 4Verify and report
93
+ 1. `pnpm install` (or chosen PM) installs `prisma` and `@prisma/client`.
94
+ 2. Confirm with the user that their `DATABASE_URL` is reachable before running any DB commands. If they picked local Docker, run `docker compose up -d postgres` first.
95
+ 3. `pnpm exec prisma generate` — generates the typed client.
96
+ 4. `pnpm exec prisma migrate dev --name init` — creates the initial migration covering NextAuth tables + sample domain models.
97
+ - **Never run `prisma db push` against a production-shaped database.** Use migrations.
98
+ - **Never run `prisma migrate reset` without explicit user confirmation** — it drops the DB.
99
+ 5. Generate `AUTH_SECRET` for the user: `pnpm exec auth secret` (Auth.js CLI) or `openssl rand -base64 32`. Put it in `.env.local` (NOT `.env.example`).
82
100
 
83
- - Run the package manager install (`pnpm install` / `npm install`).
84
- - Run `pnpm typecheck` (or `npx tsc --noEmit`). Must exit 0.
85
- - Run `pnpm lint`. Must exit 0.
86
- - Run `pnpm test` (Vitest) if any tests were generated. Must exit 0.
87
- - Run `pnpm build`. Must succeed (this catches client/server boundary errors that `tsc` misses).
88
- - Reply with a short summary: project path, versions chosen, route groups, env vars to set, next steps (e.g. "set `NEXT_PUBLIC_API_BASE_URL` in `.env.local`", "run `pnpm dev`").
101
+ ### Step 5 Verify and report
102
+
103
+ - `pnpm typecheck` (or `npx tsc --noEmit`). Must exit 0.
104
+ - `pnpm lint`. Must exit 0.
105
+ - `pnpm test` (Vitest) if any tests were generated. Must exit 0.
106
+ - `pnpm build`. Must succeed.
107
+ - Reply with a short summary: project path, versions chosen, route groups, env vars to set (especially `AUTH_SECRET` and `DATABASE_URL`), next steps (`pnpm dev`, log in with the seeded test user if Credentials was chosen).
89
108
 
90
109
  ## Project layout (canonical)
91
110
 
@@ -97,59 +116,64 @@ Top-level shape:
97
116
  {{project-name}}/
98
117
  package.json
99
118
  tsconfig.json # strict: true, paths: { "@/*": ["./src/*"] }
100
- next.config.ts # rewrites (if any), images, experimental flags
119
+ next.config.ts
101
120
  tailwind.config.ts # darkMode: ['class'], shadcn theme tokens
102
121
  postcss.config.js
103
122
  components.json # shadcn config; rsc: true
104
123
  .eslintrc.json (or eslint.config.mjs)
105
124
  .prettierrc
106
125
  .env.example # NEVER .env — only .env.example committed
107
- middleware.ts # AUTH GUARD lives here (not in src/proxy.ts)
126
+ middleware.ts # NextAuth-driven route gate; re-exports `auth`
127
+ docker-compose.yml # optional: only if user picked "local Docker"
128
+ prisma/
129
+ schema.prisma # NextAuth tables + domain models
130
+ migrations/ # generated; checked in
131
+ seed.ts # optional: seeds test user for Credentials
108
132
  src/
133
+ auth.ts # NextAuth (Auth.js v5) config — adapter, providers, callbacks
134
+ auth.config.ts # Edge-safe config (no DB/adapter imports) — used by middleware
109
135
  app/
110
- layout.tsx # server component; <html><body><Providers>
111
- page.tsx # server component; redirect() — NOT 'use client' + router.push
136
+ layout.tsx # SERVER. <html><body><Providers>{children}
112
137
  globals.css
113
- error.tsx # global error boundary
138
+ error.tsx
114
139
  not-found.tsx
140
+ api/
141
+ auth/[...nextauth]/route.ts # exports { GET, POST } from NextAuth handlers
142
+ <domain>/route.ts # list + create
143
+ <domain>/[id]/route.ts # get + update + delete
115
144
  (public)/ # unauthenticated routes (login, signup, reset)
116
- layout.tsx
117
- auth/
145
+ layout.tsx # server; minimal chrome
146
+ auth/login/
147
+ page.tsx # 'use client' — calls signIn('credentials', { ... })
118
148
  (app)/ # authenticated routes
119
- layout.tsx # server component; reads session, renders shell
120
- _components/ # private; only nested routes can import
121
- _hooks/
149
+ layout.tsx # server; renders <AppShell> ('use client' child)
150
+ _components/AppShell.tsx
122
151
  loading.tsx
123
152
  error.tsx
124
- <feature>/
125
- page.tsx
126
- loading.tsx
127
- _components/
128
- _hooks/
129
- schema.ts # Zod schemas for this feature
153
+ dashboard/
154
+ page.tsx # 'use client' — uses RTK Query hooks
130
155
  (admin)/ # optional; role-gated
131
156
  components/
132
157
  ui/ # shadcn primitives (button, input, form, ...)
133
- forms/ # composed form fields (FormInputField, ...)
158
+ forms/ # composed form fields
134
159
  Notifications.tsx
135
160
  UnsavedChangesWarning.tsx
136
161
  redux/
137
162
  store.ts # typed; NO @ts-ignore, NO serializableCheck: false
138
- providers.tsx # 'use client'; wraps <Provider>, <Toaster>, <ProgressBar>
163
+ providers.tsx # 'use client'; wraps <SessionProvider><Provider><Toaster>
139
164
  hooks.ts # typed useAppDispatch, useAppSelector
140
165
  api/
141
- api.ts # base createApi with injectEndpoints; auth-aware baseQuery
166
+ api.ts # base createApi pointing at '/api'; auth-aware baseQuery
142
167
  tags.ts # tag-type union as const
143
168
  <domain>Api.ts # one file per domain; injectEndpoints
144
- features/
145
- authSlice.ts
146
- <other>Slice.ts # ONLY for genuinely shared async/global state
147
169
  lib/
170
+ db.ts # PrismaClient singleton
148
171
  utils.ts # cn() — clsx + tailwind-merge
149
172
  zod-utils.ts # getDefaultValuesFromSchema, unwrapZodEffects, getMaxLengthsFromSchema
173
+ api-auth.ts # requireSession() helper for Route Handlers
150
174
  formatters/
151
- hooks/
152
- types/ # cross-cutting TS types (NOT per-domain; those live with their feature)
175
+ types/
176
+ next-auth.d.ts # module augmentation for Session.user.id, role
153
177
  config/
154
178
  env.ts # runtime-validated env (Zod parsed at startup)
155
179
  tests/
@@ -159,105 +183,124 @@ Top-level shape:
159
183
  ```
160
184
 
161
185
  **Dependency rules (enforced):**
162
- - `app/` routes import from `components/`, `redux/`, `lib/`, `config/` — never the other way.
163
- - `redux/features/` may import from `redux/api/` (for endpoint matchers); the reverse is forbidden.
186
+
187
+ - `app/` routes import from `components/`, `redux/`, `lib/`, `config/` never the reverse.
188
+ - `app/api/**/route.ts` files import `@/auth`, `@/lib/db`, `@/lib/api-auth`, and Zod schemas from feature folders — never from `redux/`.
189
+ - `redux/` never imports from `app/api/**` (handlers) or `prisma/` — RTK Query talks to handlers over HTTP, not through in-process function calls.
164
190
  - `components/ui/` (shadcn primitives) must not import from `app/`, `redux/`, or feature code.
165
- - Feature `_components/` and `_hooks/` are **private**: only routes inside the same feature folder may import them. If a component is needed by two features, promote it to `src/components/`.
191
+ - Feature `_components/` and `_hooks/` are **private**: only routes inside the same feature folder may import them.
166
192
 
167
193
  ## Required code patterns
168
194
 
169
- Full templates are in [`references/templates/`](references/templates/). The full Keep/Eliminate rationale (with the failure modes that motivated each rule) is in [`references/good-patterns.md`](references/good-patterns.md) and [`references/anti-patterns.md`](references/anti-patterns.md).
195
+ Full templates are in [`references/templates/`](references/templates/). Rationale for each Keep/Eliminate rule is in [`references/good-patterns.md`](references/good-patterns.md) and [`references/anti-patterns.md`](references/anti-patterns.md).
170
196
 
171
197
  ### Keep
172
198
 
173
- - **Server root layout and server root page**. `app/layout.tsx` is a server component that renders `<html><body><Providers>{children}</Providers></body></html>`. `app/page.tsx` is a server component that calls `redirect('/dashboard')` (or whichever default) never a `'use client'` component that calls `router.push` in `useEffect`. See [`references/templates/root-layout.md`](references/templates/root-layout.md).
174
- - **Route groups for auth boundaries**: `(public)`, `(app)`, optional `(admin)`. Each group has its own `layout.tsx`. The shell (header/sidebar) lives in `(app)/layout.tsx`.
175
- - **Server-side auth in `middleware.ts`** at project root. The middleware checks the session cookie and 302s unauthenticated requests to `/auth/login`. Client-side redirects are a fallback for token expiry during a session, not the primary guard. See [`references/templates/middleware.md`](references/templates/middleware.md).
176
- - **One RTK Query base `api`** in `redux/api/api.ts` with `endpoints: () => ({})`, plus domain slices that call `api.injectEndpoints(...)`. Tag types are a `const` array reused via `tagTypes`. See [`references/templates/api-base.md`](references/templates/api-base.md) and [`references/templates/api-slice.md`](references/templates/api-slice.md).
177
- - **Auth-aware `baseQuery`** that injects the bearer token from cookies/state and, on a 401, dispatches a clean logout (clears state via the store's root reducer, then routes to `/auth/login`). No hard `window.location.href = ...` from inside the base query.
178
- - **Typed Redux hooks**: `useAppDispatch`/`useAppSelector` exported from `redux/hooks.ts`. Components never use the raw `useDispatch`/`useSelector`.
179
- - **Strict store config**: `serializableCheck` left at the default; if a specific path or action genuinely needs an exception, configure `ignoredPaths` / `ignoredActions` explicitly with a comment explaining why. No `@ts-ignore`.
180
- - **Logout clears state via the root reducer**: a `combinedReducer` is wrapped so that on the logout-fulfilled action, state is reset before delegating to the combined reducer. Pattern is fine; the implementation must be fully typed (no `// @ts-ignore`).
181
- - **shadcn/ui + Tailwind + Radix**: shadcn primitives in `components/ui/` (generated, owned by the project, not a node_modules dependency). Composed form fields in `components/forms/`. `cn()` util in `lib/utils.ts` is the single source of class merging.
182
- - **React Hook Form + Zod**: every form uses `useForm({ resolver: zodResolver(schema), defaultValues: getDefaultValuesFromSchema(unwrapZodEffects(schema)) })`. Zod is the source of truth for defaults, max lengths, and validation. See [`references/templates/form-with-zod.md`](references/templates/form-with-zod.md).
183
- - **`UnsavedChangesWarning`** component wired to React Hook Form's `formState.isDirty`, intercepts in-app and `beforeunload` navigation.
184
- - **Per-feature `_components/` and `_hooks/`** folders, private to that route.
185
- - **`error.tsx`, `loading.tsx`, `not-found.tsx` at every meaningful route segment**. The `(app)` group must have a `loading.tsx` and `error.tsx` minimum.
186
- - **Runtime env validation** in `src/config/env.ts` using Zod, parsed at module load — fail fast on misconfiguration.
187
- - **Single date library: `date-fns`**. No `moment`. Format helpers live in `lib/formatters/`.
188
- - **One typography & color theme via Tailwind tokens + CSS variables** (the shadcn default). Custom colors named with a project prefix (e.g. `brand-primary`).
199
+ - **Server root layout, client pages.** `src/app/layout.tsx` is a server component that renders `<html><body><Providers>{children}</Providers></body></html>`. **Every other `page.tsx` is `'use client'`** and uses RTK Query for data. Per-route metadata lives at the layout level (server) pages can't export `metadata` because they're client. See [`references/templates/root-layout.md`](references/templates/root-layout.md).
200
+ - **Route groups for auth boundaries**: `(public)`, `(app)`, optional `(admin)`. Each group has its own `layout.tsx`. The shell (header/sidebar) lives in `(app)/layout.tsx` rendering an `'use client'` child from `_components/`.
201
+ - **NextAuth (Auth.js v5)** as the single source of auth truth. `src/auth.ts` exports `{ handlers, auth, signIn, signOut }`. `middleware.ts` re-exports `auth` (or wraps it for role/path logic) with an Edge-safe `src/auth.config.ts`. See [`references/templates/nextauth-config.md`](references/templates/nextauth-config.md).
202
+ - **Route Handlers as the backend**. Every `/api/<domain>/route.ts` calls `await auth()` first; unauthenticated requests 401. Inputs validated with the same Zod schema the form uses. Database access via the Prisma singleton in `src/lib/db.ts`. See [`references/templates/route-handler.md`](references/templates/route-handler.md).
203
+ - **One RTK Query base `api`** in `redux/api/api.ts` with `baseUrl: '/api'`, `credentials: 'include'`, and `endpoints: () => ({})`. Domain slices call `api.injectEndpoints(...)`. Tag types are a `const` array. See [`references/templates/api-base.md`](references/templates/api-base.md) and [`references/templates/api-slice.md`](references/templates/api-slice.md).
204
+ - **Auth-aware `baseQuery`**: on 401, dispatches NextAuth `signOut({ callbackUrl: '/auth/login' })`. No hard `window.location.href = ...`. The session cookie is sent automatically because `credentials: 'include'` is set and the API is same-origin.
205
+ - **Typed Redux hooks**: `useAppDispatch`/`useAppSelector` from `redux/hooks.ts`. Components never use the raw `useDispatch`/`useSelector`.
206
+ - **Strict store config**: `serializableCheck` left at the default. Targeted exceptions with comments are fine; blanket `false` is not. No `@ts-ignore`.
207
+ - **Prisma singleton** in `src/lib/db.ts` to avoid exhausting connections during dev hot-reload. See [`references/templates/db-client.md`](references/templates/db-client.md).
208
+ - **Prisma schema covers NextAuth + domain**. NextAuth tables (`User`, `Account`, `Session`, `VerificationToken`) plus a `password` column on `User` for Credentials. Domain models live in the same file. See [`references/templates/prisma-schema.md`](references/templates/prisma-schema.md).
209
+ - **shadcn/ui + Tailwind + Radix**: shadcn primitives in `components/ui/` (owned by the project, not a node_modules dependency). Composed form fields in `components/forms/`. `cn()` util in `lib/utils.ts` is the single source of class merging.
210
+ - **React Hook Form + Zod**: every form uses `useForm({ resolver: zodResolver(schema), defaultValues: getDefaultValuesFromSchema(unwrapZodEffects(schema)) })`. The same Zod schema validates request bodies in the matching Route Handler. See [`references/templates/form-with-zod.md`](references/templates/form-with-zod.md).
211
+ - **`UnsavedChangesWarning`** wired to React Hook Form's `formState.isDirty`.
212
+ - **Per-feature `_components/` and `_hooks/`** private to that route.
213
+ - **`error.tsx` and `loading.tsx` at every meaningful route segment**.
214
+ - **Runtime env validation** in `src/config/env.ts` using Zod. `AUTH_SECRET`, `DATABASE_URL`, `AUTH_URL` (production), and any OAuth provider keys are required.
215
+ - **Single date library: `date-fns`**. No `moment`.
216
+ - **Minimal comments in generated code.** Default to no comments. Only add one when the *why* is non-obvious — a workaround for a specific upstream issue (with a link), a subtle invariant the code depends on, a domain rule that isn't visible from the names. Never write block headers, never restate *what* the next line does, never leave `// TODO` without an issue link. One short line max — no multi-line comment blocks, no multi-paragraph JSDoc. Well-named identifiers carry the *what*; comments earn their place only when they carry *why*.
189
217
  - **`tsconfig.json` strict + `@/*` path alias** — see [`references/templates/tsconfig.md`](references/templates/tsconfig.md).
190
- - **Vitest + RTL for unit tests, Playwright for E2E**, configured but lightweight by default. At least one smoke test per layer (a reducer test, a component test, an E2E auth flow) so CI has something real to run.
191
- - **Husky + lint-staged** pre-commit: `prettier --write` + `eslint --fix` + `tsc --noEmit` on staged files.
192
- - **GitHub Actions CI** running install → lint → typecheck → test → build on every PR.
218
+ - **Vitest + RTL for unit tests, Playwright for E2E**. At least: one reducer test, one schema test, one component test, one E2E auth-then-dashboard flow.
219
+ - **Husky + lint-staged** pre-commit: `prettier --write` + `eslint --fix` on staged files.
220
+ - **GitHub Actions CI** running install → lint → typecheck → test → build on every PR. Tests use a throwaway Postgres service container.
193
221
 
194
222
  ### Eliminate (anti-patterns)
195
223
 
196
- Every one of these is forbidden in generated code. Rationale for each is in [`references/anti-patterns.md`](references/anti-patterns.md).
197
-
198
- - ❌ `'use client'` on `app/page.tsx`, `app/layout.tsx`, or any route-group `layout.tsx` that doesn't actually need client-only hooks. Layouts should be server components by default; only mark interactive children client.
199
- - ❌ Redirecting from the root by mounting `'use client'` + `useEffect(() => router.push('/dashboard'))`. Use server `redirect('/dashboard')` from `next/navigation` inside a server `page.tsx`, or do the redirect in `middleware.ts`.
200
- - ❌ `serializableCheck: false` on the store config without targeted `ignoredPaths`/`ignoredActions` and a comment explaining the exception. Silencing the global check hides real bugs.
201
- - ❌ `@ts-ignore` / `as any` anywhere in the store, providers, or API layer. If a type is awkward, fix the type; don't suppress the compiler.
202
- - ❌ Commented-out reducers, endpoints, or imports left in `store.ts`/`api.ts`. Either wire it up or delete it.
203
- - ❌ Mixing `moment` and `date-fns`. Pick `date-fns` (smaller, tree-shakeable, ESM, immutable). Never add `moment` to a new project.
204
- - ❌ `styled-components` (or Emotion) in a Tailwind project. The stack is Tailwind + Radix + cva + shadcn — adding a CSS-in-JS runtime is duplicate machinery.
205
- - ❌ Two folders or files that differ only by case (e.g. `stateProjectReports/` and `stateprojectreport/`). They break on case-sensitive filesystems (Linux CI, Docker) even if they work on Windows/macOS. Enforce one canonical name.
206
- - ❌ `dangerouslySetInnerHTML` with API-sourced content that hasn't been server-sanitized. If HTML rendering is genuinely needed, route through a sanitizer (DOMPurify on the client, or server-side rendering through a strict allowlist) and add an inline comment naming the sanitization point.
207
- - ❌ `sessionStorage` / `localStorage` for state that isn't transient client-only UI state. Page-to-page handoff goes through URL search params or Redux. Tokens never go in `localStorage`.
208
- - ❌ JWT tokens stored in JS-accessible cookies (`js-cookie` `Cookies.set('token', ...)`) when you can put them in `httpOnly` cookies set by the server / middleware. If a JS-accessible token is unavoidable for the chosen auth flow, document the XSS surface and lock down `dangerouslySetInnerHTML` use accordingly.
209
- - ❌ A `proxy.ts` (or similarly-named file) at `src/` root that *looks* like middleware but isn't wired through Next.js's `middleware.ts` convention. There is exactly one place auth lives: `middleware.ts` at the project root.
210
- - ❌ Inline `fetch` calls in components for backend data. All backend calls go through RTK Query (or a typed wrapper if RTK Query is genuinely the wrong fit for that case but justify it). One way to call the API per project.
211
- - ❌ Redux slices for state that should be local component state, URL state, or React Hook Form state. Reach for `useState` / `useReducer` first, then `useSearchParams`, then Redux.
212
- - ❌ Many independent `createApi()` instances. One base `api` + `injectEndpoints` per domain. Multiple reducerPaths fragment the cache.
213
- - ❌ Hard `window.location.href = '/auth'` redirects from inside the base query as the primary 401 handler. Dispatch a clean logout action, let the router or middleware handle the navigation.
214
- - ❌ Skipping `loading.tsx` / `error.tsx` / `not-found.tsx` on authenticated route groups. Users hit blank screens during data fetches and silent failures on RTK Query errors.
215
- - ❌ No tests at all (no Vitest, no Playwright, no `test` script). Even a smoke test gives CI something to enforce; zero tests means every change is a regression risk.
216
- - ❌ ESLint extending only `next/core-web-vitals`. Add `@typescript-eslint/recommended`, `react-hooks`, `jsx-a11y`, and project rules (`no-console: warn`, `no-explicit-any: error`, `prefer-const: error`, `react-hooks/exhaustive-deps: error`).
217
- - ❌ Hand-rolled spacing/animation extensions in `tailwind.config.ts` with dozens of commented-out values. Extend Tailwind only for genuine design-system tokens (brand colors, fonts). Use Tailwind's defaults for spacing and timing.
218
- - ❌ Per-feature client guards (e.g. an `<AuthExpirationHandler>` component) as the only auth check. Server-side `middleware.ts` is the primary guard; client guards are belt-and-suspenders for token expiry mid-session, not the gate.
224
+ Every one of these is forbidden in generated code. Rationale in [`references/anti-patterns.md`](references/anti-patterns.md).
225
+
226
+ - ❌ **`fetch()` or `await db.*` inside a server component** (server `page.tsx`, `layout.tsx`, or any non-`'use client'` file under `app/` that isn't `route.ts`). All data goes through RTK Query Route Handlers. The app is "API-driven, not SSR" by deliberate choice.
227
+ - ❌ **Server Actions** (`'use server'` functions called from client components). The skill does not emit any. Mutations go through Route Handlers + RTK Query mutations.
228
+ - ❌ **`async page.tsx`** pages are `'use client'` and synchronous. The body uses RTK Query hooks.
229
+ - ❌ **`redirect()` from a server `page.tsx`** as the auth-gate fallback. The auth gate is `middleware.ts`. The root `/` redirect is also middleware's job (e.g. send signed-in users to `/app/dashboard`, signed-out to `/auth/login`).
230
+ - ❌ **Custom JWT-in-`httpOnly`-cookie schemes alongside NextAuth.** Pick one. The default is NextAuth — don't generate a parallel `setCookie('session', ...)` flow in a Route Handler.
231
+ - ❌ **Decoding the NextAuth JWT manually on the client** to drive auth decisions. Use `useSession()` from `next-auth/react` (or call `await auth()` server-side in Route Handlers).
232
+ - ❌ **`serializableCheck: false`** on the store config without targeted `ignoredPaths`/`ignoredActions` and a comment explaining the exception.
233
+ - ❌ **`@ts-ignore` / `as any`** anywhere in the store, providers, API layer, or Route Handlers.
234
+ - ❌ **Commented-out reducers, endpoints, or imports** left in `store.ts`/`api.ts`.
235
+ - ❌ **Mixing `moment` and `date-fns`**. Pick `date-fns`.
236
+ - ❌ **`styled-components` (or Emotion) in a Tailwind project.**
237
+ - ❌ **Two folders or files that differ only by case** (breaks on Linux CI).
238
+ - ❌ **`dangerouslySetInnerHTML` with API-sourced content that hasn't been sanitized.**
239
+ - ❌ **`sessionStorage` / `localStorage` for state that isn't transient client-only UI state.** Tokens never go in `localStorage` NextAuth handles cookies.
240
+ - ❌ **A `proxy.ts` (or similarly-named file)** at `src/` root standing in for `middleware.ts`.
241
+ - ❌ **Inline `fetch` calls in components for backend data.** All backend calls go through RTK Query.
242
+ - ❌ **Redux slices for state that should be local component state, URL state, or React Hook Form state.** Reach for `useState` / `useReducer` first, then `useSearchParams`, then Redux.
243
+ - ❌ **Many independent `createApi()` instances.** One base `api` + `injectEndpoints` per domain.
244
+ - ❌ **Hard `window.location.href = '/auth/login'` redirects from inside the base query** as the primary 401 handler. Dispatch `signOut({ callbackUrl: '/auth/login' })`.
245
+ - ❌ **Skipping `loading.tsx` / `error.tsx`** on authenticated route groups.
246
+ - ❌ **Multiple `PrismaClient` instances.** Use the singleton in `src/lib/db.ts`.
247
+ - ❌ **Route Handlers that skip the `await auth()` check.** Every handler authenticates first.
248
+ - ❌ **Route Handlers that trust client-sent user IDs** for ownership. Read the user ID from the session, not the request body.
249
+ - ❌ **`prisma db push` in CI or any non-dev environment.** Migrations only.
250
+ - ❌ **No tests at all.**
251
+ - ❌ **ESLint extending only `next/core-web-vitals`.**
219
252
 
220
253
  ## Operating-mode playbooks
221
254
 
222
255
  ### Mode 1 — `scaffold-project`
223
256
 
224
257
  1. Resolve versions per **Step 1**. Quote them.
225
- 2. Ask the inputs per **Step 2**. Wait for answers.
258
+ 2. Ask the inputs per **Step 2** (database host, NextAuth providers, route groups, optional extras). Wait for answers.
226
259
  3. Generate, in this order:
227
- 1. `package.json`, `tsconfig.json`, `next.config.ts`, `tailwind.config.ts`, `postcss.config.js`, `components.json`, `.eslintrc.json` (or `eslint.config.mjs`), `.prettierrc`, `.gitignore`, `.env.example`, `README.md`.
228
- 2. `middleware.ts` at project root (auth guard).
229
- 3. `src/app/layout.tsx` (server), `src/app/page.tsx` (server, `redirect()`), `src/app/globals.css`, `src/app/error.tsx`, `src/app/not-found.tsx`.
230
- 4. Route groups: `src/app/(public)/layout.tsx` + a basic `auth/login/page.tsx`, `src/app/(app)/layout.tsx` + `loading.tsx` + `error.tsx`, plus `(admin)/` if requested.
231
- 5. `src/redux/store.ts`, `src/redux/providers.tsx`, `src/redux/hooks.ts`.
232
- 6. `src/redux/api/api.ts` (base), `src/redux/api/tags.ts`, `src/redux/api/authApi.ts`.
233
- 7. `src/redux/features/authSlice.ts`.
234
- 8. `src/components/ui/` with the shadcn primitives actually needed by the templates (start with button, input, label, form, dialog, toast add more on demand).
235
- 9. `src/components/forms/` composed fields (`FormInputField`, `FormPasswordField`, `FormSelectField`, `FormDatePickerField` only those needed by generated forms).
236
- 10. `src/components/UnsavedChangesWarning.tsx`, `src/components/Notifications.tsx`.
237
- 11. `src/lib/utils.ts` (`cn()`), `src/lib/zod-utils.ts`.
238
- 12. `src/config/env.ts` (Zod-validated runtime env).
239
- 13. `tests/unit/` with one reducer test + one component test. `tests/e2e/` with one Playwright smoke spec.
240
- 14. `vitest.config.ts`, `playwright.config.ts`.
241
- 15. `.husky/pre-commit`, `lint-staged` config in `package.json`.
242
- 16. `.github/workflows/ci.yml`.
243
- 4. `pnpm install` (or chosen PM).
244
- 5. `pnpm typecheck && pnpm lint && pnpm test && pnpm build` — must all pass.
245
- 6. If a first feature was requested, immediately run **Mode 2** for that feature.
246
- 7. Report.
260
+ 1. `package.json`, `tsconfig.json`, `next.config.ts`, `tailwind.config.ts`, `postcss.config.js`, `components.json`, `.eslintrc.json` (or `eslint.config.mjs`), `.prettierrc`, `.gitignore`, `.env.example`, `README.md`. Add `docker-compose.yml` if Docker was chosen.
261
+ 2. `prisma/schema.prisma` with NextAuth tables + sample domain model + (if Credentials) `password` column. `prisma/seed.ts` if a test user was requested.
262
+ 3. `src/auth.config.ts` (Edge-safe), `src/auth.ts` (full config with adapter + providers), `src/types/next-auth.d.ts`.
263
+ 4. `middleware.ts` at project root (re-exports / wraps `auth`).
264
+ 5. `src/app/api/auth/[...nextauth]/route.ts`.
265
+ 6. `src/lib/db.ts` (Prisma singleton), `src/lib/api-auth.ts` (`requireSession()` helper), `src/lib/utils.ts`, `src/lib/zod-utils.ts`.
266
+ 7. `src/app/layout.tsx` (server, renders Providers), `src/app/globals.css`, `src/app/error.tsx`, `src/app/not-found.tsx`. **No `src/app/page.tsx` that does `redirect()`** — middleware handles `/`. If a `/` page is needed (marketing landing), it's `'use client'`.
267
+ 8. Route groups: `src/app/(public)/layout.tsx` + `auth/login/page.tsx` ('use client', calls `signIn`), `src/app/(app)/layout.tsx` + `_components/AppShell.tsx` + `loading.tsx` + `error.tsx`, plus `(admin)/` if requested.
268
+ 9. `src/redux/store.ts`, `src/redux/providers.tsx` (wraps `<SessionProvider>` + `<Provider>`), `src/redux/hooks.ts`.
269
+ 10. `src/redux/api/api.ts` (base, `baseUrl: '/api'`), `src/redux/api/tags.ts`.
270
+ 11. `src/components/ui/` with shadcn primitives needed by templates (start with button, input, label, form, dialog, toast).
271
+ 12. `src/components/forms/` composed fields actually used by generated forms.
272
+ 13. `src/components/UnsavedChangesWarning.tsx`, `src/components/Notifications.tsx`.
273
+ 14. `src/config/env.ts` (Zod-validated runtime env).
274
+ 15. `tests/unit/` with one reducer test + one schema test + one component test. `tests/e2e/` with a Playwright spec that logs in and asserts the dashboard.
275
+ 16. `vitest.config.ts`, `playwright.config.ts`.
276
+ 17. `.husky/pre-commit`, `lint-staged` config in `package.json`.
277
+ 18. `.github/workflows/ci.yml` with a Postgres service container.
278
+ 4. Install dependencies (`pnpm install`).
279
+ 5. **Database setup per Step 4** (`prisma generate`, `prisma migrate dev --name init`).
280
+ 6. `pnpm typecheck && pnpm lint && pnpm test && pnpm build` — must all pass.
281
+ 7. If a first feature was requested, immediately run **Mode 2** for that feature.
282
+ 8. Report.
247
283
 
248
284
  ### Mode 2 — `add-feature`
249
285
 
250
286
  For feature `{{Feature}}` in route group `{{Group}}` (e.g. `(app)`):
251
287
 
252
- 1. **Routing**:
253
- - `src/app/{{Group}}/{{feature}}/page.tsx` server component by default. If the feature needs client interactivity, the page is server and renders a `'use client'` child from `_components/`.
254
- - `src/app/{{Group}}/{{feature}}/loading.tsx` (Suspense fallback).
255
- - `src/app/{{Group}}/{{feature}}/error.tsx` (error boundary).
256
- 2. **Schema**: `src/app/{{Group}}/{{feature}}/schema.ts` — exports `{{feature}}Schema` (Zod) and inferred `{{Feature}}FormValues` type.
257
- 3. **Private components**: `src/app/{{Group}}/{{feature}}/_components/{{Feature}}Form.tsx` `'use client'`, uses `useForm` + `zodResolver`, wraps `<UnsavedChangesWarning>`, dispatches RTK Query mutation on submit.
258
- 4. **Private hooks**: `src/app/{{Group}}/{{feature}}/_hooks/use{{Feature}}.ts` — if there's per-feature derived state.
259
- 5. **API endpoints**: extend `src/redux/api/{{domain}}Api.ts` (or run Mode 3 first if no slice exists yet) with query + mutation for this feature.
260
- 6. **Tests**: `tests/unit/{{feature}}.schema.test.ts` (validates the Zod schema with valid + invalid inputs).
288
+ 1. **Schema** (shared between form and Route Handler): `src/app/{{Group}}/{{feature}}/schema.ts` — exports `{{feature}}Schema` (Zod) and inferred `{{Feature}}FormValues` type.
289
+ 2. **Prisma model**: add a `{{Feature}}` model to `prisma/schema.prisma` if it doesn't exist. Run `pnpm exec prisma migrate dev --name add-{{feature}}`.
290
+ 3. **Route Handlers**:
291
+ - `src/app/api/{{feature}}s/route.ts` — `GET` (list) + `POST` (create). Both call `requireSession()`. `POST` validates the body with `{{feature}}Schema.safeParse`.
292
+ - `src/app/api/{{feature}}s/[id]/route.ts` — `GET` + `PATCH` + `DELETE`. All call `requireSession()`. Ownership check: `where: { id, userId: session.user.id }`.
293
+ 4. **RTK Query slice**: extend `src/redux/api/{{feature}}sApi.ts` with `getList`, `get`, `create`, `update`, `delete` endpoints. If the slice doesn't exist, run Mode 3 first.
294
+ 5. **Routing**:
295
+ - `src/app/{{Group}}/{{feature}}s/page.tsx` `'use client'`. Uses `useGet{{Feature}}sQuery()`. Renders `{{Feature}}sTable` from `_components/`.
296
+ - `src/app/{{Group}}/{{feature}}s/loading.tsx` (Suspense fallback).
297
+ - `src/app/{{Group}}/{{feature}}s/error.tsx` (error boundary).
298
+ - `src/app/{{Group}}/{{feature}}s/new/page.tsx` — `'use client'`. Renders `{{Feature}}Form mode="create"`.
299
+ - `src/app/{{Group}}/{{feature}}s/[id]/page.tsx` — `'use client'`. Renders `{{Feature}}Form mode="edit" id={params.id}`.
300
+ 6. **Private components**:
301
+ - `_components/{{Feature}}sTable.tsx` — `'use client'`, uses `useGet{{Feature}}sQuery`.
302
+ - `_components/{{Feature}}Form.tsx` — `'use client'`, uses `useForm` + `zodResolver`, wraps `<UnsavedChangesWarning>`, dispatches create/update mutation on submit.
303
+ 7. **Tests**: `tests/unit/{{feature}}.schema.test.ts` (Zod schema valid + invalid). Optional handler test that mocks `db` and `auth`.
261
304
 
262
305
  After generating: `pnpm typecheck && pnpm test && pnpm build`.
263
306
 
@@ -265,64 +308,75 @@ After generating: `pnpm typecheck && pnpm test && pnpm build`.
265
308
 
266
309
  For domain `{{domain}}` (e.g. `customers`):
267
310
 
268
- 1. Create `src/redux/api/{{domain}}Api.ts` that imports the base `api` from `./api` and calls `api.injectEndpoints(...)`.
269
- 2. Each endpoint:
270
- - Strongly typed request/response (no `any`).
271
- - `providesTags` on queries, `invalidatesTags` on mutations, both referencing constants from `tags.ts`.
272
- - `transformResponse` / `transformErrorResponse` only when the API contract demands it; otherwise return raw.
273
- 3. Add new tag types to `src/redux/api/tags.ts`. The `tagTypes` array on the base `api` reads from this constant.
274
- 4. Export the generated hooks (`use{{Domain}}GetXQuery`, `use{{Domain}}CreateXMutation`, etc.) from the slice file.
275
- 5. **Do not** create a new `createApi(...)`. One base `api`, many injected slices.
311
+ 1. Create `src/redux/api/{{domain}}Api.ts` that imports the base `api` and calls `api.injectEndpoints(...)`. Strongly typed request/response. `providesTags` on queries, `invalidatesTags` on mutations.
312
+ 2. Add new tag types to `src/redux/api/tags.ts`. The `tagTypes` array on the base `api` reads from this constant.
313
+ 3. Export generated hooks (`useGet{{Domain}}sQuery`, `useCreate{{Domain}}Mutation`, etc.).
314
+ 4. **Create the matching Route Handlers** under `src/app/api/{{domain}}/...` every endpoint needs a handler. See [`references/templates/route-handler.md`](references/templates/route-handler.md).
315
+ 5. Add the Prisma model(s) and migrate if needed.
316
+ 6. **Do not** create a new `createApi(...)`. One base `api`, many injected slices.
276
317
 
277
- After generating: `pnpm typecheck` must pass.
318
+ After generating: `pnpm typecheck && pnpm build` must pass.
278
319
 
279
320
  ## Verification checklist before reporting "done"
280
321
 
281
322
  - [ ] `pnpm install` succeeds.
323
+ - [ ] `pnpm exec prisma generate` succeeds.
324
+ - [ ] `pnpm exec prisma migrate dev --name init` succeeds (or the user confirmed they ran it manually).
282
325
  - [ ] `pnpm typecheck` exits 0.
283
- - [ ] `pnpm lint` exits 0 (no warnings either, on a fresh scaffold).
284
- - [ ] `pnpm test` exits 0 (Vitest).
285
- - [ ] `pnpm build` succeeds (catches RSC boundary errors).
286
- - [ ] `pnpm exec playwright test --list` lists the smoke spec (don't run the browser in CI without a server unless asked).
287
- - [ ] No file contains any pattern from the **Eliminate** list — verify by grepping for: `'use client'` in `app/page.tsx` and `app/layout.tsx`, `router.push` inside a `useEffect` body in `app/page.tsx`, `serializableCheck: false`, `@ts-ignore`, `as any`, `import .* from ['"]moment['"]`, `import .* from ['"]styled-components['"]`, `dangerouslySetInnerHTML` (any hit must have a sanitization comment), `Cookies.set\(['"]token['"]` (must be `httpOnly` cookie set by middleware unless documented), inline `fetch(` in `app/**/page.tsx`.
288
- - [ ] `middleware.ts` exists at project root and is wired (has a `config.matcher` that covers the `(app)` and `(admin)` groups).
289
- - [ ] `src/app/page.tsx` does **not** contain `'use client'` and does **not** contain `useEffect`. It either renders content or calls `redirect()`.
290
- - [ ] No duplicate-by-case folders anywhere in `src/`.
291
- - [ ] `.env` is **not** committed; `.env.example` is.
292
-
293
- If any check fails, fix before reporting. Don't claim success with a known-broken scaffold.
326
+ - [ ] `pnpm lint` exits 0 (no warnings on a fresh scaffold).
327
+ - [ ] `pnpm test` exits 0.
328
+ - [ ] `pnpm build` succeeds.
329
+ - [ ] No file under `src/app/**` outside `route.ts` files imports `@/lib/db` or calls `await db.*` (server pages don't touch the DB). Grep: `grep -rn "from '@/lib/db'" src/app/ --include='*.tsx'` returns nothing.
330
+ - [ ] Every `route.ts` file in `src/app/api/**` (except `[...nextauth]`) calls `await auth()` or `await requireSession()`.
331
+ - [ ] No `'use server'` directive anywhere. Grep: `grep -rn "'use server'" src/` returns nothing.
332
+ - [ ] No `async function .*Page` in any `page.tsx`. Pages are sync `'use client'`.
333
+ - [ ] No `serializableCheck: false`, `@ts-ignore`, `as any` in `src/redux/**` or `src/app/api/**`.
334
+ - [ ] `middleware.ts` exists at project root; its `config.matcher` excludes `/api/auth` (NextAuth handles its own routes).
335
+ - [ ] `src/auth.ts` and `src/auth.config.ts` both exist. `auth.config.ts` has no `@/lib/db` import (Edge-safe).
336
+ - [ ] `.env` is **not** committed; `.env.example` is. `AUTH_SECRET` is **not** in `.env.example` (it's documented as required, with instructions to generate it).
337
+ - [ ] No duplicate-by-case folders.
338
+
339
+ If any check fails, fix before reporting.
294
340
 
295
341
  ## Examples
296
342
 
297
- ### Example 1: Fresh project
343
+ ### Example 1: Fresh fullstack project
298
344
 
299
- **User:** "Scaffold a new Next.js frontend using my App Router patterns. Call it `acme-portal`. Add a `dashboard` feature too."
345
+ **User:** "Scaffold a new Next.js fullstack app with NextAuth and Prisma. Call it `acme-portal`. Add a `dashboard` feature too."
300
346
 
301
347
  **Claude:**
302
- 1. Runs `node --version` / `pnpm --version`. Resolves latest stable Next.js, React, RTK, Tailwind, Zod versions via context7.
303
- 2. Reports chosen versions and waits for confirmation if anything looks off.
304
- 3. Asks the Step-2 questions (route groups, auth flavor, real-time, optional extras).
305
- 4. Generates the full project + the `dashboard` feature slice in `(app)/dashboard/`.
306
- 5. Runs install, typecheck, lint, test, build all must pass.
307
- 6. Reports the tree, env vars to set, and `pnpm dev` next step.
348
+ 1. Runs `node --version` / `pnpm --version`. Resolves Next.js, React, NextAuth v5, Prisma, RTK, Tailwind, Zod versions via context7. Quotes them.
349
+ 2. Asks Step-2 questions: DB host (local Docker / Neon / Supabase / own), NextAuth providers (Credentials / GitHub / Google / all), route groups, extras.
350
+ 3. Generates the full project + the `dashboard` feature slice in `(app)/dashboard/` with a matching `src/app/api/dashboard/route.ts`.
351
+ 4. Runs install, `prisma generate`, `prisma migrate dev --name init`, typecheck, lint, test, build — all must pass.
352
+ 5. Reports: project path, env vars to set (`AUTH_SECRET`, `DATABASE_URL`), seeded test credentials (if Credentials provider was chosen), `pnpm dev`.
308
353
 
309
354
  ### Example 2: Add a feature
310
355
 
311
- **User:** "Add a `customers` feature end-to-end under the (app) group — list view + create form."
356
+ **User:** "Add a `customers` feature end-to-end under the (app) group — list + create + edit."
312
357
 
313
- **Claude:** Runs Mode 2. If no `customersApi` exists yet, runs Mode 3 first to create the slice with `getCustomers`, `getCustomer`, `createCustomer`, `updateCustomer` endpoints and a `Customers` tag type. Then generates `(app)/customers/page.tsx` (server, fetches list via the query hook from a `'use client'` child), `(app)/customers/_components/CustomersTable.tsx`, `(app)/customers/new/page.tsx` + `_components/CustomerForm.tsx` with Zod schema. Adds a schema unit test. Builds and tests.
358
+ **Claude:** Runs Mode 2. If no `customersApi` exists, runs Mode 3 first. Generates:
359
+ - `prisma/schema.prisma` model addition + migration.
360
+ - `src/app/api/customers/route.ts` (GET list, POST create — both `requireSession()`-gated, POST validates with `customerSchema`).
361
+ - `src/app/api/customers/[id]/route.ts` (GET / PATCH / DELETE — ownership-checked).
362
+ - `src/redux/api/customersApi.ts` with five endpoints injected.
363
+ - `src/app/(app)/customers/page.tsx`, `new/page.tsx`, `[id]/page.tsx`, `loading.tsx`, `error.tsx` — all `'use client'`.
364
+ - `src/app/(app)/customers/_components/CustomersTable.tsx`, `CustomerForm.tsx`.
365
+ - `src/app/(app)/customers/schema.ts` (Zod).
366
+ - `tests/unit/customer.schema.test.ts`.
367
+ - Adds `'Customer'` + `'Customers'` to `tags.ts`.
314
368
 
315
- ### Example 3: Add an API slice
369
+ ### Example 3: Add an API slice + handlers
316
370
 
317
371
  **User:** "Add an RTK Query slice for `invoices` with list, get, create, mark-paid endpoints."
318
372
 
319
- **Claude:** Runs Mode 3. Creates `src/redux/api/invoicesApi.ts` injecting four endpoints into the base `api`, adds `'Invoices'` + `'Invoice'` to `tags.ts`, exports the typed hooks. Typechecks.
373
+ **Claude:** Runs Mode 3. Creates `src/redux/api/invoicesApi.ts` injecting four endpoints, adds `'Invoices'` + `'Invoice'` to `tags.ts`, generates `src/app/api/invoices/route.ts` (GET list + POST create), `src/app/api/invoices/[id]/route.ts` (GET + PATCH), `src/app/api/invoices/[id]/mark-paid/route.ts` (POST). Adds the `Invoice` Prisma model and runs `prisma migrate dev --name add-invoices`. Typechecks.
320
374
 
321
375
  ## Notes
322
376
 
323
- - **Don't over-engineer**. Don't add Storybook, i18n, Sentry, MSW, NextAuth, tRPC, or Server Actions wrappers unless the user asks. The default scaffold is intentionally lean.
324
- - **Don't rewrite the user's existing project** as part of this skill. This skill is for *new* scaffolds (and additive feature/slice modes), not migrations. If the user wants a migration plan, that's a different conversation.
325
- - **Server vs client**: default to server components. Add `'use client'` only when you actually use `useState`, `useEffect`, `useRouter` (client), event handlers, browser-only APIs, or Redux hooks. The fact that a component is interactive in production doesn't make its parent need `'use client'`.
326
- - **Auth**: prefer `httpOnly` cookies set by `middleware.ts` (server-readable, JS-unreadable). If the chosen backend forces a JS-readable token, document the XSS exposure and harden `dangerouslySetInnerHTML` usage.
327
- - **Versions**: always quote the resolved package versions before writing `package.json`. The user explicitly asked not to hard-code them.
328
- - **Naming**: kebab-case for files and folders inside `src/`, except React component files which match the component name in PascalCase (`CustomerForm.tsx`). Never have two paths that differ only by case.
377
+ - **Don't over-engineer.** No Storybook, i18n, Sentry, MSW, tRPC, or Server Actions wrappers unless the user asks. The default scaffold is intentionally lean.
378
+ - **Don't rewrite the user's existing project.** This skill is for *new* scaffolds (and additive feature/slice modes), not migrations.
379
+ - **Versions**: always quote the resolved package versions before writing `package.json`.
380
+ - **Naming**: kebab-case for files and folders inside `src/`, except React component files which match the component name in PascalCase (`CustomerForm.tsx`). Never two paths that differ only by case.
381
+ - **NextAuth Credentials caveat**: when Credentials is the only/primary provider, `session.strategy` must be `'jwt'` (database sessions don't work with Credentials). The Prisma adapter is still installed because the User table still lives in the DB — just the *session* is encoded in a JWT cookie. This is by NextAuth design; don't try to switch it to `'database'` for Credentials.
382
+ - **API-driven means API-driven.** If the user asks for SSR data fetching or Server Actions mid-scaffold, push back with the rationale (consistency, single mental model, easier mock/integration testing) before complying. Don't silently switch modes.