create-rigel 0.1.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/LICENSE +21 -0
- package/README.md +156 -0
- package/cli.js +122 -0
- package/package.json +47 -0
- package/templates/express/.claude/CLAUDE.md +114 -0
- package/templates/express/.claude/agents/arch-validator.md +85 -0
- package/templates/express/.claude/agents/db-optimizer.md +72 -0
- package/templates/express/.claude/agents/doc-gardener.md +67 -0
- package/templates/express/.claude/agents/garbage-collector.md +94 -0
- package/templates/express/.claude/agents/gate-checker.md +176 -0
- package/templates/express/.claude/agents/reviewer.md +84 -0
- package/templates/express/.claude/agents/security-auditor.md +82 -0
- package/templates/express/.claude/hooks/post-write.sh +93 -0
- package/templates/express/.claude/rules/api.md +149 -0
- package/templates/express/.claude/rules/architecture.md +78 -0
- package/templates/express/.claude/rules/database.md +104 -0
- package/templates/express/.claude/rules/jobs.md +81 -0
- package/templates/express/.claude/rules/security.md +92 -0
- package/templates/express/.claude/rules/testing.md +97 -0
- package/templates/express/.claude/settings.json +35 -0
- package/templates/express/.claude/skills/00-infra-setup/SKILL.md +479 -0
- package/templates/express/.claude/skills/01-write-roadmap/SKILL.md +72 -0
- package/templates/express/.claude/skills/02-write-spec/SKILL.md +119 -0
- package/templates/express/.claude/skills/03-write-plan/SKILL.md +124 -0
- package/templates/express/.claude/skills/04-build-layer/SKILL.md +216 -0
- package/templates/express/.claude/skills/05-validate-layer/SKILL.md +43 -0
- package/templates/express/.claude/skills/06-push-layer/SKILL.md +59 -0
- package/templates/express/.claude/skills/07-layer-check/SKILL.md +62 -0
- package/templates/express/.claude/skills/08-garbage-collect/SKILL.md +86 -0
- package/templates/express/.claude/skills/09-doc-garden/SKILL.md +64 -0
- package/templates/express/.claude/skills/10-db-optimize/SKILL.md +96 -0
- package/templates/express/.claude/skills/11-load-test/SKILL.md +77 -0
- package/templates/express/.dockerignore +43 -0
- package/templates/express/.env.example +42 -0
- package/templates/express/.github/CODEOWNERS +22 -0
- package/templates/express/.github/dependabot.yml +48 -0
- package/templates/express/.github/pull_request_template.md +58 -0
- package/templates/express/.github/workflows/ci.yml +278 -0
- package/templates/express/.github/workflows/load-test.yml +41 -0
- package/templates/express/.gitleaks.toml +18 -0
- package/templates/express/.lintstagedrc.json +3 -0
- package/templates/express/.nvmrc +1 -0
- package/templates/express/.prettierrc +8 -0
- package/templates/express/.sequelizerc +8 -0
- package/templates/express/AGENTS.md +94 -0
- package/templates/express/ARCHITECTURE.md +161 -0
- package/templates/express/Dockerfile +40 -0
- package/templates/express/Makefile +79 -0
- package/templates/express/QUICKSTART.md +131 -0
- package/templates/express/docker-compose.yml +114 -0
- package/templates/express/docs/PLANS.md +111 -0
- package/templates/express/docs/QUALITY_SCORE.md +66 -0
- package/templates/express/docs/design-docs/core-beliefs.md +89 -0
- package/templates/express/docs/design-docs/decisions/ADR-000-infrastructure.md +70 -0
- package/templates/express/docs/design-docs/decisions/ADR-001-observability.md +82 -0
- package/templates/express/docs/design-docs/decisions/index.md +23 -0
- package/templates/express/docs/design-docs/index.md +11 -0
- package/templates/express/docs/design-docs/observability.md +194 -0
- package/templates/express/docs/design-docs/team-workflow.md +64 -0
- package/templates/express/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/express/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/express/docs/exec-plans/tech-debt-tracker.md +31 -0
- package/templates/express/docs/generated/.gitkeep +0 -0
- package/templates/express/docs/product-specs/ROADMAP.md +49 -0
- package/templates/express/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/express/docs/product-specs/index.md +21 -0
- package/templates/express/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/express/eslint.config.mjs +94 -0
- package/templates/express/gitignore +36 -0
- package/templates/express/infra/monitoring/alloy/config.alloy +59 -0
- package/templates/express/jest.config.ts +61 -0
- package/templates/express/package.json +45 -0
- package/templates/express/scripts/openapi.export.ts +77 -0
- package/templates/express/tests/architecture/isolation.test.ts +51 -0
- package/templates/express/tests/architecture/layers.test.ts +83 -0
- package/templates/express/tests/integration/health.test.ts +40 -0
- package/templates/express/tests/integration/isolation.test.template.ts +88 -0
- package/templates/express/tests/load/smoke.js +46 -0
- package/templates/express/tests/load/soak.js +45 -0
- package/templates/express/tests/load/stress.js +44 -0
- package/templates/express/tests/unit/utils/response.util.test.ts +53 -0
- package/templates/express/tsconfig.build.json +8 -0
- package/templates/express/tsconfig.json +20 -0
- package/templates/fastapi/.claude/CLAUDE.md +122 -0
- package/templates/fastapi/.claude/agents/arch-validator.md +64 -0
- package/templates/fastapi/.claude/agents/db-optimizer.md +59 -0
- package/templates/fastapi/.claude/agents/doc-gardener.md +55 -0
- package/templates/fastapi/.claude/agents/garbage-collector.md +74 -0
- package/templates/fastapi/.claude/agents/gate-checker.md +133 -0
- package/templates/fastapi/.claude/agents/reviewer.md +74 -0
- package/templates/fastapi/.claude/agents/security-auditor.md +69 -0
- package/templates/fastapi/.claude/hooks/post-write.sh +65 -0
- package/templates/fastapi/.claude/rules/api.md +119 -0
- package/templates/fastapi/.claude/rules/architecture.md +84 -0
- package/templates/fastapi/.claude/rules/database.md +153 -0
- package/templates/fastapi/.claude/rules/jobs.md +85 -0
- package/templates/fastapi/.claude/rules/security.md +102 -0
- package/templates/fastapi/.claude/rules/testing.md +207 -0
- package/templates/fastapi/.claude/settings.json +50 -0
- package/templates/fastapi/.claude/skills/00-infra-setup/SKILL.md +311 -0
- package/templates/fastapi/.claude/skills/01-write-roadmap/SKILL.md +61 -0
- package/templates/fastapi/.claude/skills/02-write-spec/SKILL.md +82 -0
- package/templates/fastapi/.claude/skills/03-write-plan/SKILL.md +83 -0
- package/templates/fastapi/.claude/skills/04-build-layer/SKILL.md +170 -0
- package/templates/fastapi/.claude/skills/05-validate-layer/SKILL.md +20 -0
- package/templates/fastapi/.claude/skills/06-push-layer/SKILL.md +31 -0
- package/templates/fastapi/.claude/skills/07-layer-check/SKILL.md +51 -0
- package/templates/fastapi/.claude/skills/08-garbage-collect/SKILL.md +47 -0
- package/templates/fastapi/.claude/skills/09-doc-garden/SKILL.md +9 -0
- package/templates/fastapi/.claude/skills/10-db-optimize/SKILL.md +53 -0
- package/templates/fastapi/.claude/skills/11-load-test/SKILL.md +81 -0
- package/templates/fastapi/.dockerignore +30 -0
- package/templates/fastapi/.github/dependabot.yml +24 -0
- package/templates/fastapi/AGENTS.md +87 -0
- package/templates/fastapi/ARCHITECTURE.md +141 -0
- package/templates/fastapi/Makefile +42 -0
- package/templates/fastapi/README.md +179 -0
- package/templates/fastapi/docs/PLANS.md +26 -0
- package/templates/fastapi/docs/QUALITY_SCORE.md +26 -0
- package/templates/fastapi/docs/design-docs/core-beliefs.md +46 -0
- package/templates/fastapi/docs/design-docs/decisions/ADR-000-infrastructure.md +79 -0
- package/templates/fastapi/docs/design-docs/decisions/index.md +7 -0
- package/templates/fastapi/docs/design-docs/index.md +9 -0
- package/templates/fastapi/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/fastapi/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/fastapi/docs/exec-plans/tech-debt-tracker.md +19 -0
- package/templates/fastapi/docs/generated/.gitkeep +0 -0
- package/templates/fastapi/docs/product-specs/ROADMAP.md +49 -0
- package/templates/fastapi/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/fastapi/docs/product-specs/index.md +18 -0
- package/templates/fastapi/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/fastapi/gitignore +46 -0
- package/templates/fastapi/scripts/gate.sh +68 -0
- package/templates/nestjs/.claude/CLAUDE.md +121 -0
- package/templates/nestjs/.claude/agents/db-optimizer.md +51 -0
- package/templates/nestjs/.claude/agents/doc-gardener.md +45 -0
- package/templates/nestjs/.claude/agents/garbage-collector.md +50 -0
- package/templates/nestjs/.claude/agents/gate-checker.md +127 -0
- package/templates/nestjs/.claude/agents/reviewer.md +68 -0
- package/templates/nestjs/.claude/agents/security-auditor.md +72 -0
- package/templates/nestjs/.claude/hooks/post-write.sh +91 -0
- package/templates/nestjs/.claude/rules/api.md +87 -0
- package/templates/nestjs/.claude/rules/architecture.md +104 -0
- package/templates/nestjs/.claude/rules/database.md +111 -0
- package/templates/nestjs/.claude/rules/security.md +110 -0
- package/templates/nestjs/.claude/rules/testing.md +145 -0
- package/templates/nestjs/.claude/settings.json +33 -0
- package/templates/nestjs/.claude/skills/00-infra-setup/SKILL.md +222 -0
- package/templates/nestjs/.claude/skills/01-write-spec/SKILL.md +25 -0
- package/templates/nestjs/.claude/skills/02-write-plan/SKILL.md +18 -0
- package/templates/nestjs/.claude/skills/03-build-layer/SKILL.md +242 -0
- package/templates/nestjs/.claude/skills/04-validate-layer/SKILL.md +4 -0
- package/templates/nestjs/.claude/skills/05-push-layer/SKILL.md +6 -0
- package/templates/nestjs/.claude/skills/06-layer-check/SKILL.md +12 -0
- package/templates/nestjs/.claude/skills/07-garbage-collect/SKILL.md +2 -0
- package/templates/nestjs/.claude/skills/08-doc-garden/SKILL.md +4 -0
- package/templates/nestjs/.claude/skills/09-api-sync/SKILL.md +36 -0
- package/templates/nestjs/.claude/skills/10-load-test/SKILL.md +29 -0
- package/templates/nestjs/.env.example +11 -0
- package/templates/nestjs/AGENTS.md +88 -0
- package/templates/nestjs/ARCHITECTURE.md +192 -0
- package/templates/nestjs/docs/PLANS.md +22 -0
- package/templates/nestjs/docs/QUALITY_SCORE.md +27 -0
- package/templates/nestjs/docs/design-docs/core-beliefs.md +18 -0
- package/templates/nestjs/docs/design-docs/decisions/ADR-000-infrastructure.md +58 -0
- package/templates/nestjs/docs/design-docs/decisions/index.md +7 -0
- package/templates/nestjs/docs/design-docs/index.md +7 -0
- package/templates/nestjs/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/nestjs/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/nestjs/docs/exec-plans/tech-debt-tracker.md +16 -0
- package/templates/nestjs/docs/generated/.gitkeep +0 -0
- package/templates/nestjs/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/nestjs/docs/product-specs/index.md +7 -0
- package/templates/nestjs/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/nestjs/gitignore +8 -0
- package/templates/nextjs/.claude/CLAUDE.md +139 -0
- package/templates/nextjs/.claude/agents/arch-validator.md +66 -0
- package/templates/nextjs/.claude/agents/contract-checker.md +78 -0
- package/templates/nextjs/.claude/agents/doc-gardener.md +52 -0
- package/templates/nextjs/.claude/agents/garbage-collector.md +61 -0
- package/templates/nextjs/.claude/agents/gate-checker.md +129 -0
- package/templates/nextjs/.claude/agents/perf-auditor.md +109 -0
- package/templates/nextjs/.claude/agents/reviewer.md +79 -0
- package/templates/nextjs/.claude/agents/security-auditor.md +50 -0
- package/templates/nextjs/.claude/hooks/post-write.sh +121 -0
- package/templates/nextjs/.claude/rules/api-contract.md +166 -0
- package/templates/nextjs/.claude/rules/architecture.md +99 -0
- package/templates/nextjs/.claude/rules/components.md +122 -0
- package/templates/nextjs/.claude/rules/security.md +122 -0
- package/templates/nextjs/.claude/rules/testing.md +187 -0
- package/templates/nextjs/.claude/scripts/infra-setup.sh +550 -0
- package/templates/nextjs/.claude/settings.json +33 -0
- package/templates/nextjs/.claude/skills/00-infra-setup/SKILL.md +471 -0
- package/templates/nextjs/.claude/skills/01-write-roadmap/SKILL.md +77 -0
- package/templates/nextjs/.claude/skills/02-write-spec/SKILL.md +78 -0
- package/templates/nextjs/.claude/skills/03-write-plan/SKILL.md +91 -0
- package/templates/nextjs/.claude/skills/04-build-layer/SKILL.md +141 -0
- package/templates/nextjs/.claude/skills/05-validate-layer/SKILL.md +13 -0
- package/templates/nextjs/.claude/skills/06-push-layer/SKILL.md +20 -0
- package/templates/nextjs/.claude/skills/07-layer-check/SKILL.md +28 -0
- package/templates/nextjs/.claude/skills/08-garbage-collect/SKILL.md +14 -0
- package/templates/nextjs/.claude/skills/09-doc-garden/SKILL.md +12 -0
- package/templates/nextjs/.claude/skills/10-api-sync/SKILL.md +50 -0
- package/templates/nextjs/.claude/skills/11-perf-budget/SKILL.md +51 -0
- package/templates/nextjs/.dockerignore +25 -0
- package/templates/nextjs/.gitattributes +10 -0
- package/templates/nextjs/.github/CODEOWNERS +24 -0
- package/templates/nextjs/.github/dependabot.yml +31 -0
- package/templates/nextjs/.github/pull_request_template.md +59 -0
- package/templates/nextjs/.github/workflows/ci.yml +143 -0
- package/templates/nextjs/.github/workflows/lighthouse.yml +54 -0
- package/templates/nextjs/.github/workflows/load-test.yml +54 -0
- package/templates/nextjs/.husky/pre-commit +1 -0
- package/templates/nextjs/.lintstagedrc.json +4 -0
- package/templates/nextjs/.mcp.json +8 -0
- package/templates/nextjs/.prettierignore +13 -0
- package/templates/nextjs/.prettierrc +9 -0
- package/templates/nextjs/AGENTS.md +88 -0
- package/templates/nextjs/ARCHITECTURE.md +165 -0
- package/templates/nextjs/Dockerfile +38 -0
- package/templates/nextjs/Makefile +50 -0
- package/templates/nextjs/QUICKSTART.md +128 -0
- package/templates/nextjs/docs/PLANS.md +23 -0
- package/templates/nextjs/docs/QUALITY_SCORE.md +27 -0
- package/templates/nextjs/docs/design-docs/core-beliefs.md +43 -0
- package/templates/nextjs/docs/design-docs/decisions/ADR-000-infrastructure.md +72 -0
- package/templates/nextjs/docs/design-docs/decisions/index.md +7 -0
- package/templates/nextjs/docs/design-docs/index.md +7 -0
- package/templates/nextjs/docs/design-docs/team-workflow.md +66 -0
- package/templates/nextjs/docs/exec-plans/active/.gitkeep +0 -0
- package/templates/nextjs/docs/exec-plans/completed/.gitkeep +0 -0
- package/templates/nextjs/docs/exec-plans/tech-debt-tracker.md +19 -0
- package/templates/nextjs/docs/generated/.gitkeep +0 -0
- package/templates/nextjs/docs/product-specs/ROADMAP.md +59 -0
- package/templates/nextjs/docs/product-specs/draft/.gitkeep +0 -0
- package/templates/nextjs/docs/product-specs/index.md +18 -0
- package/templates/nextjs/docs/product-specs/ready/.gitkeep +0 -0
- package/templates/nextjs/eslint.config.mjs +150 -0
- package/templates/nextjs/gitignore +35 -0
- package/templates/nextjs/lighthouserc.js +37 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# QUICKSTART — Your First 30 Minutes
|
|
2
|
+
|
|
3
|
+
This is an **agent-first** Next.js template. You don't scaffold or wire it by hand — you
|
|
4
|
+
drive [Claude Code](https://claude.com/claude-code) through a fixed set of slash commands,
|
|
5
|
+
and a gate enforces the architecture on every step. This page gets you from clone to a
|
|
6
|
+
running, contract-typed app.
|
|
7
|
+
|
|
8
|
+
> New here? Read in order: this file → `AGENTS.md` (navigation map) → `ARCHITECTURE.md`
|
|
9
|
+
> (layer rules) → `.claude/CLAUDE.md` (the agent's standing instructions).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 0. Prerequisites
|
|
14
|
+
|
|
15
|
+
- **Node.js** (latest LTS) and **npm**
|
|
16
|
+
- **Claude Code** installed — CLI (`npm i -g @anthropic-ai/claude-code`), the desktop/web
|
|
17
|
+
app, or the VS Code / JetBrains extension
|
|
18
|
+
- **bash** available on PATH (Git Bash on Windows) — the hooks and the infra script run in bash
|
|
19
|
+
- A backend that exposes an **`openapi.json`** spec (needed before you build features)
|
|
20
|
+
|
|
21
|
+
This template ships **only** the harness (`.claude/`, `docs/`, root docs). There is no
|
|
22
|
+
`package.json` yet — that's deliberate. `/infra-setup` generates the app.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 1. Open the project in Claude Code
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cd harness-nextjs
|
|
30
|
+
claude # or open the folder in the IDE extension
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Claude reads `.claude/CLAUDE.md` automatically and follows the Session Start Checklist.
|
|
34
|
+
The model is pinned to **Opus 4.8** in `.claude/settings.json`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 2. Run Phase 0 — infrastructure (once)
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
/infra-setup
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This runs the deterministic scaffold (`bash .claude/scripts/infra-setup.sh`) —
|
|
45
|
+
`create-next-app@latest`, all deps at latest LTS (no version pins), `shadcn/ui`, the
|
|
46
|
+
directory tree, and `package.json` scripts — then Claude hand-authors the harness glue
|
|
47
|
+
(`src/lib/env.ts`, `src/lib/api-client.ts`, utils, store, providers, configs, and the
|
|
48
|
+
`tests/architecture/layers.test.ts` gate). Ends with a passing gate + ADR-000 committed.
|
|
49
|
+
|
|
50
|
+
You now have a runnable app:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm run dev # http://localhost:3000
|
|
54
|
+
npm run typecheck
|
|
55
|
+
npm test
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 3. Plan the whole product (once, before the feature loop)
|
|
61
|
+
|
|
62
|
+
For a real multi-screen product, decompose it into an ordered set of specs first — don't
|
|
63
|
+
free-style screen-by-screen. With the product brief and the backend's `openapi.json` in the repo:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
/api-sync → generate src/types/api.generated.ts from the backend openapi.json
|
|
67
|
+
/write-roadmap → brief + contract → docs/product-specs/ROADMAP.md
|
|
68
|
+
(feature areas + personas, dependency order, a walking-skeleton first slice,
|
|
69
|
+
and an `Implements (backend SPEC)` column so each row is gated on the
|
|
70
|
+
backend capability being shipped)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This is the altitude above specs. It's a LIVING doc — re-run `/write-roadmap` when the backend
|
|
74
|
+
contract grows. (Small one-off feature? Skip it and go straight to `/write-spec`.)
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 4. The feature loop (every feature, forever)
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
/write-spec → describe the feature (roadmap-guided); output lands in docs/product-specs/draft/
|
|
82
|
+
(you review the spec and move it to docs/product-specs/ready/)
|
|
83
|
+
/write-plan → turns the READY spec into a layered execution plan
|
|
84
|
+
/api-sync → regenerate src/types/api.generated.ts from the backend openapi.json
|
|
85
|
+
/build-layer → builds the next unchecked layer, then the gate-checker runs (PASS/FAIL)
|
|
86
|
+
(repeat /build-layer until every layer is checked)
|
|
87
|
+
/garbage-collect → end-of-feature cleanup; plan moves to docs/exec-plans/completed/
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`/build-layer` builds **one layer at a time** (types → lib → hooks → features → app →
|
|
91
|
+
tests) and will not let you commit until the gate is green.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 5. The rules the harness enforces for you
|
|
96
|
+
|
|
97
|
+
You don't have to memorise these — the post-write hook and `gate-checker` catch them —
|
|
98
|
+
but knowing them explains the guardrails (full list in `AGENTS.md`):
|
|
99
|
+
|
|
100
|
+
- No `fetch()` in components/pages — all API calls go through `src/hooks/`
|
|
101
|
+
- `src/types/api.generated.ts` is **READ ONLY** — regenerated by `/api-sync`
|
|
102
|
+
- `process.env` only inside `src/lib/env.ts`
|
|
103
|
+
- Access tokens live in memory (React context), never `localStorage`
|
|
104
|
+
- No file > 400 lines; no `console.log` in `src/`
|
|
105
|
+
- Every `'use client'` needs a `// Client: <reason>` comment
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 6. Useful agents (invoke by asking Claude)
|
|
110
|
+
|
|
111
|
+
| Agent | When |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `reviewer` | "Use the reviewer agent to review current changes" — before a PR |
|
|
114
|
+
| `security-auditor` | before any auth / token / data-exposure change |
|
|
115
|
+
| `perf-auditor` | before adding new routes/components (Core Web Vitals + bundle) |
|
|
116
|
+
| `contract-checker` | after the OpenAPI spec changes |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Troubleshooting
|
|
121
|
+
|
|
122
|
+
- **`/infra-setup` says package.json exists** — infra runs once; it's already set up.
|
|
123
|
+
- **Hook prints nothing** — it only warns on `.ts`/`.tsx` under `src/`/`app/`; that's normal.
|
|
124
|
+
- **Gate fails on architecture tests** — `tests/architecture/layers.test.ts` enforces layer
|
|
125
|
+
imports; the failure message names the offending `file → import`. Fix the import direction.
|
|
126
|
+
- **A skill looks out of date** — check its `Verified:` header; if stale, Claude refreshes
|
|
127
|
+
the relevant library docs via `ctx7` before following it (see the Skill Freshness Rule in
|
|
128
|
+
`.claude/CLAUDE.md`).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# PLANS.md — Execution Plan Format
|
|
2
|
+
|
|
3
|
+
## Roadmap → Specs (the altitude above plans)
|
|
4
|
+
/write-roadmap creates → docs/product-specs/ROADMAP.md (brief + backend openapi.json →
|
|
5
|
+
feature-area- and persona-ordered frontend specs, each gated on the backend spec it `Implements`).
|
|
6
|
+
The roadmap plans the SET of specs; /write-spec then authors each one. A large feature area may
|
|
7
|
+
span MULTIPLE plans — its spec's `**Plan:**` field then lists them all (e.g. PLAN-003, PLAN-007).
|
|
8
|
+
|
|
9
|
+
## Lifecycle
|
|
10
|
+
/write-plan creates → docs/exec-plans/active/PLAN-XXX.md [IN_PROGRESS]
|
|
11
|
+
→ layers built one by one, checkboxes ticked
|
|
12
|
+
→ /garbage-collect closes → docs/exec-plans/completed/ [COMPLETE]
|
|
13
|
+
|
|
14
|
+
Plans are NEVER deleted. They are the project memory.
|
|
15
|
+
|
|
16
|
+
## Pre-Build Requirement
|
|
17
|
+
Always run /api-sync before the first /build-layer to ensure the contract is current.
|
|
18
|
+
|
|
19
|
+
## Escalation Rule
|
|
20
|
+
Escalate to human only when judgment is required:
|
|
21
|
+
- Ambiguous acceptance criteria
|
|
22
|
+
- API contract has breaking changes requiring design decisions
|
|
23
|
+
- Performance budget impossible without architecture change
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# QUALITY_SCORE.md — Domain Health Grades
|
|
2
|
+
|
|
3
|
+
Updated by /garbage-collect after every feature.
|
|
4
|
+
|
|
5
|
+
## Grading Rubric
|
|
6
|
+
| Grade | Meaning |
|
|
7
|
+
|---|---|
|
|
8
|
+
| A | All invariants met, coverage above threshold, zero known debt |
|
|
9
|
+
| B | Minor issues, coverage at threshold, low-priority debt logged |
|
|
10
|
+
| C | Layer violation OR coverage below threshold OR unresolved debt |
|
|
11
|
+
| D | Multiple violations, significant coverage gaps |
|
|
12
|
+
|
|
13
|
+
## Architecture Health
|
|
14
|
+
| Check | Status |
|
|
15
|
+
|---|---|
|
|
16
|
+
| No cross-layer imports | — |
|
|
17
|
+
| No files > 400 lines | — |
|
|
18
|
+
| No process.env outside env.ts | — |
|
|
19
|
+
| No console.log in src/ | — |
|
|
20
|
+
| No direct fetch() in components | — |
|
|
21
|
+
| api.generated.ts not manually edited | — |
|
|
22
|
+
| Utils: 100% test coverage | — |
|
|
23
|
+
|
|
24
|
+
## Domain Grades
|
|
25
|
+
| Domain | Grade | Coverage | Last Updated | Notes |
|
|
26
|
+
|---|---|---|---|---|
|
|
27
|
+
| *(no domains yet)* | — | — | — | — |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Core Beliefs — The Engineering Constitution
|
|
2
|
+
|
|
3
|
+
Rules without reasons get bent under pressure.
|
|
4
|
+
|
|
5
|
+
## 1. The Repo Is Reality
|
|
6
|
+
If it isn't in this repository, it doesn't exist.
|
|
7
|
+
**Consequence:** Every decision → ADR. Every product → ROADMAP.md. Every intent → spec. Every plan → PLAN-XXX.md.
|
|
8
|
+
|
|
9
|
+
## 2. The API Contract Is the Source of Truth
|
|
10
|
+
api.generated.ts is generated from the backend OpenAPI spec. Never hand-write types that duplicate it.
|
|
11
|
+
**Consequence:** /api-sync runs before every feature. TypeScript errors after sync = contract drift to fix.
|
|
12
|
+
|
|
13
|
+
## 3. Hooks Are the Only API Gateway
|
|
14
|
+
No component or page calls fetch() directly. All API calls go through TanStack Query hooks in src/hooks/.
|
|
15
|
+
**Consequence:** One place to add auth headers, one place to handle errors, one place to add retries.
|
|
16
|
+
|
|
17
|
+
## 4. Enforce Mechanically, Not Aspirationally
|
|
18
|
+
ESLint rules, hooks, and structural tests enforce the architecture. Docs alone do not.
|
|
19
|
+
**Consequence:** Every constraint is a linter rule, a hook warning, or a failing test.
|
|
20
|
+
|
|
21
|
+
## 5. Server Components Are the Default
|
|
22
|
+
Every component is a Server Component unless it explicitly needs browser APIs or React hooks.
|
|
23
|
+
**Consequence:** Every 'use client' directive requires a comment explaining why.
|
|
24
|
+
|
|
25
|
+
## 6. Layers Protect Concerns
|
|
26
|
+
Features don't call fetch(). Pages don't contain business logic. Utils don't import domain code.
|
|
27
|
+
**Consequence:** ESLint import rules + structural tests enforce this mechanically.
|
|
28
|
+
|
|
29
|
+
## 7. Tokens Live in Memory
|
|
30
|
+
Access tokens are stored in React context only. Never localStorage, never sessionStorage.
|
|
31
|
+
**Consequence:** Post-hook catches this. Tokens are wiped on page refresh by design (refresh token in httpOnly cookie handles re-auth).
|
|
32
|
+
|
|
33
|
+
## 8. All Three States, Every Time
|
|
34
|
+
Every component that fetches data must handle: loading, error, and empty. Silence is not acceptable.
|
|
35
|
+
**Consequence:** Gate-checker scans for isPending/isError patterns on data-fetching components.
|
|
36
|
+
|
|
37
|
+
## 9. Gate Before Commit — Always
|
|
38
|
+
TypeScript must compile. ESLint must pass. Architecture tests must pass. Before every commit.
|
|
39
|
+
**Consequence:** /push-layer runs typecheck + lint before committing. No exceptions.
|
|
40
|
+
|
|
41
|
+
## 10. Technical Debt Is a High-Interest Loan
|
|
42
|
+
Log debt immediately. Pay it in small daily amounts. Garbage collect after every feature.
|
|
43
|
+
**Consequence:** tech-debt-tracker.md updated after every feature.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# ADR-000 — Infrastructure & Stack Choices
|
|
2
|
+
|
|
3
|
+
**Status:** ACCEPTED
|
|
4
|
+
**Date:** *(fill when /infra-setup is run)*
|
|
5
|
+
**Plan:** Phase 0
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
Starting a new Next.js frontend project. Stack choices made here are expensive to change.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Decisions
|
|
15
|
+
|
|
16
|
+
### Framework: Next.js 16.2 + React 19.2
|
|
17
|
+
- Next.js 16 is the current stable with React Compiler stable
|
|
18
|
+
- App Router (not Pages Router) — RSC, streaming, better performance
|
|
19
|
+
- React Compiler enabled — automatic memoisation, zero manual useMemo/useCallback
|
|
20
|
+
- Turbopack as bundler — significantly faster dev server than Webpack
|
|
21
|
+
- Alternatives rejected: Remix (less ecosystem), Vite SPA (no SSR/RSC benefits)
|
|
22
|
+
|
|
23
|
+
### API Contract: openapi-typescript + openapi-fetch
|
|
24
|
+
- openapi-typescript generates types from backend OpenAPI spec — zero runtime overhead
|
|
25
|
+
- openapi-fetch: type-safe fetch client, 6kb, infers types from generated schema
|
|
26
|
+
- Together: full end-to-end type safety from backend response to component props
|
|
27
|
+
- Alternatives rejected: axios (no OpenAPI integration), React Query with manual types (error-prone)
|
|
28
|
+
|
|
29
|
+
### Server State: TanStack Query 5
|
|
30
|
+
- Industry standard for async server state management
|
|
31
|
+
- Built-in caching, background refetch, optimistic updates, devtools
|
|
32
|
+
- Version 5: simplified API (one object argument), smaller bundle
|
|
33
|
+
- Alternatives rejected: SWR (less features), Redux RTK Query (more boilerplate)
|
|
34
|
+
|
|
35
|
+
### Client State: Zustand 5
|
|
36
|
+
- Minimal (~1kb), TypeScript-native, no boilerplate
|
|
37
|
+
- Used ONLY for UI state that genuinely belongs on the client (sidebar, modals)
|
|
38
|
+
- NOT for server data — that's in TanStack Query
|
|
39
|
+
- Alternatives rejected: Redux (overkill), Jotai (less ecosystem), Context (re-render issues)
|
|
40
|
+
|
|
41
|
+
### Components: shadcn/ui
|
|
42
|
+
- Copy-owned model — components are in your repo, you control them
|
|
43
|
+
- Built on Radix UI primitives (accessibility built-in)
|
|
44
|
+
- Tailwind CSS 4 styling — no runtime CSS-in-JS
|
|
45
|
+
- No upgrade hell — you own the code
|
|
46
|
+
- Alternatives rejected: MUI (heavy, hard to customise), Chakra (JSX props model)
|
|
47
|
+
|
|
48
|
+
### Forms: React Hook Form 7 + Zod 3
|
|
49
|
+
- React Hook Form: uncontrolled, minimal re-renders, best performance
|
|
50
|
+
- Zod: same validation library as backend — consistent error messages
|
|
51
|
+
- @hookform/resolvers bridges them
|
|
52
|
+
- Alternatives rejected: Formik (slow, too many re-renders), Yup (less TypeScript support)
|
|
53
|
+
|
|
54
|
+
### Testing: Vitest 4 + Playwright + MSW 2
|
|
55
|
+
- Vitest 4: 3.8x faster than Jest, native TypeScript, same Jest API
|
|
56
|
+
- Playwright: E2E + visual regression in one tool, 80%+ new project adoption
|
|
57
|
+
- MSW 2: intercept at network level, works in both browser and node
|
|
58
|
+
- Alternatives rejected: Jest (slower), Cypress (less capable than Playwright)
|
|
59
|
+
|
|
60
|
+
### Auth Token Strategy
|
|
61
|
+
- Access token in React context (memory) — wiped on refresh
|
|
62
|
+
- Refresh token in httpOnly cookie (set by backend) — never accessible to JS
|
|
63
|
+
- On 401: call /api/auth/refresh → backend reads cookie → issues new access token
|
|
64
|
+
- No localStorage/sessionStorage — XSS attack surface reduction
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Consequences
|
|
69
|
+
- openapi-typescript: api.generated.ts is READ ONLY — must regenerate on backend changes
|
|
70
|
+
- React Compiler: no manual useMemo/useCallback needed (but don't remove existing ones without testing)
|
|
71
|
+
- Server Components: most pages are async by default — data fetching happens at render time on server
|
|
72
|
+
- Zustand for UI only: if it lives in TanStack Query cache, don't duplicate in Zustand
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Team Workflow — Branch Protection & Review Policy
|
|
2
|
+
|
|
3
|
+
Referenced by `.github/CODEOWNERS`. This documents how the harness is operated by a
|
|
4
|
+
team: branch protection, who reviews what, and the merge rules. Adjust to your org.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Branch model
|
|
9
|
+
|
|
10
|
+
- `main` is protected and always deployable. No direct pushes.
|
|
11
|
+
- All work lands via pull request from a short-lived branch:
|
|
12
|
+
`feat/<scope>`, `fix/<scope>`, `chore/<scope>`.
|
|
13
|
+
- One execution plan → one (or a few) PRs; one layer per commit where practical.
|
|
14
|
+
|
|
15
|
+
## Branch protection rules (GitHub → Settings → Branches → `main`)
|
|
16
|
+
|
|
17
|
+
Enable:
|
|
18
|
+
|
|
19
|
+
- [ ] **Require a pull request before merging**
|
|
20
|
+
- [ ] **Require approvals** — at least **1** (2 for security-sensitive paths)
|
|
21
|
+
- [ ] **Require review from Code Owners** — activates `.github/CODEOWNERS`
|
|
22
|
+
- [ ] **Require status checks to pass** → select the **CI / verify** check
|
|
23
|
+
(typecheck · lint · format · test · build) and **Lighthouse CI** for UI PRs
|
|
24
|
+
- [ ] **Require branches to be up to date before merging**
|
|
25
|
+
- [ ] **Require conversation resolution before merging**
|
|
26
|
+
- [ ] **Do not allow bypassing the above** (applies to admins too)
|
|
27
|
+
|
|
28
|
+
## Who reviews what (CODEOWNERS)
|
|
29
|
+
|
|
30
|
+
| Path | Owner | Why |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `*` (default) | `@your-team/engineers` | Any engineer can review ordinary changes |
|
|
33
|
+
| `.claude/hooks/`, `src/lib/env.ts`, `src/lib/api-client.ts`, `src/features/auth/`, `app/api/`, `next.config.ts` | `@your-team/leads` | Security-sensitive: auth, token handling, env, headers |
|
|
34
|
+
| `src/types/api.generated.ts` | `@your-team/leads` | Contract drift / accidental hand-edit (file is generated) |
|
|
35
|
+
| `.github/workflows/`, `Dockerfile` | `@your-team/platform` | CI/CD and container surface |
|
|
36
|
+
|
|
37
|
+
> Replace the placeholder team slugs in `CODEOWNERS` with real GitHub teams/usernames,
|
|
38
|
+
> then tick "Require review from Code Owners" above. Until then they are inert.
|
|
39
|
+
|
|
40
|
+
## Approve vs merge
|
|
41
|
+
|
|
42
|
+
- **Approve**: any code owner for the touched paths.
|
|
43
|
+
- **Merge**: the PR author after all required approvals + green checks, using
|
|
44
|
+
**Squash and merge**. The squash title must follow conventional commits
|
|
45
|
+
(`feat(scope): …`) — enforced locally by the commit-msg hook and reviewed against
|
|
46
|
+
the PR template.
|
|
47
|
+
|
|
48
|
+
## Local quality gates (run before you push)
|
|
49
|
+
|
|
50
|
+
The harness enforces these automatically; this is what runs and when:
|
|
51
|
+
|
|
52
|
+
| When | What | How |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| On save (optional) | format + eslint | editor / `npm run format` |
|
|
55
|
+
| On `git commit` | eslint --fix + prettier on staged files | Husky `pre-commit` → `lint-staged` |
|
|
56
|
+
| On `/build-layer` | full layer gate (PASS/FAIL) | `gate-checker` agent |
|
|
57
|
+
| On PR | typecheck, lint, format check, tests+coverage, build | `.github/workflows/ci.yml` |
|
|
58
|
+
| On UI PR | Core Web Vitals budget | `.github/workflows/lighthouse.yml` |
|
|
59
|
+
|
|
60
|
+
## Definition of done for a PR
|
|
61
|
+
|
|
62
|
+
- Gate is green (`/validate-layer` passes locally).
|
|
63
|
+
- CI is green.
|
|
64
|
+
- PR template fully checked, including the **cross-user isolation test** for any new
|
|
65
|
+
user-owned resource.
|
|
66
|
+
- An ADR exists for any non-obvious decision (`docs/design-docs/decisions/`).
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Technical Debt Tracker
|
|
2
|
+
|
|
3
|
+
## Severity
|
|
4
|
+
| Level | Fix by |
|
|
5
|
+
|---|---|
|
|
6
|
+
| P0 | Immediately — security/XSS/token exposure |
|
|
7
|
+
| P1 | Within 2 sprints — blocks features or causes bugs |
|
|
8
|
+
| P2 | Within quarter — degrades quality or DX |
|
|
9
|
+
| P3 | When in area — code smell |
|
|
10
|
+
|
|
11
|
+
## Open Debt
|
|
12
|
+
| ID | Severity | Area | Description | Created By | Date |
|
|
13
|
+
|---|---|---|---|---|---|
|
|
14
|
+
| *(none yet)* | — | — | — | — | — |
|
|
15
|
+
|
|
16
|
+
## Resolved Debt
|
|
17
|
+
| ID | Description | Resolved By | Date |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| *(none yet)* | — | — | — |
|
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Product Roadmap (Frontend)
|
|
2
|
+
|
|
3
|
+
**Product:** *(name)* · **Brief:** *(one-line, or link to the brief)* · **Last updated:** *(YYYY-MM-DD)*
|
|
4
|
+
**Walking skeleton:** *(SPEC-001 — login + app shell + one auth-gated route that fetches via the generated client; build first)*
|
|
5
|
+
|
|
6
|
+
> LIVING document — the altitude ABOVE specs. `/write-roadmap` writes it from the product brief
|
|
7
|
+
> + the backend `openapi.json`. `/write-spec` reads it to pick the next spec (one whose
|
|
8
|
+
> `Implements` backend spec is SHIPPED) and flips a row's **Spec ID** + **Status** as specs are
|
|
9
|
+
> created. Update in place; never delete history.
|
|
10
|
+
>
|
|
11
|
+
> This is NOT a mirror of the backend roadmap — it re-decomposes the product along **frontend
|
|
12
|
+
> axes** (screens, flows, personas, real-time). The OpenAPI is the *contract*, not the roadmap:
|
|
13
|
+
> one screen composes many endpoints, and many endpoints have no UI.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Feature Areas & Personas
|
|
18
|
+
|
|
19
|
+
| Feature Area | Persona(s) | What the user does here |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| *(none yet)* | — | — |
|
|
22
|
+
|
|
23
|
+
> Personas (e.g. agent / supervisor / admin) are often different surfaces over the same API.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Spec Roadmap (dependency-ordered)
|
|
28
|
+
|
|
29
|
+
| Order | Spec ID | Name | Feature Area | Implements (backend SPEC/domain) | Depends On | Skeleton | Status |
|
|
30
|
+
|---|---|---|---|---|---|---|---|
|
|
31
|
+
| *(none yet)* | — | — | — | — | — | — | — |
|
|
32
|
+
|
|
33
|
+
> `Spec ID` is `—` until `/write-spec` creates the file and assigns the real number.
|
|
34
|
+
> `Implements` = the backend spec/domain this UI consumes; a row is only **buildable** once that
|
|
35
|
+
> backend spec is SHIPPED. `Depends On` references other *frontend* rows. Exactly one row is the
|
|
36
|
+
> `✅ yes` skeleton, and it depends on nothing.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Build Sequence Rationale
|
|
41
|
+
|
|
42
|
+
1. *(walking skeleton — why first: proves auth + app shell + generated client + TanStack Query, and the WS client for a real-time product)*
|
|
43
|
+
2. *(shared design-system / layout / real-time client — what it unblocks)*
|
|
44
|
+
3. *(first persona surface, gated on its backend specs being shipped)*
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Roadmap Statuses
|
|
49
|
+
|
|
50
|
+
| Status | Meaning |
|
|
51
|
+
|---|---|
|
|
52
|
+
| NOT_STARTED | On the roadmap, no spec file yet |
|
|
53
|
+
| BLOCKED | Backend spec it `Implements` is not SHIPPED yet |
|
|
54
|
+
| DRAFT | `/write-spec` wrote a SPEC-XXX (in `draft/`) |
|
|
55
|
+
| READY | Spec approved — plannable |
|
|
56
|
+
| PLANNED | `/write-plan` created a plan |
|
|
57
|
+
| IN_PROGRESS | Being built |
|
|
58
|
+
| SHIPPED | Complete and live |
|
|
59
|
+
| CANCELLED | Removed from the roadmap |
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Product Specs Index
|
|
2
|
+
|
|
3
|
+
> Whole-product decomposition (feature areas → dependency-ordered specs, each gated on the backend
|
|
4
|
+
> spec it implements) lives in [`ROADMAP.md`](ROADMAP.md). `/write-spec` fills this index per spec.
|
|
5
|
+
|
|
6
|
+
| ID | Name | Status | Plan | Created |
|
|
7
|
+
|---|---|---|---|---|
|
|
8
|
+
| *(no specs yet)* | — | — | — | — |
|
|
9
|
+
|
|
10
|
+
## Statuses
|
|
11
|
+
| Status | Meaning |
|
|
12
|
+
|---|---|
|
|
13
|
+
| DRAFT | Written, not reviewed |
|
|
14
|
+
| READY | Approved — plannable |
|
|
15
|
+
| PLANNED | Plan created |
|
|
16
|
+
| IN_PROGRESS | Being built |
|
|
17
|
+
| SHIPPED | Complete and live |
|
|
18
|
+
| CANCELLED | Not being built |
|
|
File without changes
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// eslint.config.mjs — committed by the harness; OVERRIDES the create-next-app default
|
|
2
|
+
// (the park-and-restore in /infra-setup restores this on top of the generated one).
|
|
3
|
+
// This is what makes the layer-import matrix and the "no direct fetch / no process.env"
|
|
4
|
+
// rules MECHANICAL — `npm run lint` (= `eslint .`) fails CI on a violation, instead of
|
|
5
|
+
// the rules only living in prose. Mirrors .claude/rules/architecture.md.
|
|
6
|
+
//
|
|
7
|
+
// Uses the Next 16+ native flat-config imports (eslint-config-next/core-web-vitals),
|
|
8
|
+
// NOT the legacy FlatCompat bridge — that bridge crashes against eslint-config-next 16.
|
|
9
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
10
|
+
import nextVitals from 'eslint-config-next/core-web-vitals'
|
|
11
|
+
import nextTs from 'eslint-config-next/typescript'
|
|
12
|
+
import eslintConfigPrettier from 'eslint-config-prettier'
|
|
13
|
+
|
|
14
|
+
// Direct fetch() is forbidden outside the hooks layer (call the API through a hook).
|
|
15
|
+
const noFetch = {
|
|
16
|
+
selector: "CallExpression[callee.name='fetch']",
|
|
17
|
+
message: 'Direct fetch() is forbidden here — call the API through a hook in src/hooks/.',
|
|
18
|
+
}
|
|
19
|
+
// process.env is forbidden outside src/lib/ (env.ts is the single validated boundary).
|
|
20
|
+
const noProcessEnv = {
|
|
21
|
+
selector: "MemberExpression[object.name='process'][property.name='env']",
|
|
22
|
+
message: 'process.env is only allowed in src/lib/ — read validated env from src/lib/env.ts.',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const eslintConfig = defineConfig([
|
|
26
|
+
...nextVitals,
|
|
27
|
+
...nextTs,
|
|
28
|
+
|
|
29
|
+
globalIgnores([
|
|
30
|
+
'.next/**',
|
|
31
|
+
'node_modules/**',
|
|
32
|
+
'coverage/**',
|
|
33
|
+
'playwright-report/**',
|
|
34
|
+
'next-env.d.ts',
|
|
35
|
+
'src/types/api.generated.ts',
|
|
36
|
+
'src/components/ui/**',
|
|
37
|
+
'tests/load/**', // k6 scripts run in the k6 runtime, not linted as app code
|
|
38
|
+
]),
|
|
39
|
+
|
|
40
|
+
// Harness-wide rules
|
|
41
|
+
{
|
|
42
|
+
rules: {
|
|
43
|
+
'no-console': ['warn', { allow: ['warn', 'error'] }],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// The structured logger IS the sanctioned console boundary — allow all console here.
|
|
48
|
+
{
|
|
49
|
+
files: ['src/lib/logger.ts'],
|
|
50
|
+
rules: { 'no-console': 'off' },
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// ── Layer import boundaries (the matrix in .claude/rules/architecture.md) ──
|
|
54
|
+
// Each block's `files` glob is a distinct directory, so no file matches two
|
|
55
|
+
// no-restricted-imports blocks (flat config REPLACES rules across blocks).
|
|
56
|
+
{
|
|
57
|
+
files: ['src/types/**/*.{ts,tsx}'],
|
|
58
|
+
rules: {
|
|
59
|
+
'no-restricted-imports': [
|
|
60
|
+
'error',
|
|
61
|
+
{ patterns: ['@/lib/*', '@/hooks/*', '@/features/*', '@/store/*', '@/components/*', '@/utils/*'] },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
files: ['src/utils/**/*.{ts,tsx}'],
|
|
67
|
+
rules: {
|
|
68
|
+
'no-restricted-imports': [
|
|
69
|
+
'error',
|
|
70
|
+
{ patterns: ['@/lib/*', '@/hooks/*', '@/features/*', '@/store/*', '@/components/*'] },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
files: ['src/lib/**/*.{ts,tsx}'],
|
|
76
|
+
rules: {
|
|
77
|
+
'no-restricted-imports': [
|
|
78
|
+
'error',
|
|
79
|
+
{ patterns: ['@/hooks/*', '@/features/*', '@/store/*', '@/components/*'] },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
files: ['src/store/**/*.{ts,tsx}'],
|
|
85
|
+
rules: {
|
|
86
|
+
'no-restricted-imports': [
|
|
87
|
+
'error',
|
|
88
|
+
{ patterns: ['@/lib/*', '@/hooks/*', '@/features/*', '@/components/*'] },
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
files: ['src/hooks/**/*.{ts,tsx}'],
|
|
94
|
+
rules: {
|
|
95
|
+
'no-restricted-imports': ['error', { patterns: ['@/features/*', '@/components/*'] }],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
files: ['src/components/**/*.{ts,tsx}'],
|
|
100
|
+
rules: {
|
|
101
|
+
'no-restricted-imports': [
|
|
102
|
+
'error',
|
|
103
|
+
{ patterns: ['@/lib/*', '@/hooks/*', '@/features/*', '@/store/*'] },
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
// ── App router pages/layouts: render features, never call data hooks directly ──
|
|
109
|
+
{
|
|
110
|
+
files: ['src/app/**/page.tsx', 'src/app/**/layout.tsx', 'app/**/page.tsx', 'app/**/layout.tsx'],
|
|
111
|
+
rules: { 'no-restricted-imports': ['error', { patterns: ['@/hooks/*', '@/store/*'] }] },
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
// ── no-restricted-syntax: fetch + process.env ──
|
|
115
|
+
// NOTE: ESLint flat config REPLACES (does not merge) a rule's value across matching
|
|
116
|
+
// config objects — last match wins. So every file that needs `no-restricted-syntax`
|
|
117
|
+
// must get ALL its selectors in a SINGLE block, or earlier selectors are lost.
|
|
118
|
+
//
|
|
119
|
+
// Render layers (features/components/app): forbid BOTH direct fetch() AND process.env.
|
|
120
|
+
{
|
|
121
|
+
files: [
|
|
122
|
+
'src/features/**/*.{ts,tsx}',
|
|
123
|
+
'src/components/**/*.{ts,tsx}',
|
|
124
|
+
'src/app/**/*.{ts,tsx}',
|
|
125
|
+
'app/**/*.{ts,tsx}',
|
|
126
|
+
],
|
|
127
|
+
rules: { 'no-restricted-syntax': ['error', noFetch, noProcessEnv] },
|
|
128
|
+
},
|
|
129
|
+
// Non-render src layers (hooks/store/utils): forbid process.env only.
|
|
130
|
+
// (fetch isn't restricted in hooks — that's where the typed api-client lives.)
|
|
131
|
+
{
|
|
132
|
+
files: ['src/hooks/**/*.{ts,tsx}', 'src/store/**/*.{ts,tsx}', 'src/utils/**/*.{ts,tsx}'],
|
|
133
|
+
rules: { 'no-restricted-syntax': ['error', noProcessEnv] },
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// ── Tests cross layers by design — relax the boundary + console rules there ──
|
|
137
|
+
{
|
|
138
|
+
files: ['tests/**/*.{ts,tsx}', 'src/**/*.test.{ts,tsx}'],
|
|
139
|
+
rules: {
|
|
140
|
+
'no-restricted-imports': 'off',
|
|
141
|
+
'no-restricted-syntax': 'off',
|
|
142
|
+
'no-console': 'off',
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// Prettier LAST — disable formatting rules that fight Prettier.
|
|
147
|
+
eslintConfigPrettier,
|
|
148
|
+
])
|
|
149
|
+
|
|
150
|
+
export default eslintConfig
|