@codepassion/skills 1.2.0 → 1.5.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 (34) 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 +322 -0
  7. package/skills/c9n-pipeline/SKILL.md +171 -0
  8. package/skills/c9n-pipeline/templates/Dockerfile.api +49 -0
  9. package/skills/c9n-pipeline/templates/Dockerfile.service +45 -0
  10. package/skills/c9n-pipeline/templates/Dockerfile.web +55 -0
  11. package/skills/c9n-pipeline/templates/dockerignore +18 -0
  12. package/skills/c9n-pipeline/templates/workflows/_build-job.partial.yml +13 -0
  13. package/skills/c9n-pipeline/templates/workflows/_deploy-job.partial.yml +17 -0
  14. package/skills/c9n-pipeline/templates/workflows/_migration-check.partial.yml +16 -0
  15. package/skills/c9n-pipeline/templates/workflows/ci.yml +50 -0
  16. package/skills/c9n-pipeline/templates/workflows/deployment.yml +21 -0
  17. package/skills/c9n-sentry/REFERENCE.md +172 -0
  18. package/skills/c9n-sentry/SKILL.md +53 -0
  19. package/skills/c9n-spec/SKILL.md +92 -0
  20. package/skills/c9n-spec/templates/.github/pull_request_template.md +29 -0
  21. package/skills/c9n-spec/templates/AGENTS.md +179 -0
  22. package/skills/c9n-spec/templates/CLAUDE.md +6 -0
  23. package/skills/c9n-spec/templates/CONTEXT.md +53 -0
  24. package/skills/c9n-spec/templates/DESIGN.md +73 -0
  25. package/skills/c9n-spec/templates/docs/SRS.md +37 -0
  26. package/skills/c9n-spec/templates/docs/adr/0001-spec-driven-iso29110-docs.md +44 -0
  27. package/skills/c9n-spec/templates/docs/adr/_TEMPLATE.md +26 -0
  28. package/skills/c9n-spec/templates/docs/agents/domain.md +43 -0
  29. package/skills/c9n-spec/templates/docs/agents/issue-tracker.md +22 -0
  30. package/skills/c9n-spec/templates/docs/agents/triage-labels.md +27 -0
  31. package/skills/c9n-spec/templates/docs/architecture.md +50 -0
  32. package/skills/c9n-spec/templates/docs/features/_TEMPLATE.md +34 -0
  33. package/skills/c9n-spec/templates/docs/test-plan.md +30 -0
  34. package/skills/c9n-spec/templates/docs/traceability.md +27 -0
@@ -0,0 +1,49 @@
1
+ # -----------------------------------------------------------------------------
2
+ # {{PACKAGE_NAME}} (Elysia BFF) — compiled to a single Bun binary, run on
3
+ # debian slim. Generated by c9n-pipeline; tune freely after.
4
+ # -----------------------------------------------------------------------------
5
+
6
+ FROM oven/bun:{{BUN_VERSION}} AS build
7
+
8
+ WORKDIR /app
9
+
10
+ # Root manifests + lockfile
11
+ COPY package.json bun.lock ./
12
+
13
+ # This app's manifest + shared packages (compile needs only this member's graph)
14
+ COPY {{APP_DIR}}/package.json ./{{APP_DIR}}/package.json
15
+ COPY packages/ ./packages/
16
+
17
+ # Source needed to compile (copied before install so workspace links resolve)
18
+ COPY {{APP_DIR}}/src ./{{APP_DIR}}/src
19
+
20
+ RUN bun install
21
+
22
+ ENV NODE_ENV=production
23
+
24
+ # Compile the API to a standalone binary from the repo root
25
+ RUN bun build \
26
+ --compile \
27
+ --minify-whitespace \
28
+ --minify-syntax \
29
+ --target=bun \
30
+ --outfile /app/server \
31
+ ./{{APP_DIR}}/src/index.ts
32
+
33
+ # Runtime image — debian slim for compiled-Bun-binary compatibility
34
+ FROM debian:bookworm-slim
35
+
36
+ WORKDIR /app
37
+
38
+ RUN apt-get update && \
39
+ apt-get install -y --no-install-recommends ca-certificates && \
40
+ rm -rf /var/lib/apt/lists/*
41
+
42
+ COPY --from=build /app/server ./server
43
+ RUN chmod +x ./server
44
+
45
+ ENV NODE_ENV=production
46
+
47
+ EXPOSE {{APP_PORT}}
48
+
49
+ CMD ["./server"]
@@ -0,0 +1,45 @@
1
+ # -----------------------------------------------------------------------------
2
+ # {{PACKAGE_NAME}} (generic Bun service / worker) — compiled to a single Bun
3
+ # binary, run on debian slim. Generated by c9n-pipeline.
4
+ # A worker with no HTTP port: drop the EXPOSE line and skip its Coolify domain.
5
+ # NOTE: the org deploy.yml only wires API_UUID + WEB_UUID — a third app type
6
+ # needs a PR to codepassion-team/cicd to add its COOLIFY_RESOURCE_<NAME>_UUID.
7
+ # -----------------------------------------------------------------------------
8
+
9
+ FROM oven/bun:{{BUN_VERSION}} AS build
10
+
11
+ WORKDIR /app
12
+
13
+ COPY package.json bun.lock ./
14
+ COPY {{APP_DIR}}/package.json ./{{APP_DIR}}/package.json
15
+ COPY packages/ ./packages/
16
+ COPY {{APP_DIR}}/src ./{{APP_DIR}}/src
17
+
18
+ RUN bun install
19
+
20
+ ENV NODE_ENV=production
21
+
22
+ RUN bun build \
23
+ --compile \
24
+ --minify-whitespace \
25
+ --minify-syntax \
26
+ --target=bun \
27
+ --outfile /app/server \
28
+ ./{{APP_DIR}}/src/index.ts
29
+
30
+ FROM debian:bookworm-slim
31
+
32
+ WORKDIR /app
33
+
34
+ RUN apt-get update && \
35
+ apt-get install -y --no-install-recommends ca-certificates && \
36
+ rm -rf /var/lib/apt/lists/*
37
+
38
+ COPY --from=build /app/server ./server
39
+ RUN chmod +x ./server
40
+
41
+ ENV NODE_ENV=production
42
+
43
+ EXPOSE {{APP_PORT}}
44
+
45
+ CMD ["./server"]
@@ -0,0 +1,55 @@
1
+ # -----------------------------------------------------------------------------
2
+ # {{PACKAGE_NAME}} (Next.js app) — Bun multi-stage build.
3
+ # Public env is read at RUNTIME via next-runtime-env (<PublicEnvScript>), so this
4
+ # image bakes no NEXT_PUBLIC_* — Coolify injects them at run, like the API image.
5
+ # Generated by c9n-pipeline; see the ADR this skill points you to.
6
+ #
7
+ # {{BUN_VERSION}} must be >= 1.3.10 — 1.2.x breaks `next build` on Linux.
8
+ # Single-app repo: {{APP_DIR}}=. and {{WORKSPACE_MANIFEST_COPIES}}= empty; also
9
+ # delete the `COPY packages/ ./packages/` line below (no packages/ dir). See the
10
+ # "Single-app repos" section in SKILL.md.
11
+ # -----------------------------------------------------------------------------
12
+
13
+ FROM oven/bun:{{BUN_VERSION}} AS base
14
+ WORKDIR /app
15
+
16
+ # Install dependencies with bun
17
+ FROM base AS deps
18
+ COPY package.json bun.lock ./
19
+ {{WORKSPACE_MANIFEST_COPIES}}
20
+ COPY packages/ ./packages/
21
+ RUN bun install
22
+
23
+ # Rebuild the source code only when needed
24
+ FROM base AS builder
25
+ WORKDIR /app
26
+ COPY --from=deps /app/node_modules ./node_modules
27
+ COPY . .
28
+
29
+ # Next.js expects {{APP_DIR}}/.env to exist; intentionally empty — no public env
30
+ # is baked at build (it is injected at runtime via next-runtime-env).
31
+ RUN touch {{APP_DIR}}/.env
32
+
33
+ RUN cd {{APP_DIR}} && bun run build
34
+
35
+ # Production image — serve the Next.js standalone output
36
+ FROM base AS runner
37
+ WORKDIR /app
38
+
39
+ ENV NODE_ENV=production \
40
+ PORT={{APP_PORT}} \
41
+ HOSTNAME="0.0.0.0"
42
+
43
+ RUN groupadd --system --gid 1001 nodejs && \
44
+ useradd --system --uid 1001 nextjs
45
+
46
+ # Leverage Next.js output file tracing to keep the image small
47
+ COPY --from=builder --chown=nextjs:nodejs /app/{{APP_DIR}}/.next/standalone ./
48
+ COPY --from=builder --chown=nextjs:nodejs /app/{{APP_DIR}}/.next/static ./{{APP_DIR}}/.next/static
49
+ COPY --from=builder --chown=nextjs:nodejs /app/{{APP_DIR}}/public ./{{APP_DIR}}/public
50
+
51
+ USER nextjs
52
+
53
+ EXPOSE {{APP_PORT}}
54
+
55
+ CMD ["bun", "{{APP_DIR}}/server.js"]
@@ -0,0 +1,18 @@
1
+ .next
2
+ node_modules
3
+ **/node_modules
4
+ **/.next
5
+ **/dist
6
+ .git
7
+ .turbo
8
+ **/.turbo
9
+ npm-debug.log
10
+ yarn-error.log
11
+ bun-debug.log
12
+ .env
13
+ **/.env
14
+ .env.*
15
+ **/.env.*
16
+
17
+ # Next.js telemetry
18
+ .next/telemetry
@@ -0,0 +1,13 @@
1
+ # One BUILD job per app. Alpha only — the image is built once at the tag push
2
+ # and redeployed to Beta/Production by base tag (no rebuild). {{APP_KEY}} is a
3
+ # lowercase id unique per app (e.g. api, web). {{ORG_REF}} is the org workflow
4
+ # ref (e.g. turborepo) — keep it identical across every job in this file.
5
+ build-{{APP_KEY}}-alpha:
6
+ name: Build
7
+ if: github.event_name != 'release' && startsWith(github.ref, 'refs/tags/v')
8
+ uses: codepassion-team/cicd/.github/workflows/build.yml@{{ORG_REF}}
9
+ with:
10
+ environment: Alpha
11
+ build_path: ./{{APP_DIR}}
12
+ package_name: {{PACKAGE_NAME}}
13
+ secrets: inherit
@@ -0,0 +1,17 @@
1
+ # One DEPLOY job per app per environment. {{DEPLOY_NAME}} is the org deploy.yml
2
+ # name input that resolves the Coolify UUID var: it is uppercased to
3
+ # ${{DEPLOY_NAME_UPPER}}_UUID, so it MUST be a key the org deploy.yml wires
4
+ # (currently only API and WEB). Stamp the right {{IF_CONDITION}} per environment
5
+ # from c9n-semver-deployment:
6
+ # Alpha -> needs: build-{{APP_KEY}}-alpha ; if: github.event_name != 'release' && startsWith(github.ref, 'refs/tags/v')
7
+ # Beta -> (no needs) ; if: github.event_name == 'release' && github.event.release.prerelease == true && startsWith(github.event.release.tag_name, 'v')
8
+ # Production -> (no needs) ; if: github.event_name == 'release' && github.event.release.prerelease == false && startsWith(github.event.release.tag_name, 'v')
9
+ deploy-{{APP_KEY}}-{{ENV_KEY}}:
10
+ name: Deploy
11
+ if: {{IF_CONDITION}}
12
+ {{NEEDS_LINE}}
13
+ uses: codepassion-team/cicd/.github/workflows/deploy.yml@{{ORG_REF}}
14
+ with:
15
+ name: {{DEPLOY_NAME}}
16
+ environment: {{ENVIRONMENT}}
17
+ secrets: inherit
@@ -0,0 +1,16 @@
1
+ # Inject in place of {{MIGRATION_CHECK}} in ci.yml ONLY when a DB is detected
2
+ # (a migration-generate script exists in some package.json AND a migrations dir
3
+ # exists). Substitute {{MIGRATION_SCRIPT}} and {{MIGRATIONS_DIR}} with the real
4
+ # detected names — do not assume drizzle:generate / packages/supabase/migrations.
5
+ # If no DB, {{MIGRATION_CHECK}} is the empty string and ci.yml ends at Build.
6
+ - name: Verify migrations are up to date
7
+ run: bun run {{MIGRATION_SCRIPT}} -- --name check
8
+ - name: Check for uncommitted migration changes
9
+ run: |
10
+ if git diff --name-only --exit-code {{MIGRATIONS_DIR}}; then
11
+ echo "Migrations are up to date"
12
+ else
13
+ echo "Detected uncommitted migration changes. Run 'bun run {{MIGRATION_SCRIPT}}' locally and commit the result."
14
+ git diff {{MIGRATIONS_DIR}}
15
+ exit 1
16
+ fi
@@ -0,0 +1,50 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: ['main', 'develop']
5
+ pull_request:
6
+ types: [opened, synchronize]
7
+ jobs:
8
+ build:
9
+ name: Check
10
+ timeout-minutes: 15
11
+ runs-on: ubuntu-latest
12
+ env:
13
+ TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
14
+ TURBO_TEAM: ${{ vars.TURBO_TEAM }}
15
+ steps:
16
+ - name: Check out code
17
+ uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 2
20
+ - name: Cache turbo build setup
21
+ uses: actions/cache@v4
22
+ with:
23
+ path: .turbo
24
+ key: ${{ runner.os }}-turbo-${{ github.sha }}
25
+ restore-keys: |
26
+ ${{ runner.os }}-turbo-
27
+ - uses: oven-sh/setup-bun@v2
28
+ - name: Setup Node.js environment
29
+ uses: actions/setup-node@v4
30
+ with:
31
+ node-version: 24
32
+ - name: Install dependencies
33
+ run: bun install
34
+ - name: Check types
35
+ run: bun run check-types
36
+ - name: Build
37
+ # Placeholder NEXT_PUBLIC_* values satisfy module-init that reads them at import
38
+ # time (e.g. Supabase clients) — CI has no .env files, so without these
39
+ # `next build` throws "Error: supabaseUrl is required" collecting page
40
+ # data. Real values are injected at runtime via next-runtime-env, never
41
+ # baked. Mirrors the Dockerfile build stage. Add one line per public var
42
+ # the app constructs a client from at import.
43
+ run: SKIP_ENV_VALIDATION=1 bun run build
44
+ env:
45
+ NEXT_PUBLIC_SUPABASE_URL: http://placeholder.invalid
46
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: placeholder
47
+ {{MIGRATION_CHECK}}
48
+ # Single-app repos (no turbo.json): remove the TURBO_TOKEN/TURBO_TEAM `env:` and
49
+ # the `.turbo` cache step above, and swap `bun run check-types` for
50
+ # `bunx tsc --noEmit` if the repo has no check-types script.
@@ -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)