@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.
- package/README.md +87 -38
- package/package.json +1 -1
- package/skills/code-review/SKILL.md +270 -0
- package/skills/codebase-explainer/SKILL.md +112 -0
- package/skills/diagnose/SKILL.md +31 -1
- package/skills/dotnet-onion-api/SKILL.md +1 -0
- package/skills/nextjs-app-router/SKILL.md +229 -175
- package/skills/nextjs-app-router/references/anti-patterns.md +163 -99
- package/skills/nextjs-app-router/references/folder-layout.md +79 -46
- package/skills/nextjs-app-router/references/good-patterns.md +233 -99
- package/skills/nextjs-app-router/references/templates/api-base.md +24 -21
- package/skills/nextjs-app-router/references/templates/auth-slice.md +82 -78
- package/skills/nextjs-app-router/references/templates/ci-and-hooks.md +58 -6
- package/skills/nextjs-app-router/references/templates/db-client.md +48 -0
- package/skills/nextjs-app-router/references/templates/env-and-utils.md +90 -23
- package/skills/nextjs-app-router/references/templates/feature-slice.md +110 -47
- package/skills/nextjs-app-router/references/templates/form-with-zod.md +23 -15
- package/skills/nextjs-app-router/references/templates/middleware.md +69 -59
- package/skills/nextjs-app-router/references/templates/next-config.md +4 -14
- package/skills/nextjs-app-router/references/templates/nextauth-config.md +178 -0
- package/skills/nextjs-app-router/references/templates/package.md +35 -5
- package/skills/nextjs-app-router/references/templates/prisma-schema.md +162 -0
- package/skills/nextjs-app-router/references/templates/providers-and-store.md +35 -21
- package/skills/nextjs-app-router/references/templates/root-layout.md +99 -20
- package/skills/nextjs-app-router/references/templates/route-group-layouts.md +46 -6
- package/skills/nextjs-app-router/references/templates/route-handler.md +168 -0
- package/skills/nextjs-app-router/references/templates/testing.md +105 -31
- package/skills/plan-and-build/SKILL.md +45 -3
- package/skills/pr-review/SKILL.md +50 -3
- 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)
|
|
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
|
|
6
|
+
# Next.js App Router Fullstack Scaffolder (NextAuth + Prisma + RTK Query)
|
|
7
7
|
|
|
8
|
-
Generate a production-grade Next.js
|
|
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
|
|
15
|
-
- "Next.js App Router project" / "
|
|
16
|
-
- "RTK Query
|
|
17
|
-
- "shadcn/ui project" / "Tailwind + shadcn + Radix scaffold"
|
|
18
|
-
- "use my
|
|
19
|
-
- "add a feature
|
|
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
|
|
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`,
|
|
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
|
|
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
|
-
|
|
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`)
|
|
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
|
|
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
|
|
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
|
-
- **
|
|
61
|
-
- **
|
|
62
|
-
- **
|
|
63
|
-
- **
|
|
64
|
-
- **Optional extras**: Storybook? i18n? Sentry? Dockerfile? GitHub Actions CI?
|
|
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),
|
|
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
|
|
76
|
-
- Replace all `{{ProjectName}}`, `{{Feature}}`, `{{Domain}}` placeholders consistently. `{{
|
|
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
|
|
79
|
-
- Initialize shadcn/ui by writing `components.json` from [`references/templates/components
|
|
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
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
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
|
|
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 #
|
|
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 #
|
|
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
|
|
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
|
|
120
|
-
_components/
|
|
121
|
-
_hooks/
|
|
149
|
+
layout.tsx # server; renders <AppShell> ('use client' child)
|
|
150
|
+
_components/AppShell.tsx
|
|
122
151
|
loading.tsx
|
|
123
152
|
error.tsx
|
|
124
|
-
|
|
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
|
|
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
|
|
163
|
+
providers.tsx # 'use client'; wraps <SessionProvider><Provider><Toaster>
|
|
139
164
|
hooks.ts # typed useAppDispatch, useAppSelector
|
|
140
165
|
api/
|
|
141
|
-
api.ts # base createApi
|
|
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
|
-
|
|
152
|
-
|
|
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
|
-
|
|
163
|
-
- `
|
|
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.
|
|
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/).
|
|
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
|
|
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
|
-
- **
|
|
176
|
-
- **
|
|
177
|
-
- **
|
|
178
|
-
- **
|
|
179
|
-
- **
|
|
180
|
-
- **
|
|
181
|
-
- **
|
|
182
|
-
- **
|
|
183
|
-
-
|
|
184
|
-
- **
|
|
185
|
-
- **`
|
|
186
|
-
- **
|
|
187
|
-
-
|
|
188
|
-
- **
|
|
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
|
|
191
|
-
- **Husky + lint-staged** pre-commit: `prettier --write` + `eslint --fix`
|
|
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
|
|
197
|
-
|
|
198
|
-
- ❌ `
|
|
199
|
-
- ❌
|
|
200
|
-
- ❌
|
|
201
|
-
- ❌
|
|
202
|
-
- ❌
|
|
203
|
-
- ❌
|
|
204
|
-
- ❌
|
|
205
|
-
- ❌
|
|
206
|
-
- ❌
|
|
207
|
-
- ❌ `
|
|
208
|
-
- ❌
|
|
209
|
-
- ❌
|
|
210
|
-
- ❌
|
|
211
|
-
- ❌
|
|
212
|
-
- ❌
|
|
213
|
-
- ❌
|
|
214
|
-
- ❌
|
|
215
|
-
- ❌
|
|
216
|
-
- ❌
|
|
217
|
-
- ❌
|
|
218
|
-
- ❌
|
|
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
|
|
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. `
|
|
229
|
-
3. `src/
|
|
230
|
-
4.
|
|
231
|
-
5. `src/
|
|
232
|
-
6. `src/
|
|
233
|
-
7. `src/
|
|
234
|
-
8. `src/
|
|
235
|
-
9. `src/
|
|
236
|
-
10. `src/
|
|
237
|
-
11. `src/
|
|
238
|
-
12. `src/
|
|
239
|
-
13. `
|
|
240
|
-
14. `
|
|
241
|
-
15.
|
|
242
|
-
16.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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. **
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
- `src/app/
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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`
|
|
269
|
-
2.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
|
284
|
-
- [ ] `pnpm test` exits 0
|
|
285
|
-
- [ ] `pnpm build` succeeds
|
|
286
|
-
- [ ] `
|
|
287
|
-
- [ ]
|
|
288
|
-
- [ ] `
|
|
289
|
-
- [ ] `
|
|
290
|
-
- [ ] No
|
|
291
|
-
- [ ]
|
|
292
|
-
|
|
293
|
-
|
|
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
|
|
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
|
|
303
|
-
2.
|
|
304
|
-
3.
|
|
305
|
-
4.
|
|
306
|
-
5.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
324
|
-
- **Don't rewrite the user's existing project
|
|
325
|
-
- **
|
|
326
|
-
- **
|
|
327
|
-
- **
|
|
328
|
-
- **
|
|
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.
|