@rashidee/co2 1.2.5

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 (190) hide show
  1. package/dist/index.js +25449 -0
  2. package/drizzle/0000_remarkable_charles_xavier.sql +210 -0
  3. package/drizzle/0001_wise_wolf_cub.sql +13 -0
  4. package/drizzle/0002_secret_spyke.sql +16 -0
  5. package/drizzle/0003_workspace_config_singleton.sql +16 -0
  6. package/drizzle/0004_terminal_claim_v120.sql +11 -0
  7. package/drizzle/0005_brainstorm_v124.sql +10 -0
  8. package/drizzle/0006_project_v140.sql +6 -0
  9. package/drizzle/0007_prd_wizard_v124.sql +14 -0
  10. package/drizzle/0008_workflow_artifact_v126.sql +24 -0
  11. package/drizzle/0009_project_import_v150.sql +7 -0
  12. package/drizzle/0010_quality_v151.sql +3 -0
  13. package/drizzle/meta/0000_snapshot.json +1335 -0
  14. package/drizzle/meta/0001_snapshot.json +1416 -0
  15. package/drizzle/meta/0002_snapshot.json +1510 -0
  16. package/drizzle/meta/_journal.json +83 -0
  17. package/package.json +41 -0
  18. package/plugin/.claude-plugin/marketplace.json +36 -0
  19. package/plugin/.claude-plugin/plugin.json +22 -0
  20. package/plugin/README.md +625 -0
  21. package/plugin/SKILLS.md +350 -0
  22. package/plugin/co2.svg +5 -0
  23. package/plugin/commands/brainstorm-loop.md +129 -0
  24. package/plugin/skills/conductor-defect/SKILL.md +898 -0
  25. package/plugin/skills/conductor-feature-develop/SKILL.md +1383 -0
  26. package/plugin/skills/conductor-feature-develop/references/implementation-domain-template.md +131 -0
  27. package/plugin/skills/conductor-feature-develop/references/implementation-master-template.md +89 -0
  28. package/plugin/skills/conductor-feature-develop/references/playwright-setup.md +224 -0
  29. package/plugin/skills/conductor-feature-prepare/SKILL.md +604 -0
  30. package/plugin/skills/depgen-k8s/SKILL.md +468 -0
  31. package/plugin/skills/depgen-k8s/references/dockerfile-laravel.md +197 -0
  32. package/plugin/skills/depgen-k8s/references/dockerfile-nodejs.md +163 -0
  33. package/plugin/skills/depgen-k8s/references/dockerfile-spring-boot.md +174 -0
  34. package/plugin/skills/depgen-k8s/references/k8s-patterns.md +869 -0
  35. package/plugin/skills/mockgen-shadcn/SKILL.md +1067 -0
  36. package/plugin/skills/mockgen-shadcn/references/admin-layout-template.md +1467 -0
  37. package/plugin/skills/mockgen-shadcn/references/mockup-hub-template.md +498 -0
  38. package/plugin/skills/mockgen-shadcn/references/mockup-index-template.md +216 -0
  39. package/plugin/skills/mockgen-tailwind/SKILL.md +904 -0
  40. package/plugin/skills/mockgen-tailwind/references/admin-layout-template.md +720 -0
  41. package/plugin/skills/mockgen-tailwind/references/mockup-hub-template.md +498 -0
  42. package/plugin/skills/mockgen-tailwind/references/mockup-index-template.md +190 -0
  43. package/plugin/skills/modelgen-nosql/SKILL.md +617 -0
  44. package/plugin/skills/modelgen-nosql/references/model-extraction-methodology.md +497 -0
  45. package/plugin/skills/modelgen-nosql/references/nosql-design-guide.md +258 -0
  46. package/plugin/skills/modelgen-relational/SKILL.md +707 -0
  47. package/plugin/skills/modelgen-relational/references/model-extraction-methodology.md +499 -0
  48. package/plugin/skills/specgen-flutter-riverpod/SKILL.md +898 -0
  49. package/plugin/skills/specgen-flutter-riverpod/references/component-patterns.md +971 -0
  50. package/plugin/skills/specgen-flutter-riverpod/references/notification-patterns.md +457 -0
  51. package/plugin/skills/specgen-flutter-riverpod/references/routing-patterns.md +362 -0
  52. package/plugin/skills/specgen-flutter-riverpod/references/security-patterns.md +709 -0
  53. package/plugin/skills/specgen-flutter-riverpod/references/spec-template.md +1566 -0
  54. package/plugin/skills/specgen-flutter-riverpod/references/state-patterns.md +518 -0
  55. package/plugin/skills/specgen-flutter-riverpod/references/storage-patterns.md +370 -0
  56. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/SKILL.md +984 -0
  57. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/batch-patterns.md +359 -0
  58. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/messaging-patterns.md +468 -0
  59. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/modulith-patterns.md +461 -0
  60. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/reporting-patterns.md +803 -0
  61. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/security-patterns.md +501 -0
  62. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/spec-template.md +1268 -0
  63. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/web-patterns.md +301 -0
  64. package/plugin/skills/specgen-node-cli-web/SKILL.md +561 -0
  65. package/plugin/skills/specgen-node-cli-web/references/auth-patterns.md +293 -0
  66. package/plugin/skills/specgen-node-cli-web/references/cli-packaging-patterns.md +250 -0
  67. package/plugin/skills/specgen-node-cli-web/references/server-patterns.md +247 -0
  68. package/plugin/skills/specgen-node-cli-web/references/spec-template.md +401 -0
  69. package/plugin/skills/specgen-node-cli-web/references/testing-patterns.md +174 -0
  70. package/plugin/skills/specgen-react-mui/SKILL.md +789 -0
  71. package/plugin/skills/specgen-react-mui/references/component-patterns.md +1077 -0
  72. package/plugin/skills/specgen-react-mui/references/reporting-patterns.md +1998 -0
  73. package/plugin/skills/specgen-react-mui/references/routing-patterns.md +461 -0
  74. package/plugin/skills/specgen-react-mui/references/security-patterns.md +599 -0
  75. package/plugin/skills/specgen-react-mui/references/spec-template.md +1030 -0
  76. package/plugin/skills/specgen-react-mui/references/state-patterns.md +327 -0
  77. package/plugin/skills/specgen-react-tailwind/SKILL.md +859 -0
  78. package/plugin/skills/specgen-react-tailwind/references/component-patterns.md +1212 -0
  79. package/plugin/skills/specgen-react-tailwind/references/reporting-patterns.md +1529 -0
  80. package/plugin/skills/specgen-react-tailwind/references/routing-patterns.md +669 -0
  81. package/plugin/skills/specgen-react-tailwind/references/security-patterns.md +656 -0
  82. package/plugin/skills/specgen-react-tailwind/references/spec-template.md +1237 -0
  83. package/plugin/skills/specgen-react-tailwind/references/state-patterns.md +327 -0
  84. package/plugin/skills/specgen-sdk-java/SKILL.md +933 -0
  85. package/plugin/skills/specgen-sdk-java/references/api-extraction-patterns.md +247 -0
  86. package/plugin/skills/specgen-sdk-java/references/http-client-patterns.md +495 -0
  87. package/plugin/skills/specgen-sdk-java/references/packaging-patterns.md +366 -0
  88. package/plugin/skills/specgen-sdk-java/references/spec-template.md +956 -0
  89. package/plugin/skills/specgen-spring-jpa-jtehtmx/SKILL.md +1284 -0
  90. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/batch-patterns.md +1224 -0
  91. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/jasper-patterns.md +1638 -0
  92. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/messaging-patterns.md +512 -0
  93. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/modulith-patterns.md +354 -0
  94. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/security-patterns.md +551 -0
  95. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/spec-template.md +2502 -0
  96. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/web-patterns.md +503 -0
  97. package/plugin/skills/specgen-spring-jpa-restapi/SKILL.md +990 -0
  98. package/plugin/skills/specgen-spring-jpa-restapi/references/batch-patterns.md +1224 -0
  99. package/plugin/skills/specgen-spring-jpa-restapi/references/messaging-patterns.md +512 -0
  100. package/plugin/skills/specgen-spring-jpa-restapi/references/modulith-patterns.md +279 -0
  101. package/plugin/skills/specgen-spring-jpa-restapi/references/reporting-patterns.md +1536 -0
  102. package/plugin/skills/specgen-spring-jpa-restapi/references/restapi-patterns.md +722 -0
  103. package/plugin/skills/specgen-spring-jpa-restapi/references/security-patterns.md +351 -0
  104. package/plugin/skills/specgen-spring-jpa-restapi/references/spec-template.md +553 -0
  105. package/plugin/skills/specgen-ts-cli/SKILL.md +861 -0
  106. package/plugin/skills/specgen-ts-cli/references/async-patterns.md +1101 -0
  107. package/plugin/skills/specgen-ts-cli/references/command-patterns.md +383 -0
  108. package/plugin/skills/specgen-ts-cli/references/config-patterns.md +430 -0
  109. package/plugin/skills/specgen-ts-cli/references/database-patterns.md +750 -0
  110. package/plugin/skills/specgen-ts-cli/references/packaging-patterns.md +426 -0
  111. package/plugin/skills/specgen-ts-cli/references/spec-template.md +1391 -0
  112. package/plugin/skills/specgen-ts-cli/references/testing-patterns.md +909 -0
  113. package/plugin/skills/testgen-functional/SKILL.md +1381 -0
  114. package/plugin/skills/tracegen-matrix/SKILL.md +243 -0
  115. package/plugin/skills/util-preparek8senv/SKILL.md +422 -0
  116. package/plugin/skills/util-projectinit/SKILL.md +307 -0
  117. package/plugin/skills/util-projectinit/reference/brainstorm-loop.md +129 -0
  118. package/plugin/skills/util-projectinit/reference/brainstorm-protocol.md +144 -0
  119. package/plugin/skills/util-projectinit/reference/brainstorm-setup-guide.md +153 -0
  120. package/plugin/skills/util-projectinit/reference/brainstorm-template-appdev.md +87 -0
  121. package/plugin/skills/util-projectinit/reference/co2-context-generation-guide.md +761 -0
  122. package/plugin/skills/util-projectsync/SKILL.md +501 -0
  123. package/plugin/skills/util-updprd/SKILL.md +324 -0
  124. package/plugin/skills/util-usanalyzer/SKILL.md +307 -0
  125. package/plugin/skills/util-ustagger/SKILL.md +154 -0
  126. package/static/assets/abnfDiagram-VRR7QNED-DvPuwyCV.js +1 -0
  127. package/static/assets/arc-DRKw7sjs.js +1 -0
  128. package/static/assets/architectureDiagram-ZJ3FMSHR-CaNcxUbC.js +36 -0
  129. package/static/assets/blockDiagram-677ZJIJ3-Demd4AOK.js +132 -0
  130. package/static/assets/c4Diagram-LMCZKHZV-PVKUfc2x.js +10 -0
  131. package/static/assets/channel-C2nVbuwv.js +1 -0
  132. package/static/assets/chunk-2Q5K7J3B-CExf8ww_.js +1 -0
  133. package/static/assets/chunk-32BRIVSS-CFPaoONF.js +1 -0
  134. package/static/assets/chunk-5VM5RSS4-DE2esM67.js +15 -0
  135. package/static/assets/chunk-EX3LRPZG-SON_YdDG.js +231 -0
  136. package/static/assets/chunk-JWPE2WC7-Qxah8LNr.js +1 -0
  137. package/static/assets/chunk-MOJQB5TN-BcWGQV3j.js +88 -0
  138. package/static/assets/chunk-RYQCIY6F-DkDj-OR5.js +1 -0
  139. package/static/assets/chunk-V7JOEXUC-BlI1Mrah.js +206 -0
  140. package/static/assets/chunk-VR4S4FIN-Agf__duj.js +1 -0
  141. package/static/assets/chunk-XXDRQBXY-B5CfAh85.js +1 -0
  142. package/static/assets/classDiagram-OUVF2IWQ-DXJIljsR.js +1 -0
  143. package/static/assets/classDiagram-v2-EOCWNBFH-DXJIljsR.js +1 -0
  144. package/static/assets/cose-bilkent-JH36ORCC-DO0cQkcy.js +1 -0
  145. package/static/assets/cynefin-VYW2F7L2-CfOnsnXc.js +178 -0
  146. package/static/assets/cynefinDiagram-TSTJHNR4-BJ8tULAv.js +62 -0
  147. package/static/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
  148. package/static/assets/dagre-VKFMJZFB-DfjwzHqP.js +4 -0
  149. package/static/assets/defaultLocale-DX6XiGOO.js +1 -0
  150. package/static/assets/diagram-FQU43EPY-CndSOIIM.js +3 -0
  151. package/static/assets/diagram-G47NLZAW-Czf5hN0Z.js +24 -0
  152. package/static/assets/diagram-NH7WQ7WH-COAyojGh.js +24 -0
  153. package/static/assets/diagram-OA4YK3LP-H8PoiN2m.js +30 -0
  154. package/static/assets/diagram-WEI45ONY-DzcaVzjp.js +41 -0
  155. package/static/assets/ebnfDiagram-CCIWWBDH-DPazGYLJ.js +1 -0
  156. package/static/assets/erDiagram-Q63AITRT-Bo-fubgF.js +85 -0
  157. package/static/assets/flowDiagram-23GEKE2U-CSvxUDwh.js +156 -0
  158. package/static/assets/ganttDiagram-NO4QXBWP-DnBveWX6.js +292 -0
  159. package/static/assets/gitGraphDiagram-IHSO6WYX-B3rVL8c-.js +106 -0
  160. package/static/assets/graph-C9eacEi8.js +1 -0
  161. package/static/assets/index-LZSQkLE2.css +41 -0
  162. package/static/assets/index-y7XDSgMG.js +495 -0
  163. package/static/assets/infoDiagram-FWYZ7A6U-CvWV9yy2.js +2 -0
  164. package/static/assets/init-Gi6I4Gst.js +1 -0
  165. package/static/assets/ishikawaDiagram-FXEZZL3T-DF28a1N6.js +70 -0
  166. package/static/assets/journeyDiagram-5HDEW3XC-CB6CugYk.js +139 -0
  167. package/static/assets/kanban-definition-HUTT4EX6-ResSLF6d.js +89 -0
  168. package/static/assets/katex-C5jXJg4s.js +257 -0
  169. package/static/assets/layout-DEXfKzaS.js +1 -0
  170. package/static/assets/linear-CLO--ryk.js +1 -0
  171. package/static/assets/map-Czzmt4hB.js +1 -0
  172. package/static/assets/mindmap-definition-LN4V7U3C-BvW3EbxX.js +96 -0
  173. package/static/assets/ordinal-Cboi1Yqb.js +1 -0
  174. package/static/assets/pegDiagram-2B236MQR-BHCgqrrM.js +1 -0
  175. package/static/assets/pieDiagram-ENE6RG2P-DVmCQ5FA.js +39 -0
  176. package/static/assets/quadrantDiagram-ABIIQ3AL-B3e5KR52.js +7 -0
  177. package/static/assets/railroadDiagram-RFXS5EU6-Csv5ysLc.js +1 -0
  178. package/static/assets/requirementDiagram-TGXJPOKE-DOMVzvnB.js +84 -0
  179. package/static/assets/sankeyDiagram-HTMAVEWB-B1dcTOvy.js +40 -0
  180. package/static/assets/sequenceDiagram-DBY2YBRQ-BY414yeO.js +162 -0
  181. package/static/assets/sizeCapture-X5ZJPWSS-CuJfrfBN.js +1 -0
  182. package/static/assets/stateDiagram-2N3HPSRC-FX4rJkzV.js +1 -0
  183. package/static/assets/stateDiagram-v2-6OUMAXLB-BVufbO_H.js +1 -0
  184. package/static/assets/swimlanes-5IMT3BWC-Sfy58mmv.js +2 -0
  185. package/static/assets/swimlanesDiagram-G3AALYLV-wDCDw08H.js +8 -0
  186. package/static/assets/timeline-definition-FHXFAJF6-CmV7by8p.js +120 -0
  187. package/static/assets/vennDiagram-L72KCM5P-FqIyFZFt.js +34 -0
  188. package/static/assets/wardleyDiagram-EHGQE667-BZ06O45i.js +78 -0
  189. package/static/assets/xychartDiagram-FW5EYKEG-BOkffR06.js +7 -0
  190. package/static/index.html +24 -0
@@ -0,0 +1,247 @@
1
+ # Server Patterns — specgen-node-cli-web
2
+
3
+ Canonical patterns for the data directory (root spec Section 5), database layer
4
+ (Section 6), and Hono server composition (Section 7).
5
+
6
+ ## 1. Data directory resolution
7
+
8
+ Per-platform, XDG-compliant, keyed by the package name. Resolve manually (shown below) or
9
+ via `env-paths` — no heavier dependency:
10
+
11
+ ```ts
12
+ import { homedir } from 'node:os'
13
+ import { join } from 'node:path'
14
+ import { mkdirSync } from 'node:fs'
15
+
16
+ export function resolveDataDir(override?: string): string {
17
+ const dir = override ?? defaultDataDir()
18
+ mkdirSync(dir, { recursive: true, mode: 0o700 })
19
+ return dir
20
+ }
21
+
22
+ function defaultDataDir(): string {
23
+ const app = '{{PACKAGE_NAME}}'
24
+ switch (process.platform) {
25
+ case 'darwin':
26
+ return join(homedir(), 'Library', 'Application Support', app)
27
+ case 'win32':
28
+ return join(process.env.LOCALAPPDATA ?? join(homedir(), 'AppData', 'Local'), app)
29
+ default:
30
+ return join(process.env.XDG_DATA_HOME ?? join(homedir(), '.local', 'share'), app)
31
+ }
32
+ }
33
+ ```
34
+
35
+ Contents: `app.db` (+ WAL/SHM files), `config.json`, `logs/` (optional),
36
+ [If FileStorage] `files/`. Rules:
37
+
38
+ - Created on first run with `0700` permissions.
39
+ - The package installation directory is read-only at runtime (global npm installs may not
40
+ be writable) — NEVER write anything next to the installed code.
41
+
42
+ ## 2. config.json
43
+
44
+ Zod-validated on load; unknown keys rejected (`.strict()`). Absent file = all defaults.
45
+
46
+ ```ts
47
+ import { readFileSync, existsSync } from 'node:fs'
48
+ import { join } from 'node:path'
49
+ import { z } from 'zod'
50
+
51
+ export const configSchema = z
52
+ .object({
53
+ port: z.number().int().min(1).max(65535).optional(),
54
+ host: z.string().optional(),
55
+ // [If HttpIntegration] apiBaseUrl: z.string().url().optional(),
56
+ // ...one key per config-driven setting discovered in the PRD
57
+ })
58
+ .strict()
59
+
60
+ export type AppConfig = z.infer<typeof configSchema>
61
+
62
+ export function loadConfig(dataDir: string): AppConfig {
63
+ const file = join(dataDir, 'config.json')
64
+ if (!existsSync(file)) return {}
65
+ return configSchema.parse(JSON.parse(readFileSync(file, 'utf8')))
66
+ }
67
+ ```
68
+
69
+ ## 3. Database connection factory
70
+
71
+ No module-level singletons bound to `process.env` — the factory takes the resolved
72
+ data-dir path (or `:memory:`) so tests can inject in-memory databases. The three pragmas
73
+ are mandatory:
74
+
75
+ ```ts
76
+ import Database from 'better-sqlite3'
77
+ import { drizzle } from 'drizzle-orm/better-sqlite3'
78
+ import { migrate } from 'drizzle-orm/better-sqlite3/migrator'
79
+ import { join, dirname } from 'node:path'
80
+ import { fileURLToPath } from 'node:url'
81
+ import * as schema from './schema.js'
82
+
83
+ export type Db = ReturnType<typeof openDatabase>
84
+
85
+ export function openDatabase(dataDirOrMemory: string) {
86
+ const path =
87
+ dataDirOrMemory === ':memory:' ? ':memory:' : join(dataDirOrMemory, 'app.db')
88
+ const sqlite = new Database(path)
89
+ sqlite.pragma('journal_mode = WAL')
90
+ sqlite.pragma('foreign_keys = ON')
91
+ sqlite.pragma('busy_timeout = 5000')
92
+ return drizzle(sqlite, { schema })
93
+ }
94
+
95
+ export function runMigrations(db: Db): void {
96
+ // In the published package, drizzle/ sits next to dist/ — resolve relative to the
97
+ // bundle, never relative to process.cwd().
98
+ const migrationsFolder = join(dirname(fileURLToPath(import.meta.url)), '..', 'drizzle')
99
+ migrate(db, { migrationsFolder })
100
+ }
101
+ ```
102
+
103
+ Migrations run automatically on every `start` before the server binds. Idempotent; no
104
+ separate migrate command for end users. Migration SQL files are generated by
105
+ `drizzle-kit generate`, committed in `server/drizzle/`, and shipped in the package —
106
+ never hand-edited after commit.
107
+
108
+ ## 4. Hono app factory
109
+
110
+ One Hono app serves everything. Middleware order is fixed:
111
+ **request-id → logger → session resolution → route guards → routes.**
112
+
113
+ ```ts
114
+ import { Hono } from 'hono'
115
+ import { requestId } from 'hono/request-id'
116
+ import { secureHeaders } from 'hono/secure-headers'
117
+ import { serveStatic } from '@hono/node-server/serve-static'
118
+ import { join, dirname } from 'node:path'
119
+ import { fileURLToPath } from 'node:url'
120
+ import type { Db } from './db/index.js'
121
+ import { requestLogger } from './lib/logger.js'
122
+ import { sessionMiddleware, forcedChangeGuard } from './auth/middleware.js'
123
+ import { authRoutes } from './features/auth/routes.js'
124
+ import { userRoutes } from './features/users/routes.js'
125
+ // ...one import per module feature
126
+
127
+ export interface AppDeps {
128
+ db: Db
129
+ dataDir: string
130
+ }
131
+
132
+ export function createApp({ db, dataDir }: AppDeps) {
133
+ const app = new Hono<{ Variables: { db: Db; user: SessionUser | null } }>()
134
+ .use('*', requestId())
135
+ .use('*', requestLogger())
136
+ .use('*', secureHeaders())
137
+ .use('*', async (c, next) => {
138
+ c.set('db', db)
139
+ await next()
140
+ })
141
+ .use('/api/*', sessionMiddleware())
142
+ .use('/api/*', forcedChangeGuard())
143
+
144
+ const api = app
145
+ .route('/api/auth', authRoutes)
146
+ .route('/api/users', userRoutes)
147
+ // .route('/api/{{module}}', {{module}}Routes)
148
+ .get('/api/health', (c) =>
149
+ c.json({ status: 'ok', version: APP_VERSION, uptimeSeconds: process.uptime() }),
150
+ )
151
+
152
+ const staticRoot = join(dirname(fileURLToPath(import.meta.url)), '..', 'static')
153
+ app.use('*', serveStatic({ root: staticRoot }))
154
+ app.get('*', serveStatic({ root: staticRoot, rewriteRequestPath: () => '/index.html' }))
155
+
156
+ return api
157
+ }
158
+
159
+ export type AppType = ReturnType<typeof createApp>
160
+ ```
161
+
162
+ Rules:
163
+ - `/api/*` routes are mounted before `serveStatic`; the SPA fallback rewrites unknown
164
+ non-API GETs to `index.html` for client-side routing.
165
+ - Security headers on ALL responses via `hono/secure-headers`.
166
+ - **CORS is NOT enabled** — the UI is same-origin by construction. Never add permissive
167
+ CORS.
168
+
169
+ ## 5. Typed API contract (hono/client RPC)
170
+
171
+ Routes are defined with `@hono/zod-validator`; the route tree's type (`AppType`) is
172
+ exported so `web/` consumes a fully typed client. The API contract is compiler-enforced
173
+ end to end — no OpenAPI codegen step.
174
+
175
+ ```ts
176
+ // packages/web/src/lib/api.ts
177
+ import { hc } from 'hono/client'
178
+ import type { AppType } from '@{{PACKAGE_NAME}}/server/app'
179
+
180
+ export const api = hc<AppType>('/', {
181
+ fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
182
+ const res = await fetch(input, { ...init, credentials: 'same-origin' })
183
+ if (res.status === 403) {
184
+ const body = await res.clone().json().catch(() => null)
185
+ if (body?.code === 'PASSWORD_CHANGE_REQUIRED') {
186
+ window.location.assign('/force-change-password')
187
+ }
188
+ }
189
+ return res
190
+ },
191
+ })
192
+ ```
193
+
194
+ Route definition pattern (per feature):
195
+
196
+ ```ts
197
+ import { Hono } from 'hono'
198
+ import { zValidator } from '@hono/zod-validator'
199
+ import { createItemSchema, listQuerySchema } from '@{{PACKAGE_NAME}}/core/schemas/{{domain}}'
200
+ import { requireRole } from '../../auth/middleware.js'
201
+ import * as service from './service.js'
202
+
203
+ export const {{module}}Routes = new Hono<AppEnv>()
204
+ .get('/', zValidator('query', listQuerySchema), (c) =>
205
+ c.json(service.list(c.var.db, c.req.valid('query'))),
206
+ )
207
+ .post('/', requireRole('admin'), zValidator('json', createItemSchema), (c) =>
208
+ c.json(service.create(c.var.db, c.req.valid('json')), 201),
209
+ )
210
+ ```
211
+
212
+ ## 6. Structured logger
213
+
214
+ No logging framework — a small JSON-lines logger in `server/src/lib/logger.ts`,
215
+ picocolors-highlighted only when stdout is a TTY. The one-time start status block is the
216
+ sole non-structured output; everything after it goes through the logger.
217
+
218
+ ```ts
219
+ import pc from 'picocolors'
220
+
221
+ type Level = 'info' | 'warn' | 'error'
222
+
223
+ export function log(level: Level, message: string, fields: Record<string, unknown> = {}): void {
224
+ const entry = { time: new Date().toISOString(), level, message, ...fields }
225
+ const line = JSON.stringify(entry)
226
+ if (!process.stdout.isTTY) {
227
+ process.stdout.write(`${line}\n`)
228
+ return
229
+ }
230
+ const color = level === 'error' ? pc.red : level === 'warn' ? pc.yellow : pc.dim
231
+ process.stdout.write(`${color(line)}\n`)
232
+ }
233
+
234
+ export function requestLogger() {
235
+ return async (c: HonoContext, next: () => Promise<void>) => {
236
+ const started = performance.now()
237
+ await next()
238
+ log('info', 'request', {
239
+ requestId: c.var.requestId,
240
+ method: c.req.method,
241
+ path: c.req.path,
242
+ status: c.res.status,
243
+ durationMs: Math.round(performance.now() - started),
244
+ })
245
+ }
246
+ }
247
+ ```
@@ -0,0 +1,401 @@
1
+ # Specification Template — Self-Hosted Node.js CLI Web Application
2
+
3
+ This is the authoritative template for the generated specification. The specification is
4
+ split into **two types of files**:
5
+
6
+ 1. **`SPECIFICATION.md`** (root) — Table of Contents, monorepo + shared infrastructure,
7
+ CLI contract, data directory, database, server composition, bootstrap, auth baseline,
8
+ SPA shell, testing, packaging. Generated once per application.
9
+ 2. **`<module-name>/SPEC.md`** (per-module) — Self-contained module blueprint spanning
10
+ the server feature and the SPA feature. Generated once per business module from
11
+ PRD.md, PLUS the mandatory `user-management/SPEC.md`.
12
+
13
+ ```
14
+ specification/
15
+ ├── SPECIFICATION.md
16
+ ├── user-management/
17
+ │ └── SPEC.md
18
+ ├── inventory/
19
+ │ └── SPEC.md
20
+ └── ...
21
+ ```
22
+
23
+ Placeholders use `{{VARIABLE}}` syntax and must be replaced with actual values.
24
+
25
+ ---
26
+
27
+ # Part A: Root SPECIFICATION.md
28
+
29
+ ---
30
+
31
+ ## Table of Contents
32
+
33
+ Generate a TOC with anchor links. Include a **Modules** section linking to each module's
34
+ `SPEC.md` (user-management first):
35
+
36
+ ```markdown
37
+ ## Table of Contents
38
+
39
+ ### Shared Infrastructure
40
+ - [1. Project Overview](#1-project-overview)
41
+ - [2. Monorepo & Workspace Configuration](#2-monorepo--workspace-configuration)
42
+ - ...
43
+
44
+ ### Modules
45
+ - [User Management (mandatory)](user-management/SPEC.md)
46
+ - [Inventory](inventory/SPEC.md)
47
+ - ...
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Section 1: Project Overview
53
+
54
+ ```
55
+ # {{APPLICATION_NAME}} — Technical Specification
56
+
57
+ ## 1. Project Overview
58
+
59
+ **Application Name**: {{APPLICATION_NAME}}
60
+ **Package / Binary**: {{PACKAGE_NAME}} (npm package name AND executable command)
61
+ **Install**: npm install -g {{PACKAGE_NAME}}
62
+ **Start**: {{PACKAGE_NAME}} start → http://<LAN-IP>:3000
63
+ **Node.js Version**: 22 LTS (engines.node ">=22")
64
+ **Description**: {{APP_DESCRIPTION}}
65
+ **Versions Covered**: v1.0.0 — v{{LATEST_VERSION}}
66
+
67
+ ### Architecture Model
68
+ Single-process, local-first. One Node process serves the REST API (Hono) and the
69
+ embedded pre-built React SPA. All state lives in the per-user data directory. There is
70
+ no hosted backend, no database server, no Docker.
71
+
72
+ ### Optional Components (Auto-Determined)
73
+ **DataGrid**: {{yes|no}}
74
+ **Charts**: {{yes|no}}
75
+ **DatePickers**: {{yes|no}}
76
+ **RichText**: {{yes|no}}
77
+ **FileStorage**: {{yes|no}}
78
+ **InProcessJobs**: {{yes|no}}
79
+ **HttpIntegration**: {{yes|no}}
80
+ **ExtraCommands**: {{list or none}}
81
+
82
+ ### Technology Stack
83
+ (Render the core stack table from SKILL.md, plus selected optional versions)
84
+
85
+ ### CLI Commands
86
+ | Command | Description | Version |
87
+ |---------------|------------------------------------------------|---------|
88
+ | start | Start the web application (foreground) | v1.0.0 |
89
+ | status | Show whether an instance is reachable | v1.0.0 |
90
+ | reset-admin | Regenerate the admin password offline | v1.0.0 |
91
+ | {{extra}} | {{description}} | {{ver}} |
92
+
93
+ ### User Roles
94
+ | Role | Source (mockup folder) | Capabilities summary |
95
+ |-------|------------------------|----------------------|
96
+ | admin | mockup/admin/ | Full access + user management |
97
+ | user | mockup/user/ | {{...}} |
98
+
99
+ ### Module Index
100
+ | Module | Spec File | Tables | SPA Routes |
101
+ |--------|-----------|--------|------------|
102
+ | User Management (mandatory) | [user-management/SPEC.md](user-management/SPEC.md) | users, sessions | /login, /force-change-password, /users, /settings |
103
+ | {{Module}} | [{{module}}/SPEC.md]({{module}}/SPEC.md) | {{tables}} | {{routes}} |
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Section 2: Monorepo & Workspace Configuration
109
+
110
+ Render the full monorepo tree (from SKILL.md, with actual feature/module names
111
+ substituted), then complete copy-pasteable config files:
112
+
113
+ - `pnpm-workspace.yaml` (`packages: ["packages/*"]`)
114
+ - Root `package.json` with the workspace scripts — exactly these:
115
+
116
+ ```json
117
+ {
118
+ "name": "{{PACKAGE_NAME}}-workspace",
119
+ "private": true,
120
+ "version": "{{VERSION}}",
121
+ "engines": { "node": ">=22" },
122
+ "packageManager": "pnpm@9.15.0",
123
+ "scripts": {
124
+ "dev": "pnpm --parallel --filter server --filter web dev",
125
+ "build": "pnpm --filter core --filter server --filter web --filter cli build",
126
+ "check": "tsc -b && biome check .",
127
+ "fix": "biome check --write .",
128
+ "test": "vitest run",
129
+ "test:e2e": "playwright test",
130
+ "smoke": "node packages/cli/dist/index.js --version && node scripts/smoke-start.mjs",
131
+ "verify": "pnpm check && pnpm test && pnpm build && pnpm smoke"
132
+ }
133
+ }
134
+ ```
135
+
136
+ - `biome.json` (formatter + linter, recommended rules, 100-char line width)
137
+ - Root `tsconfig.json` (composite project references: core → server → web → cli) and each
138
+ package's `tsconfig.json` with `"strict": true`
139
+ - `packages/core/package.json`, `packages/server/package.json`,
140
+ `packages/web/package.json` (all `"private": true`)
141
+
142
+ State the structural rules: feature-folder colocation, no barrel files, <300 lines/file,
143
+ Zod at every boundary, `any` forbidden, types via `z.infer<>`.
144
+
145
+ ---
146
+
147
+ ## Section 3: Published CLI Package & Build Pipeline
148
+
149
+ Read `references/cli-packaging-patterns.md`. Must include, copy-pasteable:
150
+
151
+ - `packages/cli/package.json` — `name: {{PACKAGE_NAME}}`, `bin`, `files: ["dist",
152
+ "static", "drizzle"]`, `engines`, `better-sqlite3` as the ONLY runtime dependency,
153
+ `prepublishOnly: "pnpm -w verify"`
154
+ - `packages/cli/tsup.config.ts` — entry `src/index.ts`, `format: ["esm"]`, shebang
155
+ preserved, `external: ["better-sqlite3"]`
156
+ - The three-step publish pipeline (bundle → vite build + copy to `static/` → copy
157
+ `drizzle/`) as npm scripts
158
+ - Install-weight budget note: tarball SHOULD stay under 5 MB excluding better-sqlite3;
159
+ new runtime dependencies require explicit human approval
160
+ - Local install check: `npm pack` → `npm i -g ./<tarball>` → smoke sequence
161
+
162
+ ### Section 3a: Application Version Configuration
163
+
164
+ The `packages/cli/package.json` `version` field MUST be set to the version value derived
165
+ from the version argument provided during skill invocation (e.g., `1.0.3`). If multiple
166
+ versions were provided, use the highest one.
167
+
168
+ - `{{PACKAGE_NAME}} --version` prints it (commander `.version()` fed from the bundled
169
+ package.json)
170
+ - The `start` status block prints it
171
+ - The SPA footer renders `v{{VERSION}}` (served from a `/api/system/info` route — the SPA
172
+ must not hardcode it)
173
+
174
+ ---
175
+
176
+ ## Section 4: CLI Contract
177
+
178
+ Read `references/cli-packaging-patterns.md`. Must include:
179
+
180
+ - The full command surface with flags:
181
+ ```
182
+ {{PACKAGE_NAME}} start [--port <n>] [--host <addr>] [--data-dir <path>]
183
+ {{PACKAGE_NAME}} status
184
+ {{PACKAGE_NAME}} reset-admin
185
+ {{PACKAGE_NAME}} --version | --help
186
+ ```
187
+ - `src/index.ts` (shebang + commander program) — complete sample
188
+ - `commands/start.ts` — option resolution order (flag → `APP_PORT`/`APP_HOST`/
189
+ `APP_DATA_DIR` env → config.json → default 3000 / 0.0.0.0), port-in-use failure message
190
+ naming `--port`, LAN IP detection, the single status block, graceful shutdown closing
191
+ the SQLite handle — complete sample
192
+ - `commands/status.ts` and `commands/reset-admin.ts` — complete samples
193
+ - Explicit statements: foreground only, NO daemon/forking logic; handlers are thin
194
+ (parse → Zod → delegate to server/core)
195
+ - [If ExtraCommands] one subsection per extra command with traceability IDs
196
+
197
+ ---
198
+
199
+ ## Section 5: Data Directory & Configuration
200
+
201
+ Read `references/server-patterns.md`. Must include:
202
+
203
+ - Per-platform resolution table (Linux `~/.local/share/{{PACKAGE_NAME}}/`, macOS
204
+ `~/Library/Application Support/{{PACKAGE_NAME}}/`, Windows
205
+ `%LOCALAPPDATA%/{{PACKAGE_NAME}}/`) and the resolver sample (manual or `env-paths`)
206
+ - Contents: `app.db` (+ WAL/SHM), `config.json`, `logs/` (optional),
207
+ [If FileStorage] `files/`
208
+ - Creation on first run with `0700` permissions; install dir treated read-only
209
+ - `config.json` Zod schema (unknown keys rejected) with every key, type, and default —
210
+ complete sample
211
+ - Auto-migration on every start before the server binds, against the shipped `drizzle/`
212
+ folder
213
+
214
+ ---
215
+
216
+ ## Section 6: Database Layer
217
+
218
+ Must include, with complete samples:
219
+
220
+ - `server/src/db/schema.ts` — Drizzle definitions for `users` + `sessions` (from
221
+ `references/auth-patterns.md`) PLUS every module table from the model files,
222
+ field-for-field
223
+ - `server/src/db/index.ts` — connection factory taking the data-dir path (or `:memory:`),
224
+ mandatory pragmas: WAL, `foreign_keys = ON`, `busy_timeout = 5000`; no module-level
225
+ singletons
226
+ - `drizzle.config.ts` and the `db:generate` workflow; migrations committed in
227
+ `server/drizzle/` and shipped in the published package
228
+
229
+ ---
230
+
231
+ ## Section 7: Server Composition
232
+
233
+ Read `references/server-patterns.md`. Must include:
234
+
235
+ - `server/src/app.ts` app factory — complete sample showing middleware order
236
+ (request-id → logger → session resolution → route guards → routes), `/api/*` route
237
+ mounting, `secure-headers`, `serveStatic` + SPA fallback
238
+ - The exported `AppType` and the `hono/client` consumption pattern
239
+ - Health endpoint (`GET /api/health`) used by `status` and the smoke test
240
+ - Statement: CORS is NOT enabled; never add it
241
+ - `server/src/lib/logger.ts` — structured JSON-line logger, picocolors-highlighted when
242
+ TTY — complete sample
243
+
244
+ ---
245
+
246
+ ## Section 8: First-Run Bootstrap
247
+
248
+ Read `references/auth-patterns.md`. Must include `server/src/db/bootstrap.ts` complete
249
+ sample: users-table-empty check → create `admin` (role `admin`,
250
+ `must_change_password = true`) with a cryptographically random 16-character password
251
+ (base58/alphanumeric, no ambiguous characters) → return credentials for one-time printing
252
+ inside the start status block. Plaintext never written to file or log; no-op once any
253
+ user exists (verified by test).
254
+
255
+ ---
256
+
257
+ ## Section 9: Authentication & User Lifecycle
258
+
259
+ Read `references/auth-patterns.md`. Must include, with complete samples:
260
+
261
+ - scrypt hash/verify (`node:crypto`, N=2^15, r=8, p=1, `salt:hash`, `timingSafeEqual`)
262
+ - Password policy Zod schema in `core/` (min 10 chars, reject username-as-password, no
263
+ composition rules) shared by UI and API
264
+ - Session issue/resolve/revoke: 32-byte random token, SHA-256 hash stored, sliding
265
+ expiry, 30-day absolute cap; cookie `httpOnly` `SameSite=Lax` `Path=/`, `Secure` only
266
+ over HTTPS
267
+ - In-memory login rate limiter (fixed window, 10 / 15 min per username+IP)
268
+ - Forced-change middleware returning `403 PASSWORD_CHANGE_REQUIRED` on every route except
269
+ login / change-password / logout
270
+ - The user management flow table (create / forced change / change / admin reset /
271
+ delete with last-admin invariant) and the MUST-NOT list (no email, registration,
272
+ OAuth, JWT)
273
+
274
+ ---
275
+
276
+ ## Section 10: Web SPA Shell
277
+
278
+ Must include:
279
+
280
+ - `packages/web/vite.config.ts` (dev proxy to the server port; build output consumed by
281
+ the publish pipeline), Tailwind v4 CSS-first setup (`@import "tailwindcss"` + `@theme`
282
+ tokens extracted from the mockups/design system), vendored shadcn/ui conventions
283
+ - `web/src/lib/api.ts` — typed `hono/client` RPC client with the 403
284
+ `PASSWORD_CHANGE_REQUIRED` interceptor hard-redirecting to `/force-change-password` —
285
+ complete sample
286
+ - Router setup with the mandatory routes (`/login`, `/force-change-password`, `/users`,
287
+ `/settings`) plus per-module routes; role-guarded navigation derived from mockups
288
+ - Shared layout (sidebar + topbar + footer rendering `v{{VERSION}}` from
289
+ `/api/system/info`)
290
+
291
+ ---
292
+
293
+ ## Section 11: Testing Strategy
294
+
295
+ Read `references/testing-patterns.md`. Must include the Vitest setup (`:memory:` SQLite
296
+ via the connection factory with real migrations — never mock the DB), the mandatory
297
+ coverage list (forced-change gating on every guarded route, last-admin invariant, session
298
+ revocation on password change, rate limiting, bootstrap no-op on second start), the
299
+ `scripts/smoke-start.mjs` complete sample, and the Playwright E2E scenario (first-run
300
+ login with printed credentials → forced change → create second user → second user's
301
+ forced change → password change from settings).
302
+
303
+ ---
304
+
305
+ ## Section 12: Packaging & Distribution
306
+
307
+ npm-only distribution: `files` whitelist, `engines`, `bin`, `prepublishOnly` runs
308
+ `pnpm verify`, semantic versioning guidance, the `npm pack` → global-install →
309
+ smoke-sequence pre-publish check, and the note that daemonization/TLS are the operator's
310
+ concern (systemd/pm2/reverse proxy examples in prose, never in code).
311
+
312
+ ---
313
+
314
+ # Part B: Per-Module `<module-name>/SPEC.md`
315
+
316
+ Every module file is **self-contained** — a coding agent implements it independently
317
+ after the shared infrastructure exists. `user-management/SPEC.md` is always generated
318
+ and follows this same template with the auth blueprint as its content.
319
+
320
+ ## Template
321
+
322
+ ```
323
+ # {{MODULE_NAME}} — Module Specification
324
+
325
+ > Part of [{{APPLICATION_NAME}} Technical Specification](../SPECIFICATION.md).
326
+ > Implement after the shared infrastructure (root spec sections 2–10) is in place.
327
+
328
+ ## 1. Traceability
329
+
330
+ ### User Stories
331
+ | ID | Version | Summary | Implemented By |
332
+ |----|---------|---------|----------------|
333
+ | {{USXX00001}} | [v1.0.0] | {{summary}} | {{routes.ts handler / page component}} |
334
+
335
+ ### Non-Functional Requirements
336
+ | ID | Version | Requirement | Technical Decision |
337
+ |----|---------|-------------|--------------------|
338
+
339
+ ### Constraints
340
+ | ID | Version | Constraint | Enforcement Point |
341
+ |----|---------|------------|-------------------|
342
+
343
+ ### Mockup Screens
344
+ | Screen | Role | SPA Route | Page Component |
345
+ |--------|------|-----------|----------------|
346
+
347
+ ### Removed / Replaced
348
+ | Removed ID | Removed In | Replaced By | Reason |
349
+ |-----------|------------|-------------|--------|
350
+
351
+ ## 2. Data Model (Drizzle)
352
+ The module's tables in server/src/db/schema.ts — field-for-field from the model files,
353
+ with relations and the generated migration filename.
354
+
355
+ ## 3. Shared Schemas (packages/core)
356
+ core/src/schemas/{{domain}}.ts — Zod schemas for entities, create/update inputs, and
357
+ query params; exported types via z.infer<>. Complete sample.
358
+
359
+ ## 4. Service (packages/server)
360
+ features/{{module}}/service.ts — pure functions taking the db handle; business rules
361
+ from constraints as explicit invariants. No HTTP concerns, no terminal I/O.
362
+ Complete sample.
363
+
364
+ ## 5. Routes (packages/server)
365
+ features/{{module}}/routes.ts — Hono sub-app with @hono/zod-validator on every body/
366
+ query/param, role guards, and typed responses; mounted in app.ts under /api/{{module}}.
367
+ Complete sample. Route table: method, path, guard, request schema, response type,
368
+ story IDs.
369
+
370
+ ## 6. SPA Feature (packages/web)
371
+ - Page components under web/src/routes/ — one per mockup screen, shadcn/ui components
372
+ matching the mockup layout ([If DataGrid] shadcn Data Table / TanStack Table;
373
+ [If DatePickers] react-day-picker; [If RichText] Tiptap)
374
+ - Forms with the shared core/ Zod schemas
375
+ - Typed data access via the hono/client RPC client (no hand-written fetch paths)
376
+ - Route definitions + role-guarded navigation entries
377
+ Complete samples for every component.
378
+
379
+ ## 7. Tests
380
+ - Vitest: service tests + route tests over :memory: with real migrations; every
381
+ constraint invariant has a test
382
+ - Playwright: the module's user-visible flows appended to the E2E suite
383
+ ```
384
+
385
+ ## Special case: `user-management/SPEC.md`
386
+
387
+ Same template; its content comes from `references/auth-patterns.md`:
388
+
389
+ - Tables: `users`, `sessions` (Section 2)
390
+ - Schemas: password policy, login input, user create/update (Section 3)
391
+ - Service: bootstrap, hashing, session lifecycle, user CRUD with last-admin invariant
392
+ (Section 4)
393
+ - Routes: `POST /api/auth/login`, `POST /api/auth/logout`,
394
+ `POST /api/auth/change-password`, `GET /api/auth/me`, `GET/POST/PATCH/DELETE
395
+ /api/users...` with admin guards (Section 5)
396
+ - SPA: `/login`, `/force-change-password`, `/users`, `/settings` pages (Section 6)
397
+ - Tests: the mandatory security coverage list (Section 7)
398
+
399
+ When PRD.md defines its own auth/user stories, merge their IDs into this file's
400
+ traceability tables. PRD phrasing never weakens the security invariants — flag conflicts
401
+ to the user instead.