@codepassion/skills 1.1.1 → 1.4.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 (41) hide show
  1. package/README.md +6 -1
  2. package/SKILLS.md +6 -1
  3. package/bin/c9n-skills.js +28 -3
  4. package/install.sh +25 -2
  5. package/package.json +1 -1
  6. package/skills/c9n/SKILL.md +344 -0
  7. package/skills/c9n-deliverables/REFERENCE.md +97 -0
  8. package/skills/c9n-deliverables/SKILL.md +63 -0
  9. package/skills/c9n-deliverables/scripts/data-dictionary.cjs +49 -0
  10. package/skills/c9n-deliverables/scripts/export-openapi.cjs +35 -0
  11. package/skills/c9n-deliverables/scripts/md-to-pdf.mjs +73 -0
  12. package/skills/c9n-deliverables/scripts/openapi-to-pdf.mjs +78 -0
  13. package/skills/c9n-deliverables/scripts/snapshot-source.sh +23 -0
  14. package/skills/c9n-pipeline/SKILL.md +128 -0
  15. package/skills/c9n-pipeline/templates/Dockerfile.api +49 -0
  16. package/skills/c9n-pipeline/templates/Dockerfile.service +45 -0
  17. package/skills/c9n-pipeline/templates/Dockerfile.web +50 -0
  18. package/skills/c9n-pipeline/templates/dockerignore +18 -0
  19. package/skills/c9n-pipeline/templates/workflows/_build-job.partial.yml +13 -0
  20. package/skills/c9n-pipeline/templates/workflows/_deploy-job.partial.yml +17 -0
  21. package/skills/c9n-pipeline/templates/workflows/_migration-check.partial.yml +16 -0
  22. package/skills/c9n-pipeline/templates/workflows/ci.yml +38 -0
  23. package/skills/c9n-pipeline/templates/workflows/deployment.yml +21 -0
  24. package/skills/c9n-sentry/REFERENCE.md +172 -0
  25. package/skills/c9n-sentry/SKILL.md +53 -0
  26. package/skills/c9n-spec/SKILL.md +92 -0
  27. package/skills/c9n-spec/templates/.github/pull_request_template.md +29 -0
  28. package/skills/c9n-spec/templates/AGENTS.md +179 -0
  29. package/skills/c9n-spec/templates/CLAUDE.md +6 -0
  30. package/skills/c9n-spec/templates/CONTEXT.md +53 -0
  31. package/skills/c9n-spec/templates/DESIGN.md +73 -0
  32. package/skills/c9n-spec/templates/docs/SRS.md +37 -0
  33. package/skills/c9n-spec/templates/docs/adr/0001-spec-driven-iso29110-docs.md +44 -0
  34. package/skills/c9n-spec/templates/docs/adr/_TEMPLATE.md +26 -0
  35. package/skills/c9n-spec/templates/docs/agents/domain.md +43 -0
  36. package/skills/c9n-spec/templates/docs/agents/issue-tracker.md +22 -0
  37. package/skills/c9n-spec/templates/docs/agents/triage-labels.md +27 -0
  38. package/skills/c9n-spec/templates/docs/architecture.md +50 -0
  39. package/skills/c9n-spec/templates/docs/features/_TEMPLATE.md +34 -0
  40. package/skills/c9n-spec/templates/docs/test-plan.md +30 -0
  41. package/skills/c9n-spec/templates/docs/traceability.md +27 -0
@@ -0,0 +1,21 @@
1
+ name: Deployment
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ tags:
7
+ - 'v*.*.*'
8
+ release:
9
+ types: [published]
10
+
11
+ # Assembled by c9n-pipeline from the partials below. The triggers and the
12
+ # event->environment mapping follow c9n-semver-deployment (single source of
13
+ # truth): tag push -> Alpha, prerelease -> Beta, release -> Production.
14
+ #
15
+ # Stamp one BUILD job per app (Alpha only — built once, redeployed by base tag),
16
+ # then one DEPLOY job per app per environment the project actually has. Prune
17
+ # environments the project does not use.
18
+
19
+ jobs:
20
+ {{BUILD_JOBS}}
21
+ {{DEPLOY_JOBS}}
@@ -0,0 +1,172 @@
1
+ # Sentry Bun+Elysia+Next.js — Reference
2
+
3
+ ## package.json (`packages/sentry/`)
4
+
5
+ ```json
6
+ {
7
+ "name": "@repo/sentry",
8
+ "type": "module",
9
+ "exports": {
10
+ "./bun": { "import": "./src/bun.ts" },
11
+ "./client": { "import": "./src/client.ts" },
12
+ "./server": { "import": "./src/server.ts" },
13
+ "./edge": { "import": "./src/edge.ts" },
14
+ "./pdpa": { "import": "./src/pdpa.ts" }
15
+ },
16
+ "dependencies": {
17
+ "@sentry/elysia": "^10",
18
+ "@sentry/nextjs": "^10"
19
+ },
20
+ "peerDependencies": {
21
+ "elysia": "*",
22
+ "next-runtime-env": "*"
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## PDPA scrubber
28
+
29
+ ```ts
30
+ // src/pdpa.ts
31
+ import type { Event } from "@sentry/core"
32
+
33
+ const PII_KEY = /phone|otp|lat|lng|latitude|longitude|member_?id|token|secret|password/i
34
+ const DROP_HEADERS = ["authorization", "cookie", "set-cookie"]
35
+
36
+ function redactKeys(obj: unknown): unknown {
37
+ if (!obj || typeof obj !== "object") return obj
38
+ if (Array.isArray(obj)) return obj.map(redactKeys)
39
+ return Object.fromEntries(
40
+ Object.entries(obj as Record<string, unknown>).map(([k, v]) => [
41
+ k,
42
+ PII_KEY.test(k) ? "[redacted]" : redactKeys(v)
43
+ ])
44
+ )
45
+ }
46
+
47
+ export function pdpaBeforeSend(event: Event): Event | null {
48
+ if (event.request) {
49
+ event.request.data = undefined
50
+ event.request.query_string = undefined
51
+ event.request.cookies = undefined
52
+ if (event.request.headers) {
53
+ DROP_HEADERS.forEach(h => { delete (event.request!.headers as Record<string, string>)[h] })
54
+ }
55
+ }
56
+ if (event.extra) event.extra = redactKeys(event.extra) as Record<string, unknown>
57
+ return event
58
+ }
59
+ ```
60
+
61
+ ## src/bun.ts
62
+
63
+ ```ts
64
+ export * from "@sentry/elysia"
65
+ import * as Sentry from "@sentry/elysia"
66
+ import { pdpaBeforeSend } from "./pdpa.js"
67
+
68
+ export function initBun(): void {
69
+ const dsn = process.env.SENTRY_DSN
70
+ if (!dsn) return
71
+ Sentry.init({
72
+ dsn,
73
+ environment: process.env.ENVIRONMENT || "development",
74
+ tracesSampleRate: 0.1,
75
+ sendDefaultPii: false,
76
+ beforeSend: pdpaBeforeSend,
77
+ initialScope: { tags: { app: "api" } }
78
+ })
79
+ }
80
+ ```
81
+
82
+ ## src/client.ts (runtime env — ADR 0005)
83
+
84
+ ```ts
85
+ export * from "@sentry/nextjs"
86
+ import * as Sentry from "@sentry/nextjs"
87
+ import { env } from "next-runtime-env" // ← NOT process.env
88
+ import { pdpaBeforeSend } from "./pdpa.js"
89
+
90
+ export function initClient(): void {
91
+ const dsn = env("NEXT_PUBLIC_SENTRY_DSN") // runtime, not build-time
92
+ if (!dsn) return
93
+ Sentry.init({
94
+ dsn,
95
+ environment: env("NEXT_PUBLIC_ENVIRONMENT") || "development",
96
+ tracesSampleRate: 0.1,
97
+ sendDefaultPii: false,
98
+ beforeSend: pdpaBeforeSend,
99
+ tags: { app: "web" }
100
+ })
101
+ }
102
+ ```
103
+
104
+ ## apps/api/src/index.ts wiring
105
+
106
+ ```ts
107
+ import "./lib/sentry.js" // ← must be FIRST import
108
+ // ... other imports ...
109
+ import { withElysia } from "@repo/sentry/bun"
110
+
111
+ const app = withElysia(new Elysia()) // wraps for auto error capture
112
+ .use(...)
113
+ // remove any console.error in onError — withElysia handles it
114
+ ```
115
+
116
+ ## apps/web/next.config.js
117
+
118
+ ```js
119
+ import { withSentryConfig } from "@repo/sentry/client"
120
+ const nextConfig = { transpilePackages: ["@repo/sentry"], ... }
121
+ export default withSentryConfig(nextConfig, {
122
+ silent: true,
123
+ hideSourceMaps: true,
124
+ tunnelRoute: "/monitoring" // guards against in-app-browser/CSP drops
125
+ })
126
+ ```
127
+
128
+ ## apps/web/instrumentation.ts
129
+
130
+ ```ts
131
+ export async function register() {
132
+ if (process.env.NEXT_RUNTIME === "nodejs") {
133
+ await import("./sentry.server.config")
134
+ }
135
+ if (process.env.NEXT_RUNTIME === "edge") {
136
+ await import("./sentry.edge.config")
137
+ }
138
+ }
139
+ export { captureRequestError as onRequestError } from "@sentry/nextjs"
140
+ ```
141
+
142
+ ## apps/web/instrumentation-client.ts
143
+
144
+ ```ts
145
+ import { initClient, captureRouterTransitionStart } from "@repo/sentry/client"
146
+ initClient()
147
+ export const onRouterTransitionStart = captureRouterTransitionStart
148
+ ```
149
+
150
+ ## turbo.json globalEnv additions
151
+
152
+ ```json
153
+ "globalEnv": ["SENTRY_DSN", "ENVIRONMENT"]
154
+ ```
155
+
156
+ Do NOT add `NEXT_PUBLIC_*` to globalEnv — they are runtime-injected via `PublicEnvScript`.
157
+
158
+ ## Sentry project setup
159
+
160
+ 1. sentry.io → **Create Project** → platform: **Next.js** → name: `<project>`
161
+ 2. Copy DSN from **Project Settings → Client Keys (DSN)**
162
+ 3. Same DSN in both Coolify services (one project, two env var names)
163
+ 4. Redeploy both services after setting vars
164
+
165
+ ## ADR checklist (write ADR when adopting)
166
+
167
+ - Why `@sentry/elysia` not `@sentry/bun` + custom plugin
168
+ - Why `@sentry/elysia` not `@sentry/node` (compiled binary landmine)
169
+ - Client env split reasoning (ADR 0005 or equivalent)
170
+ - PDPA/privacy scrubbing rationale
171
+ - Alpha-state risk acceptance if applicable
172
+ - Generic env naming rationale
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: c9n-sentry
3
+ description: Scaffold Sentry error tracking in a Bun + ElysiaJS + Next.js monorepo via a shared @repo/sentry package. Use when user wants to add Sentry, set up error tracking, or wire error monitoring to an ElysiaJS API and/or Next.js frontend in a Turborepo monorepo.
4
+ ---
5
+
6
+ # Sentry — Bun + Elysia + Next.js
7
+
8
+ ## Three landmines (check first)
9
+
10
+ 1. **`@sentry/node` under `bun --compile` fails silently** — valid DSN, zero events. Use `@sentry/elysia` (built on `@sentry/bun`). Never let `@sentry/node` load on the API.
11
+ 2. **Runtime public env** — if the project uses `next-runtime-env` (ADR 0005 pattern), the browser DSN MUST use `env("NEXT_PUBLIC_SENTRY_DSN")` not `process.env`. Server/edge/api use `process.env`. Wrong = undefined DSN in prod = dead Sentry.
12
+ 3. **PDPA / PII** — add `beforeSend` scrubber + `sendDefaultPii: false`. Strip request body/query/cookies, drop auth headers, recursively redact PII keys. See [REFERENCE.md](REFERENCE.md#pdpa-scrubber).
13
+
14
+ ## Quick start
15
+
16
+ ```
17
+ packages/sentry/ ← @repo/sentry (shared)
18
+ src/pdpa.ts ← beforeSend scrubber (shared by all inits)
19
+ src/bun.ts ← initBun() for apps/api
20
+ src/client.ts ← initClient() for browser (uses env() not process.env)
21
+ src/server.ts ← initServer() for Next.js server runtime
22
+ src/edge.ts ← initEdge() for Next.js edge runtime
23
+ package.json ← exports map: ./bun ./client ./server ./edge ./pdpa
24
+ apps/api/src/lib/sentry.ts ← import { initBun } from "@repo/sentry/bun"; initBun()
25
+ apps/api/src/index.ts ← first import: "./lib/sentry.js", then withElysia(new Elysia())
26
+ apps/web/instrumentation.ts ← register() → dynamic import server/edge config
27
+ apps/web/instrumentation-client.ts ← initClient()
28
+ apps/web/sentry.server.config.ts / sentry.edge.config.ts
29
+ apps/web/next.config.js ← withSentryConfig + transpilePackages: ["@repo/sentry"]
30
+ ```
31
+
32
+ ## Env vars
33
+
34
+ | Service | Key | Read by |
35
+ |---------|-----|---------|
36
+ | API (Coolify) | `SENTRY_DSN`, `ENVIRONMENT` | `process.env` |
37
+ | Web (Coolify) | `NEXT_PUBLIC_SENTRY_DSN`, `NEXT_PUBLIC_ENVIRONMENT` | `env()` from next-runtime-env (client) / `process.env` (server/edge) |
38
+
39
+ One Sentry project, same DSN in both vars. Add `initialScope: { tags: { app: "api" } }` to `initBun()` so api vs web events are distinguishable in the shared project.
40
+
41
+ ## Verification checklist
42
+
43
+ - [ ] `bun install --frozen-lockfile` clean
44
+ - [ ] `bun run check-types` (api + web) clean
45
+ - [ ] `bun run build --compile` on API — confirms `@sentry/node` never loaded (the landmine test)
46
+ - [ ] Web Sentry bundle builds green
47
+ - [ ] After deploy: `window.__ENV.NEXT_PUBLIC_SENTRY_DSN` populated in devtools (runtime env proof)
48
+ - [ ] Trigger a test error → event appears in Sentry tagged correct environment
49
+ - [ ] Open event payload — no phone/otp/lat/lng/member_id (PDPA proof)
50
+
51
+ ## Reference
52
+
53
+ See [REFERENCE.md](REFERENCE.md) for full file contents, PDPA scrubber code, and `turbo.json` config.
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: c9n-spec
3
+ description: Scaffold the C9N spec-driven, ISO/IEC 29110-aligned agentic documentation system INTO a repo — AGENTS.md (protocol + stack) with a CLAUDE.md bridge, CONTEXT.md glossary, DESIGN.md, the docs/ tree (SRS, architecture, traceability, test-plan, ADRs, feature stubs, agent docs), and the PR-template merge gate. Use when bootstrapping a new C9N project, "init docs", "set up the spec-driven docs", "add the agentic workflow files", or porting the ddg-jewelry doc system to another repo. Complements c9n-deliverables (that generates docs OUT of a codebase; this seeds the doc system INTO one).
4
+ ---
5
+
6
+ Bootstraps the Code Passion (C9N) spec-driven development doc system into a target repo. Drops
7
+ a self-contained, agent-readable documentation skeleton so a fresh project starts with the same
8
+ approval gates, traceability, and glossary discipline as the reference implementation
9
+ (ddg-jewelry). Fully generic — adapt the placeholders to whatever stack the project uses.
10
+
11
+ Bundled `templates/` are the source skeleton. **Copy them, then substitute tokens** — never edit
12
+ the templates in place for a specific project.
13
+
14
+ ## What gets scaffolded
15
+
16
+ | File | Role |
17
+ |------|------|
18
+ | `AGENTS.md` | **Canonical** agent context: the full ISO/IEC 29110 spec-driven protocol (inlined, so the repo is self-contained) + C9N stack + module patterns. References the sibling `c9n-*` convention skills rather than copying them. |
19
+ | `CLAUDE.md` | Bridge that `@AGENTS.md`-imports the canonical file (so Claude Code's memory auto-loads the protocol; other tools read AGENTS.md directly). |
20
+ | `CONTEXT.md` | Ubiquitous-language glossary skeleton (no implementation detail). |
21
+ | `DESIGN.md` | Visual design-system rules — **only if the repo has a frontend.** |
22
+ | `docs/SRS.md` | Requirements master registry (feature short-codes + system NFRs). |
23
+ | `docs/architecture.md` | Software-design as-is map. |
24
+ | `docs/traceability.md` | Requirement → design → test master index. |
25
+ | `docs/test-plan.md` | Master test strategy. |
26
+ | `docs/adr/0001-spec-driven-iso29110-docs.md` | Seed ADR: why this doc system exists. |
27
+ | `docs/adr/_TEMPLATE.md` | ADR format for future decisions. |
28
+ | `docs/features/_TEMPLATE.md` | Per-feature deep-doc stub (Requirements · Design · Test Plan · Test Cases · Traceability). |
29
+ | `docs/agents/{issue-tracker,triage-labels,domain}.md` | Agent-process docs (GitHub `gh`, triage vocab, domain-doc consumption). |
30
+ | `.github/pull_request_template.md` | The Definition-of-Done merge gate. |
31
+
32
+ ## Workflow
33
+
34
+ Run each step in order; this is a table of contents — the rules are below.
35
+
36
+ 1. **Detect repo shape.** Read the target's root `package.json`/workspaces. Decide:
37
+ monorepo vs single app; **frontend present?** (`apps/web`, or `next`/`astro`/`vite`/`react`
38
+ in any `package.json`) → include `DESIGN.md`. **Backend/API present?** → keep the API
39
+ module-patterns section in AGENTS.md; otherwise tell the user it's deletable.
40
+ 2. **No-clobber.** For every target path, **skip if it already exists** — never overwrite. Collect
41
+ skipped paths for the final report. (Re-running the skill must be safe and idempotent.)
42
+ 3. **Copy templates** into the target repo, substituting tokens (below). Skip `DESIGN.md` if no
43
+ frontend. Skip the API section guidance if no backend.
44
+ 4. **Optional scan — OFF by default.** Only if the user **explicitly** asks to seed from code
45
+ ("scan the codebase", "seed the glossary", "reverse-document"): read the codebase and fill
46
+ - `CONTEXT.md` — first real glossary terms (actors, core entities) from the domain;
47
+ - `docs/architecture.md` — the actual module map + data-model relationships;
48
+ - `docs/features/` — one as-built stub per shipped module (low-confidence, no test cases),
49
+ and register each in `docs/SRS.md` with a fresh short-code.
50
+ Without this request, leave the placeholders untouched.
51
+ 5. **Report.** Print created vs skipped files, then next steps: pick the first feature, write its
52
+ SRS section (Gate 1), get sign-off, then Design + Test Plan (Gate 2) — no production code
53
+ before Gate 2.
54
+
55
+ ## Token substitution
56
+
57
+ When copying, replace these placeholders:
58
+
59
+ | Token | Source |
60
+ |-------|--------|
61
+ | `{{PROJECT_NAME}}` | Target root dir name, or `package.json` `name` (humanized). |
62
+ | `{{YEAR}}` / `{{DATE}}` | Current year / ISO date (for the seed ADR). |
63
+ | `{{DECIDER}}` | Ask, or default to the repo owner. |
64
+ | Stack rows in AGENTS.md | Keep C9N defaults; trim rows the detected stack doesn't use. |
65
+
66
+ ## Conventions (referenced, not copied)
67
+
68
+ The scaffolded `AGENTS.md` points at the sibling C9N skills for engineering conventions — it does
69
+ **not** inline them, so they have a single source of truth:
70
+
71
+ - Commits → `c9n-commit-messages` · Branching → `c9n-git-branching` · PRs → `c9n-pull-requests`
72
+ - Clean code → `c9n-clean-code-typescript` · Lint/types → `c9n-typescript-eslint`
73
+ - Formatting → `c9n-code-formatting` · Review → `c9n-code-review`
74
+
75
+ For C9N-internal repos every dev has these installed, so the references always resolve. If you
76
+ scaffold into a repo where they may not be installed, tell the user to
77
+ `npx @codepassion/skills install claude`.
78
+
79
+ ## Gotchas
80
+
81
+ - **Combined install mode does not carry `templates/`.** `install.sh combined` copies only the
82
+ generated `skills/c9n` SKILL.md body; the bundled templates are absent. Install `c9n-spec` via
83
+ `install.sh claude` (or `project`/`codex`) so the templates come along. Same limitation as
84
+ `c9n-deliverables`' scripts.
85
+ - **AGENTS.md vs CLAUDE.md.** AGENTS.md is the real file. CLAUDE.md exists only so Claude Code's
86
+ memory auto-load reaches the protocol — it does so via the **`@AGENTS.md` import** (Claude Code's
87
+ memory-import syntax), not a markdown link (a link is inert and pulls nothing into context). Don't
88
+ duplicate content into CLAUDE.md. If a target tool doesn't support `@`-imports, it reads AGENTS.md
89
+ directly anyway, so nothing is lost.
90
+ - **Don't grade the stubs.** If you run the optional scan, as-built stubs describe *current*
91
+ behavior at low confidence with **no** test cases — deepen on touch, per the protocol. Don't
92
+ invent acceptance criteria for code you only read.
@@ -0,0 +1,29 @@
1
+ <!-- See AGENTS.md › Spec-Driven Development Protocol for the workflow and behavior-change rule. -->
2
+
3
+ ## What & why
4
+
5
+ <!-- Ticket ID + one-line summary. Link the approved SRS/Design if this is a feature. -->
6
+
7
+ ## Spec-driven gate
8
+
9
+ - [ ] For a **new feature**: SRS approved (Gate 1) and Design + Test Plan approved (Gate 2) **before** this code.
10
+ - [ ] This PR links the relevant `docs/features/<name>.md` (or master SRS section).
11
+
12
+ ## Behavior-change check
13
+
14
+ > Does this change **observable behavior, a requirement, an interface, or a test outcome**?
15
+
16
+ - [ ] **No** — refactor / rename / dep-bump / typo / format. Doc updates N/A. _(skip the next section)_
17
+ - [ ] **Yes** — complete the doc-update checklist below.
18
+
19
+ ### Doc updates (only if "Yes" above)
20
+
21
+ - [ ] SRS updated (new/changed requirement) — `docs/SRS.md` or `docs/features/<name>.md`
22
+ - [ ] Design updated (behavior/architecture) — `docs/architecture.md` or feature `## Design` (+ ADR if hard-to-reverse)
23
+ - [ ] Test cases updated/added (incl. regression for bug fixes)
24
+ - [ ] Traceability updated — `docs/traceability.md` or feature `## Traceability`
25
+
26
+ ## Verification
27
+
28
+ - [ ] Tests pass locally
29
+ - [ ] Lint/format clean (no semicolons, double quotes)
@@ -0,0 +1,179 @@
1
+ # AGENTS.md
2
+
3
+ AI-assisted development context for the **{{PROJECT_NAME}}** repo.
4
+
5
+ > This is the canonical agent file. `CLAUDE.md` is a one-line pointer to it. Codex, Cursor,
6
+ > OpenCode, and Claude Code all read this file.
7
+
8
+ ## Spec-Driven Development Protocol (read first)
9
+
10
+ This repo follows a spec-driven, ISO/IEC 29110-aligned documentation system (Software
11
+ Implementation work products). This section is the **canonical source** — agents MUST follow it.
12
+ The repo is authoritative.
13
+
14
+ ### Doc map
15
+
16
+ | File | ISO 29110 work product | Holds |
17
+ | ---------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------- |
18
+ | `AGENTS.md` / `CLAUDE.md` | — (agent protocol) | This protocol + stack + patterns |
19
+ | [`CONTEXT.md`](CONTEXT.md) | Domain glossary | Ubiquitous language only — no implementation |
20
+ | [`DESIGN.md`](DESIGN.md) | — (visual design system) | UI design language: color/type/component **intent & rules** (values in code) |
21
+ | [`docs/SRS.md`](docs/SRS.md) | Requirements Specification | Master registry: features + requirement IDs + system NFRs |
22
+ | [`docs/architecture.md`](docs/architecture.md) | Software Design | System map, module boundaries, data model, integrations |
23
+ | [`docs/traceability.md`](docs/traceability.md) | Traceability Record | Master index: requirement → design → test |
24
+ | [`docs/test-plan.md`](docs/test-plan.md) | Test Cases & Procedures | Master test strategy |
25
+ | `docs/adr/NNNN-*.md` | Architecture Decisions | One ADR per hard-to-reverse decision |
26
+ | `docs/features/<name>.md` | Per-feature deep doc | Sections: Requirements · Design · Test Plan · Test Cases · Traceability |
27
+
28
+ **Master-then-split (two levels):** a feature starts as a section in the master files →
29
+ graduates to its own `docs/features/<name>.md` when it outgrows the section → graduates to a
30
+ folder `docs/features/<name>/` (one file per section) only when a _section_ outgrows one file.
31
+ Default to the smallest form that fits.
32
+
33
+ **Feature ID:** every functional feature has a unique **short-code** — a 2–4 letter
34
+ human-readable mnemonic (`PAY`, `INV`, `AUTH`). The short-code _is_ the feature ID; it prefixes
35
+ all the feature's child IDs. Short-codes are **append-only** — pick a fresh, unused one for a new
36
+ feature (check `docs/SRS.md`), and never reuse one even after a feature is removed. `docs/SRS.md`
37
+ is the authoritative registry.
38
+
39
+ **Child IDs:** feature-prefixed, append-only — `PAY-REQ-001` (requirement), `PAY-TC-001` (test
40
+ case). Never reuse or renumber.
41
+
42
+ **"Design" disambiguation:** `DESIGN.md` = **visual** design (UI). The `## Design` sections in
43
+ `docs/features/*.md` and `docs/architecture.md` = **software** design (engineering). Different
44
+ layers — don't conflate them.
45
+
46
+ ### Approval gates (no code before blueprint)
47
+
48
+ A new feature passes three sequential gates, each needing the owner's sign-off:
49
+
50
+ 1. **SRS approved** — the _what_ (requirements + acceptance criteria).
51
+ 2. **Design + Test Plan approved** — the _how_ + how we'll prove it.
52
+ 3. **Code** — only now. The PR links the approved docs.
53
+
54
+ ### Definition of Ready (before touching code)
55
+
56
+ 1. Read [`CONTEXT.md`](CONTEXT.md) (glossary) and [`docs/architecture.md`](docs/architecture.md) (system map).
57
+ 2. Identify the feature; read its `docs/features/<name>.md` (or its master SRS section).
58
+ 3. For **UI work**, also read [`DESIGN.md`](DESIGN.md) first.
59
+ 4. For a **new feature**, Gate 1 **and** Gate 2 must already be approved. **No production code
60
+ before Gate 2 sign-off.**
61
+
62
+ ### Definition of Done (before opening the PR)
63
+
64
+ Apply the **behavior-change rule**: update docs **iff** the change alters observable behavior, a
65
+ requirement, an interface, or a test outcome.
66
+
67
+ | Change kind | Doc action |
68
+ | -------------------------------------------- | -------------------------------------------------------------- |
69
+ | New/changed requirement | Update SRS + traceability + test cases |
70
+ | Behavior/architecture change | Update design (+ ADR if hard-to-reverse) + affected test cases |
71
+ | Bug fix toward spec | Add a regression test case |
72
+ | Visual _intent_ change | Update `DESIGN.md` |
73
+ | Token _value_ change in Tailwind/CSS | No doc update (`DESIGN.md` references values, never copies) |
74
+ | Refactor / rename / dep-bump / typo / format | No doc update (code-only PR) |
75
+
76
+ The `.github/pull_request_template.md` checklist is the merge gate.
77
+
78
+ ### Reverse-documentation policy
79
+
80
+ Existing shipped modules each get an **as-built stub** in `docs/features/` (reverse-documented
81
+ from code, **not grilled** — requirements describe current behavior at low confidence, no test
82
+ cases). When a module is next touched, **deepen its stub** to the full chain (acceptance criteria
83
+ + Test Cases + Traceability) for the part you change — don't try to deepen the whole stub at once.
84
+ New features still get the full chain up front via the gates.
85
+
86
+ ## C9N engineering conventions (referenced, not duplicated)
87
+
88
+ These follow the Code Passion skill family — the single source of truth. Don't restate the rules
89
+ here; consult the skill:
90
+
91
+ | Topic | Skill |
92
+ | ---------------- | --------------------------- |
93
+ | Commit messages | `c9n-commit-messages` |
94
+ | Git branching | `c9n-git-branching` |
95
+ | Pull requests | `c9n-pull-requests` |
96
+ | Code review | `c9n-code-review` |
97
+ | Clean Code (TS) | `c9n-clean-code-typescript` |
98
+ | ESLint / types | `c9n-typescript-eslint` |
99
+ | Formatting | `c9n-code-formatting` |
100
+ | SemVer / deploy | `c9n-semver-deployment` |
101
+
102
+ Install: `npx @codepassion/skills install claude`.
103
+
104
+ ## Tech Stack
105
+
106
+ C9N defaults — trim rows this project doesn't use.
107
+
108
+ | Layer | Technology |
109
+ | ---------- | ------------------------------------------------ |
110
+ | Runtime | Bun |
111
+ | API | ElysiaJS |
112
+ | Frontend | Next.js / React (or Astro) |
113
+ | Database | PostgreSQL via Drizzle ORM |
114
+ | Storage | Supabase Storage + Auth |
115
+ | Build | Turborepo (monorepo) |
116
+ | Validation | Zod (shared with Drizzle via drizzle-zod) |
117
+ | Lint | ESLint + Prettier (no semicolons, double quotes) |
118
+ | Commits | Conventional Commits (commitlint + Husky) |
119
+
120
+ ## Project Structure
121
+
122
+ <!-- Describe the actual repo layout here. C9N monorepo default: -->
123
+
124
+ ```text
125
+ {{PROJECT_NAME}}/
126
+ apps/
127
+ api/ -- backend (if any)
128
+ web/ -- frontend (if any)
129
+ packages/
130
+ database/ -- Drizzle ORM schemas + client
131
+ ...
132
+ ```
133
+
134
+ <!-- =========================================================================
135
+ API MODULE PATTERNS — delete this whole section for a web-only repo.
136
+ ========================================================================= -->
137
+
138
+ ## API Module Structure (delete if no backend)
139
+
140
+ Each feature lives under `apps/api/src/modules/<feature>/`:
141
+
142
+ ```text
143
+ modules/<feature>/
144
+ models/ -- Zod schemas + types as namespace exports
145
+ use-cases/ -- Business logic as abstract static classes
146
+ services/ -- External API / infrastructure integrations
147
+ models.ts -- Barrel export
148
+ use-cases.ts -- Barrel export
149
+ constants.ts -- Shared constants
150
+ types.ts -- Shared TS interfaces
151
+ index.ts -- Elysia route definitions
152
+ ```
153
+
154
+ ### Key patterns
155
+
156
+ - **Models** — Zod `namespace` pattern; error messages as `z.literal()` so they're both
157
+ type-safe constants and response schema.
158
+ - **Use cases** — `abstract class` with a public `static execute(...)`; private `static` helpers
159
+ hold the how. `execute()` reads like a table of contents (each line a clear step), no inline
160
+ env-extraction/conditional-throw/DB-query.
161
+ - **Services** — same abstract-static shape, wrapping external integrations.
162
+ - **Routes** — `new Elysia({ prefix })`; `throw status(404, "...")` for HTTP errors.
163
+ - **Enum value objects** — `as const satisfies Record<string, T>` for type-safe dot access.
164
+
165
+ <!-- ===================== END deletable API section ===================== -->
166
+
167
+ ## Environment Variables
168
+
169
+ <!-- List required env vars and which module/package consumes each. -->
170
+
171
+ | Variable | Used by |
172
+ | -------------- | ------- |
173
+ | `DATABASE_URL` | … |
174
+
175
+ ## Code Style
176
+
177
+ Per `c9n-code-formatting` + `c9n-typescript-eslint`: no semicolons, double quotes, no trailing
178
+ commas. Barrel exports per subdirectory. Use the project's error-reporting path (e.g.
179
+ `Sentry.captureException`) — no `console.error`/`console.log` for errors.
@@ -0,0 +1,6 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ The canonical agent context for this repo is **AGENTS.md** (cross-tool standard). The import
4
+ below pulls it into Claude Code's memory so the spec-driven protocol auto-loads.
5
+
6
+ @AGENTS.md
@@ -0,0 +1,53 @@
1
+ # {{PROJECT_NAME}} — Domain Glossary & Project Context
2
+
3
+ > **Glossary only — no implementation detail.** This file is the ubiquitous language of the
4
+ > project: what each term *means*. Code, schemas, and decisions live elsewhere (`docs/`). Keep it
5
+ > a dictionary, not a spec. Produced/maintained via `/grill-with-docs`.
6
+
7
+ ## Actors
8
+
9
+ <!-- Who interacts with the system, and how they authenticate / what they can do. -->
10
+
11
+ ### <Actor>
12
+
13
+ - …
14
+
15
+ ## Core Entities
16
+
17
+ <!-- The nouns of the domain. For each: code term, customer-facing term, definition,
18
+ statuses/lifecycle, key fields. Example shape below — replace it. -->
19
+
20
+ ### <Entity> (<local-language term if any>)
21
+
22
+ - **Code term:** `<table_name>` (database), `/<route>` (API)
23
+ - **Customer-facing term:** "…"
24
+ - **Definition:** …
25
+ - **Statuses:** … → … → …
26
+ - **Lifecycle:** … → … → …
27
+
28
+ ## External Integrations
29
+
30
+ <!-- Third-party services and what they do for the domain — not how they're wired. -->
31
+
32
+ ### <Service>
33
+
34
+ - …
35
+
36
+ ## Data Model (Key Relationships)
37
+
38
+ ```
39
+ <Entity A> → <Entity B> (1:N)
40
+
41
+ ```
42
+
43
+ ## Key Business Decisions
44
+
45
+ <!-- Domain rules a newcomer would get wrong. One line each. -->
46
+
47
+ - …
48
+
49
+ ## Glossary Hygiene
50
+
51
+ - When output names a domain concept, use the term **as defined here** — don't drift to synonyms.
52
+ - If a needed concept isn't here yet: either you're inventing language the project doesn't use
53
+ (reconsider) or there's a real gap (resolve it via `/grill-with-docs`).