@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,1237 @@
1
+ # Specification Template — React SPA with Tailwind CSS
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, shared infrastructure, and all
7
+ application-level sections. Generated once per application.
8
+ 2. **`<module>/SPEC.md`** (per-module) — Self-contained module blueprint.
9
+ Generated once per module from PRD.md.
10
+
11
+ ```
12
+ spec/
13
+ ├── SPECIFICATION.md
14
+ ├── hero-section/
15
+ │ └── SPEC.md
16
+ ├── product-service/
17
+ │ └── SPEC.md
18
+ └── ...
19
+ ```
20
+
21
+ Placeholders use `{{VARIABLE}}` syntax and must be replaced with actual values gathered
22
+ from context files.
23
+
24
+ Sections marked **[CONDITIONAL]** should only be included when the corresponding
25
+ integration is selected.
26
+
27
+ **CRITICAL: Sample code requirement.** Every component in the spec MUST include a
28
+ complete, continuous code sample in a fenced code block (TypeScript, TSX, or JSON as
29
+ appropriate). The code must be self-explanatory and directly usable as a reference for
30
+ a coding agent. Do not describe components with bullet points alone — always accompany
31
+ descriptions with full code.
32
+
33
+ ---
34
+
35
+ # Part A: Root SPECIFICATION.md
36
+
37
+ ---
38
+
39
+ ## Table of Contents
40
+
41
+ Generate a TOC with clickable Markdown anchor links to every H2 and H3 section.
42
+ Additionally, include a **Modules** section in the TOC that links to each module's
43
+ `SPEC.md` file:
44
+
45
+ ```markdown
46
+ ## Table of Contents
47
+
48
+ ### Shared Infrastructure
49
+ - [1. Project Overview](#1-project-overview)
50
+ - [2. Package Configuration](#2-package-configuration)
51
+ - ...all shared sections...
52
+
53
+ ### Modules
54
+ - [Hero Section](hero-section/SPEC.md)
55
+ - [Product and Service](product-service/SPEC.md)
56
+ - [Blog](blog/SPEC.md)
57
+ - ...(one link per module)...
58
+ ```
59
+
60
+ Only include conditional sections that apply based on determined selections.
61
+
62
+ ---
63
+
64
+ ## Section 1: Project Overview
65
+
66
+ ```
67
+ # {{APPLICATION_NAME}} — Technical Specification
68
+
69
+ ## 1. Project Overview
70
+
71
+ **Application Name**: {{APPLICATION_NAME}}
72
+ **Project Slug**: {{PROJECT_SLUG}}
73
+ **App Title**: {{APP_TITLE}}
74
+ **Framework**: React SPA (Tailwind CSS)
75
+ **Description**: {{APP_DESCRIPTION}}
76
+ **Versions Covered**: v1.0.0 — v{{LATEST_VERSION}}
77
+
78
+ ### Optional Components (Auto-Determined)
79
+ **Backend API Base URL**: {{API_BASE_URL}}
80
+ **Authentication**: {{AUTH_TYPE}}
81
+ **DataGrid**: {{DATAGRID}} (TanStack Table)
82
+ **Charts**: {{CHARTS}} (Recharts)
83
+ **DatePickers**: {{DATE_PICKERS}} (react-day-picker)
84
+ **WebSocket**: {{WEBSOCKET}}
85
+ **i18n**: {{I18N}}
86
+ **RichText**: {{RICH_TEXT}} (Tiptap)
87
+
88
+ ### Technology Stack
89
+ (Render the core stack version table from SKILL.md, plus selected optional integration versions)
90
+
91
+ ### User Roles
92
+ (List each user role extracted from mockup role folders, with role constant and access scope.)
93
+
94
+ | Role | Description | Constant | Accessible Modules |
95
+ |------|-------------|----------|-------------------|
96
+ | Administrator | Full system access | `ADMIN` | All modules |
97
+ | Editor | Content management | `EDITOR` | Hero Section, Blog, ... |
98
+
99
+ ### Modules
100
+ (List each module from PRD.md, with type and link to its SPEC.md.)
101
+
102
+ | Module | Type | Stories | Versions | Spec |
103
+ |--------|------|---------|----------|------|
104
+ | Hero Section | Business | 3 | 1.0.0, 1.0.4 | [SPEC](hero-section/SPEC.md) |
105
+ | Blog | Business | 5 | 1.0.0 | [SPEC](blog/SPEC.md) |
106
+
107
+ ### Input Sources
108
+ - CLAUDE.md: {{path}}
109
+ - PRD.md: {{path}}
110
+ - Module Model: {{path to MODEL.md}}
111
+ - Mockup Screens: {{path to MOCKUP.html}}
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Section 2: Package Configuration
117
+
118
+ ### 2.1 package.json
119
+
120
+ Generate a complete `package.json` inside a code block. Include all core and
121
+ conditional dependencies based on the determined selections.
122
+
123
+ ```json
124
+ {
125
+ "name": "{{PROJECT_SLUG}}",
126
+ "version": "1.0.0",
127
+ "private": true,
128
+ "type": "module",
129
+ "scripts": {
130
+ "dev": "vite",
131
+ "build": "tsc -b && vite build",
132
+ "preview": "vite preview",
133
+ "lint": "eslint .",
134
+ "type-check": "tsc --noEmit"
135
+ },
136
+ "dependencies": {
137
+ "react": "^19.0.0",
138
+ "react-dom": "^19.0.0",
139
+ "react-router-dom": "^7.0.0",
140
+ "@tanstack/react-query": "^5.0.0",
141
+ "zustand": "^5.0.0",
142
+ "react-hook-form": "^7.0.0",
143
+ "@hookform/resolvers": "^3.0.0",
144
+ "zod": "^3.0.0",
145
+ "axios": "^1.0.0",
146
+ "@headlessui/react": "^2.0.0",
147
+ "@heroicons/react": "^2.0.0",
148
+ "clsx": "^2.0.0",
149
+ "tailwind-merge": "^2.0.0",
150
+ "class-variance-authority": "^0.7.0"
151
+ },
152
+ "devDependencies": {
153
+ "typescript": "^5.0.0",
154
+ "@types/react": "^19.0.0",
155
+ "@types/react-dom": "^19.0.0",
156
+ "vite": "^6.0.0",
157
+ "@vitejs/plugin-react": "^4.0.0",
158
+ "tailwindcss": "^3.4.0",
159
+ "postcss": "^8.4.0",
160
+ "autoprefixer": "^10.4.0",
161
+ "@tailwindcss/forms": "^0.5.0",
162
+ "@tanstack/react-query-devtools": "^5.0.0",
163
+ "eslint": "^9.0.0",
164
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
165
+ "@typescript-eslint/parser": "^8.0.0"
166
+ }
167
+ }
168
+ ```
169
+
170
+ Include conditional dependencies as annotated comments in the final output:
171
+
172
+ ```jsonc
173
+ // [If Auth = Keycloak or OIDC]
174
+ // "oidc-client-ts": "^3.1.0",
175
+ // "react-oidc-context": "^3.2.0"
176
+ // [If DataGrid = yes]
177
+ // "@tanstack/react-table": "^8.0.0"
178
+ // [If Charts = yes]
179
+ // "recharts": "^2.0.0"
180
+ // [If DatePickers = yes]
181
+ // "react-day-picker": "^9.0.0",
182
+ // "date-fns": "^4.0.0"
183
+ // [If WebSocket = yes]
184
+ // "socket.io-client": "^4.0.0"
185
+ // [If i18n = yes]
186
+ // "react-i18next": "^15.0.0", "i18next": "^24.0.0",
187
+ // "i18next-browser-languagedetector": "^8.0.0", "i18next-http-backend": "^3.0.0"
188
+ // [If RichText = yes]
189
+ // "@tiptap/react": "^2.0.0", "@tiptap/starter-kit": "^2.0.0",
190
+ // "@tiptap/extension-link": "^2.0.0", "@tiptap/extension-placeholder": "^2.0.0",
191
+ // "dompurify": "^3.0.0" (+ devDep "@types/dompurify", "@tailwindcss/typography")
192
+ // [If Reporting = yes]
193
+ // "xlsx": "^0.18.5", "papaparse": "^5.4.1" (+ devDep "@types/papaparse")
194
+ ```
195
+
196
+ ### 2.2 vite.config.ts
197
+
198
+ ```typescript
199
+ import { defineConfig } from 'vite';
200
+ import react from '@vitejs/plugin-react';
201
+ import path from 'path';
202
+
203
+ export default defineConfig({
204
+ plugins: [react()],
205
+ resolve: {
206
+ alias: {
207
+ '@': path.resolve(__dirname, './src'),
208
+ },
209
+ },
210
+ server: {
211
+ port: {{DEV_PORT}},
212
+ proxy: {
213
+ '/api': {
214
+ target: '{{API_BASE_URL_DEV}}',
215
+ changeOrigin: true,
216
+ rewrite: (path) => path.replace(/^\/api/, ''),
217
+ },
218
+ },
219
+ },
220
+ });
221
+ ```
222
+
223
+ > Note: Tailwind v3 is wired through PostCSS (see `postcss.config.js` in Section 3), so no
224
+ > Vite plugin is required for Tailwind itself.
225
+
226
+ ### 2.3 tsconfig.json
227
+
228
+ ```json
229
+ {
230
+ "compilerOptions": {
231
+ "target": "ES2020",
232
+ "useDefineForClassFields": true,
233
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
234
+ "module": "ESNext",
235
+ "skipLibCheck": true,
236
+ "moduleResolution": "bundler",
237
+ "allowImportingTsExtensions": true,
238
+ "isolatedModules": true,
239
+ "moduleDetection": "force",
240
+ "noEmit": true,
241
+ "jsx": "react-jsx",
242
+ "strict": true,
243
+ "noUnusedLocals": true,
244
+ "noUnusedParameters": true,
245
+ "noFallthroughCasesInSwitch": true,
246
+ "baseUrl": ".",
247
+ "paths": {
248
+ "@/*": ["./src/*"]
249
+ }
250
+ },
251
+ "include": ["src"],
252
+ "references": [{ "path": "./tsconfig.node.json" }]
253
+ }
254
+ ```
255
+
256
+ ### 2.4 Environment Variables
257
+
258
+ ```env
259
+ # .env.development
260
+ VITE_APP_TITLE={{APP_TITLE}}
261
+ VITE_APP_VERSION={{LATEST_VERSION}}
262
+ VITE_API_BASE_URL={{API_BASE_URL_DEV}}
263
+
264
+ # [If Auth = Keycloak]
265
+ VITE_KEYCLOAK_AUTHORITY=http://localhost:8180/realms/{{KEYCLOAK_REALM}}
266
+ VITE_KEYCLOAK_CLIENT_ID={{KEYCLOAK_CLIENT_ID}}
267
+ VITE_KEYCLOAK_REDIRECT_URI=http://localhost:{{DEV_PORT}}/auth/callback
268
+ VITE_KEYCLOAK_POST_LOGOUT_REDIRECT_URI=http://localhost:{{DEV_PORT}}
269
+ VITE_KEYCLOAK_SCOPE=openid profile email
270
+ ```
271
+
272
+ ```env
273
+ # .env.production
274
+ VITE_APP_TITLE={{APP_TITLE}}
275
+ VITE_APP_VERSION={{LATEST_VERSION}}
276
+ VITE_API_BASE_URL=${API_BASE_URL}
277
+
278
+ # [If Auth = Keycloak]
279
+ VITE_KEYCLOAK_AUTHORITY=${KEYCLOAK_AUTHORITY}
280
+ VITE_KEYCLOAK_CLIENT_ID=${KEYCLOAK_CLIENT_ID}
281
+ VITE_KEYCLOAK_REDIRECT_URI=${APP_URL}/auth/callback
282
+ VITE_KEYCLOAK_POST_LOGOUT_REDIRECT_URI=${APP_URL}
283
+ VITE_KEYCLOAK_SCOPE=openid profile email
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Section 3: Application Configuration
289
+
290
+ ### 3.1 .gitignore
291
+
292
+ ```gitignore
293
+ # Build output
294
+ dist/
295
+ dist-ssr/
296
+
297
+ # Dependencies
298
+ node_modules/
299
+
300
+ # IDE
301
+ .idea/
302
+ *.iml
303
+ .vscode/
304
+ *.swp
305
+ *~
306
+
307
+ # OS
308
+ .DS_Store
309
+ Thumbs.db
310
+
311
+ # Environment (never commit secrets)
312
+ .env
313
+ .env.local
314
+ .env.production
315
+ .env.*.local
316
+
317
+ # TypeScript
318
+ *.tsbuildinfo
319
+
320
+ # Logs
321
+ *.log
322
+ npm-debug.log*
323
+ yarn-debug.log*
324
+ pnpm-debug.log*
325
+
326
+ # Testing
327
+ coverage/
328
+ playwright-report/
329
+ test-results/
330
+ e2e/node_modules/
331
+ ```
332
+
333
+ ### 3.2 Environment Type Declarations
334
+
335
+ ```typescript
336
+ // src/types/global.d.ts
337
+
338
+ /// <reference types="vite/client" />
339
+
340
+ interface ImportMetaEnv {
341
+ readonly VITE_APP_TITLE: string;
342
+ readonly VITE_APP_VERSION: string;
343
+ readonly VITE_API_BASE_URL: string;
344
+ // [If Auth = Keycloak]
345
+ readonly VITE_KEYCLOAK_AUTHORITY: string;
346
+ readonly VITE_KEYCLOAK_CLIENT_ID: string;
347
+ readonly VITE_KEYCLOAK_REDIRECT_URI: string;
348
+ readonly VITE_KEYCLOAK_POST_LOGOUT_REDIRECT_URI: string;
349
+ readonly VITE_KEYCLOAK_SCOPE: string;
350
+ }
351
+
352
+ interface ImportMeta {
353
+ readonly env: ImportMetaEnv;
354
+ }
355
+ ```
356
+
357
+ ### 3.3 postcss.config.js
358
+
359
+ ```javascript
360
+ export default {
361
+ plugins: {
362
+ tailwindcss: {},
363
+ autoprefixer: {},
364
+ },
365
+ };
366
+ ```
367
+
368
+ ---
369
+
370
+ ## Section 4: Directory Structure
371
+
372
+ Generate the full `src/` directory tree. Use actual module names from PRD.md and MODEL.md.
373
+ Follow the feature-based structure from `references/routing-patterns.md`.
374
+
375
+ ```
376
+ src/
377
+ ├── main.tsx
378
+ ├── App.tsx
379
+ ├── index.css ← Tailwind directives + design-token CSS variables
380
+ ├── router/
381
+ │ └── index.tsx
382
+ ├── lib/
383
+ │ ├── api/
384
+ │ │ ├── axiosInstance.ts
385
+ │ │ └── [If Auth = Keycloak] authBridge.ts
386
+ │ ├── auth/
387
+ │ │ ├── [If Auth = Keycloak] oidcConfig.ts
388
+ │ │ ├── [If Auth = Keycloak] keycloakRoles.ts
389
+ │ │ ├── [If Auth = Keycloak] useAuthUser.ts
390
+ │ │ └── roles.ts
391
+ │ ├── utils/
392
+ │ │ ├── cn.ts ← twMerge(clsx(...)) helper
393
+ │ │ └── zodErrors.ts
394
+ │ └── queryClient.ts
395
+ ├── store/
396
+ │ ├── [If Auth = Local] auth.store.ts
397
+ │ ├── notification.store.ts
398
+ │ └── ui.store.ts
399
+ ├── shared/
400
+ │ ├── layouts/
401
+ │ │ ├── DashboardLayout.tsx
402
+ │ │ ├── PublicLayout.tsx
403
+ │ │ ├── AuthLayout.tsx
404
+ │ │ └── Footer.tsx
405
+ │ ├── components/
406
+ │ │ ├── ProtectedRoute.tsx
407
+ │ │ ├── Button.tsx
408
+ │ │ ├── Card.tsx
409
+ │ │ ├── AppTopBar.tsx
410
+ │ │ ├── AppSidebar.tsx
411
+ │ │ ├── navigationConfig.ts
412
+ │ │ ├── PageHeader.tsx
413
+ │ │ ├── DataTable.tsx
414
+ │ │ ├── Pagination.tsx
415
+ │ │ ├── ConfirmDialog.tsx
416
+ │ │ ├── StatusBadge.tsx
417
+ │ │ ├── Modal.tsx
418
+ │ │ ├── ImageUpload.tsx
419
+ │ │ ├── LoadingOverlay.tsx
420
+ │ │ ├── Spinner.tsx
421
+ │ │ ├── EmptyState.tsx
422
+ │ │ ├── ErrorBoundary.tsx
423
+ │ │ ├── NotificationProvider.tsx
424
+ │ │ └── SearchInput.tsx
425
+ │ ├── hooks/
426
+ │ │ ├── useDebounce.ts
427
+ │ │ ├── useNotification.ts
428
+ │ │ ├── useColorMode.ts
429
+ │ │ └── useConfirm.ts
430
+ │ └── form/
431
+ │ ├── TextFieldController.tsx
432
+ │ ├── TextAreaController.tsx
433
+ │ ├── SelectController.tsx ← Headless UI Listbox
434
+ │ ├── DatePickerController.tsx ← react-day-picker in a Popover
435
+ │ ├── SwitchController.tsx ← Headless UI Switch
436
+ │ ├── ComboboxController.tsx ← Headless UI Combobox
437
+ │ └── [If RichText = yes] RichTextController.tsx ← Tiptap
438
+ ├── features/
439
+ │ ├── auth/
440
+ │ │ ├── pages/
441
+ │ │ │ ├── [If Auth = Keycloak] AuthCallbackPage.tsx
442
+ │ │ │ └── [If Auth = Local] LoginPage.tsx
443
+ │ │ └── index.ts
444
+ │ ├── dashboard/
445
+ │ │ ├── pages/
446
+ │ │ │ └── DashboardPage.tsx
447
+ │ │ └── index.ts
448
+ │ ├── {{module1}}/ ← Replace with actual module names
449
+ │ │ ├── api/
450
+ │ │ │ └── {{module1}}Api.ts
451
+ │ │ ├── components/
452
+ │ │ ├── hooks/
453
+ │ │ ├── pages/
454
+ │ │ ├── {{module1}}.types.ts
455
+ │ │ ├── {{module1}}.schema.ts
456
+ │ │ └── index.ts
457
+ │ └── {{module2}}/
458
+ │ └── (same structure)
459
+ └── types/
460
+ └── global.d.ts
461
+ ```
462
+
463
+ > **Note:** `tailwind.config.js` and `postcss.config.js` live at the project root (not under
464
+ > `src/`), alongside `package.json` and `vite.config.ts`.
465
+
466
+ ---
467
+
468
+ ## Section 5: Tailwind Configuration & Design Tokens
469
+
470
+ Generate the complete Tailwind configuration using design tokens extracted from MOCKUP.html.
471
+ Reference `references/component-patterns.md` for the token setup pattern.
472
+
473
+ Include:
474
+ - `tailwind.config.js` — `darkMode: 'class'`, content globs, `theme.extend` with actual
475
+ color/font/radius/shadow tokens from the mockup, and `plugins`
476
+ - `src/index.css` — `@tailwind` directives + `:root` / `.dark` CSS custom properties
477
+ - `src/lib/utils/cn.ts` — the `cn()` helper
478
+ - Design token mapping table showing mockup CSS property → Tailwind token
479
+
480
+ ### 5.1 tailwind.config.js
481
+
482
+ ```javascript
483
+ /** @type {import('tailwindcss').Config} */
484
+ export default {
485
+ darkMode: 'class',
486
+ content: ['./index.html', './src/**/*.{ts,tsx}'],
487
+ theme: {
488
+ extend: {
489
+ colors: {
490
+ // Map to CSS variables so light/dark switch automatically (see index.css)
491
+ primary: {
492
+ DEFAULT: 'rgb(var(--color-primary) / <alpha-value>)',
493
+ dark: 'rgb(var(--color-primary-dark) / <alpha-value>)',
494
+ },
495
+ secondary: 'rgb(var(--color-secondary) / <alpha-value>)',
496
+ danger: 'rgb(var(--color-danger) / <alpha-value>)',
497
+ warning: 'rgb(var(--color-warning) / <alpha-value>)',
498
+ success: 'rgb(var(--color-success) / <alpha-value>)',
499
+ surface: 'rgb(var(--color-surface) / <alpha-value>)',
500
+ canvas: 'rgb(var(--color-canvas) / <alpha-value>)',
501
+ },
502
+ fontFamily: {
503
+ // Extract from mockup CSS font-family declaration
504
+ sans: ['{{FONT_FAMILY}}', 'system-ui', 'sans-serif'],
505
+ },
506
+ borderRadius: {
507
+ // Extract base radius from mockup (e.g., '0.5rem')
508
+ DEFAULT: '{{BORDER_RADIUS_BASE}}',
509
+ },
510
+ },
511
+ },
512
+ plugins: [
513
+ require('@tailwindcss/forms'),
514
+ // [If RichText = yes] require('@tailwindcss/typography'),
515
+ ],
516
+ };
517
+ ```
518
+
519
+ ### 5.2 src/index.css
520
+
521
+ ```css
522
+ @tailwind base;
523
+ @tailwind components;
524
+ @tailwind utilities;
525
+
526
+ /* Semantic design tokens — values extracted from MOCKUP.html.
527
+ Stored as space-separated RGB channels so Tailwind's <alpha-value> works. */
528
+ :root {
529
+ --color-primary: 34 113 177; /* e.g., #2271b1 */
530
+ --color-primary-dark: 19 94 150; /* e.g., #135e96 */
531
+ --color-secondary: 100 105 112; /* e.g., #646970 */
532
+ --color-danger: 214 54 56; /* e.g., #d63638 */
533
+ --color-warning: 219 166 23; /* e.g., #dba617 */
534
+ --color-success: 0 163 42; /* e.g., #00a32a */
535
+ --color-canvas: 240 240 241; /* page background — e.g., #f0f0f1 */
536
+ --color-surface: 255 255 255; /* card/surface background — #ffffff */
537
+ }
538
+
539
+ .dark {
540
+ --color-primary: 96 165 250;
541
+ --color-primary-dark: 59 130 246;
542
+ --color-secondary: 148 163 184;
543
+ --color-danger: 248 113 113;
544
+ --color-warning: 250 204 21;
545
+ --color-success: 74 222 128;
546
+ --color-canvas: 15 23 42; /* slate-900 */
547
+ --color-surface: 30 41 59; /* slate-800 */
548
+ }
549
+
550
+ body {
551
+ @apply bg-canvas text-slate-900 antialiased dark:text-slate-100;
552
+ }
553
+ ```
554
+
555
+ ### 5.3 cn() helper
556
+
557
+ ```typescript
558
+ // src/lib/utils/cn.ts
559
+ import { clsx, type ClassValue } from 'clsx';
560
+ import { twMerge } from 'tailwind-merge';
561
+
562
+ /**
563
+ * Merge Tailwind class names, resolving conflicts (last-wins) via tailwind-merge.
564
+ * Use this for every conditional/composed className in the application.
565
+ */
566
+ export function cn(...inputs: ClassValue[]): string {
567
+ return twMerge(clsx(inputs));
568
+ }
569
+ ```
570
+
571
+ ### 5.4 main.tsx integration
572
+
573
+ ```tsx
574
+ // src/main.tsx
575
+ import React from 'react';
576
+ import ReactDOM from 'react-dom/client';
577
+ import { QueryClientProvider } from '@tanstack/react-query';
578
+ import { queryClient } from './lib/queryClient';
579
+ import { App } from './App';
580
+ import './index.css';
581
+ // [If Auth = Keycloak]
582
+ // import { AuthProvider } from 'react-oidc-context';
583
+ // import { oidcConfig } from './lib/auth/oidcConfig';
584
+
585
+ ReactDOM.createRoot(document.getElementById('root')!).render(
586
+ <React.StrictMode>
587
+ {/* [If Auth = Keycloak] <AuthProvider {...oidcConfig}> */}
588
+ <QueryClientProvider client={queryClient}>
589
+ <App />
590
+ </QueryClientProvider>
591
+ {/* [If Auth = Keycloak] </AuthProvider> */}
592
+ </React.StrictMode>,
593
+ );
594
+ ```
595
+
596
+ ### 5.5 App.tsx integration
597
+
598
+ ```tsx
599
+ // src/App.tsx
600
+ import { useEffect } from 'react';
601
+ import { RouterProvider } from 'react-router-dom';
602
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
603
+ import { useUiStore } from './store/ui.store';
604
+ import { router } from './router';
605
+ import { NotificationProvider } from './shared/components/NotificationProvider';
606
+ import { ConfirmDialog } from './shared/components/ConfirmDialog';
607
+ // [If Auth = Keycloak]
608
+ // import { useAuth } from 'react-oidc-context';
609
+ // import { setAuthUser } from './lib/api/authBridge';
610
+
611
+ export function App() {
612
+ const themeMode = useUiStore((s) => s.themeMode);
613
+
614
+ // Sync the Tailwind `dark` class on the document root
615
+ useEffect(() => {
616
+ document.documentElement.classList.toggle('dark', themeMode === 'dark');
617
+ }, [themeMode]);
618
+
619
+ // [If Auth = Keycloak] Keep the auth bridge in sync
620
+ // const auth = useAuth();
621
+ // useEffect(() => { setAuthUser(auth.user ?? null); }, [auth.user]);
622
+
623
+ return (
624
+ <>
625
+ <RouterProvider router={router} />
626
+ <NotificationProvider />
627
+ <ConfirmDialog />
628
+ <ReactQueryDevtools initialIsOpen={false} />
629
+ </>
630
+ );
631
+ }
632
+ ```
633
+
634
+ ---
635
+
636
+ ## Section 6: Authentication Configuration [CONDITIONAL — Include only if Auth != none]
637
+
638
+ **[If Auth = Keycloak]:**
639
+ Refer to `references/security-patterns.md` for the complete content.
640
+ Must cover:
641
+ - `src/lib/auth/oidcConfig.ts` — OIDC configuration object
642
+ - `src/lib/auth/keycloakRoles.ts` — role extraction utilities
643
+ - `src/lib/auth/useAuthUser.ts` — typed auth hook
644
+ - `src/lib/auth/roles.ts` — role constants
645
+ - `src/lib/api/authBridge.ts` — bridge for Axios interceptor
646
+ - `src/shared/components/ProtectedRoute.tsx` — route guard component
647
+ - `src/features/auth/pages/AuthCallbackPage.tsx` — OIDC callback handler
648
+ - main.tsx integration with `AuthProvider`
649
+ - Axios interceptor that injects Bearer token
650
+
651
+ **[If Auth = Local]:**
652
+ Refer to `references/security-patterns.md` (Local JWT section) for the complete content.
653
+ Must cover:
654
+ - `src/store/auth.store.ts` — Zustand auth store with login/logout/token management
655
+ - `src/lib/api/axiosInstance.ts` — interceptor reads token from Zustand store
656
+ - Token refresh interceptor for 401 handling
657
+ - `src/shared/components/ProtectedRoute.tsx` — redirects to /login
658
+ - `src/features/auth/pages/LoginPage.tsx` — email/password form with RHF + Zod + Tailwind
659
+ - `src/lib/auth/roles.ts` — role constants
660
+
661
+ ---
662
+
663
+ ## Section 7: Router Configuration
664
+
665
+ Refer to `references/routing-patterns.md` for the complete route tree.
666
+ Must cover:
667
+ - `src/router/index.tsx` — complete `createBrowserRouter()` with ALL routes from PRD.md
668
+ - Lazy loading via `React.lazy()` for every page component
669
+ - `<Suspense>` with `<LoadingOverlay />` fallback
670
+ - `<ProtectedRoute>` wrappers with `requiredRoles` matching the mockup role folders
671
+ - Public routes (login, callback, 404)
672
+ - The exact module-based URL paths (e.g., `/hero-section`, NOT `/admin/hero-section`)
673
+
674
+ ---
675
+
676
+ ## Section 8: API Client Configuration
677
+
678
+ ```typescript
679
+ // src/lib/api/axiosInstance.ts
680
+ import axios from 'axios';
681
+
682
+ export const axiosInstance = axios.create({
683
+ baseURL: import.meta.env.VITE_API_BASE_URL,
684
+ timeout: 30_000,
685
+ headers: { 'Content-Type': 'application/json' },
686
+ // [If Auth = Local] withCredentials: true, // for httpOnly refresh token cookie
687
+ });
688
+
689
+ // Auth interceptor — see Section 6 for implementation
690
+ // Error interceptor — see below
691
+ axiosInstance.interceptors.response.use(
692
+ (response) => response,
693
+ (error) => {
694
+ if (axios.isAxiosError(error)) {
695
+ const status = error.response?.status;
696
+ const message =
697
+ (error.response?.data as { message?: string })?.message ??
698
+ error.message ??
699
+ 'An unexpected error occurred';
700
+
701
+ // Global error notifications for non-401 errors
702
+ // (401 handled by the auth interceptor)
703
+ if (status && status !== 401) {
704
+ // Imported lazily to avoid circular dependency with Zustand store
705
+ import('../../store/notification.store').then(({ useNotificationStore }) => {
706
+ useNotificationStore.getState().push('error', message);
707
+ });
708
+ }
709
+ }
710
+ return Promise.reject(error);
711
+ },
712
+ );
713
+ ```
714
+
715
+ ---
716
+
717
+ ## Section 9: Global State (Zustand)
718
+
719
+ Describe and provide code for:
720
+ - `src/store/notification.store.ts` — toast notification queue
721
+ - `src/store/ui.store.ts` — sidebar open/closed, theme mode (persisted)
722
+ - [If Auth = Local] `src/store/auth.store.ts` — auth state and actions
723
+
724
+ Reference `references/component-patterns.md` for the full store implementations.
725
+
726
+ ---
727
+
728
+ ## Section 10: TanStack Query Setup
729
+
730
+ ```typescript
731
+ // src/lib/queryClient.ts
732
+ // Full implementation from references/component-patterns.md
733
+ ```
734
+
735
+ Describe:
736
+ - `QueryClient` configuration (staleTime, gcTime, retry policy)
737
+ - `QueryClientProvider` in `main.tsx`
738
+ - `ReactQueryDevtools` in `App.tsx` (dev mode only)
739
+ - Query key factory pattern (object with `all`, `lists`, `list(params)`, `detail(id)`)
740
+ - Naming convention: `use{Entity}s` for list queries, `use{Entity}` for single queries,
741
+ `use{Entity}Mutations` for all CUD mutations of a feature
742
+
743
+ ---
744
+
745
+ ## Section 11: Shared Layouts
746
+
747
+ For each layout, provide:
748
+ 1. The TypeScript props interface
749
+ 2. The complete TSX component
750
+
751
+ - **DashboardLayout**: Tailwind flex layout — fixed sidebar (`AppSidebar`) + topbar
752
+ (`AppTopBar`) + scrollable `<main>` with `<Outlet>` and `<Footer>`
753
+ from `references/routing-patterns.md`
754
+ - **PublicLayout**: Minimal layout for landing/public pages
755
+ - **AuthLayout**: Centered card (`max-w-md` panel) for login/callback pages
756
+
757
+ ---
758
+
759
+ ## Section 12: Shared Components
760
+
761
+ For each shared component, provide the TypeScript props interface and complete TSX.
762
+ Reference `references/component-patterns.md` for implementations.
763
+
764
+ | Component | Purpose |
765
+ |---|---|
766
+ | `Button` | cva-based button with `variant`/`size` props (primary, outline, ghost, danger) |
767
+ | `Card` | Surface container (`bg-surface rounded shadow-sm border`) |
768
+ | `ProtectedRoute` | Auth + role guard |
769
+ | `AppTopBar` | Sticky topbar with sidebar toggle, user menu (Headless UI `Menu`), theme toggle |
770
+ | `AppSidebar` | Off-canvas/persistent sidebar with role-filtered navigation items |
771
+ | `navigationConfig.ts` | Navigation item definitions with role requirements |
772
+ | `PageHeader` | Page title + breadcrumbs + action buttons area |
773
+ | `StatusBadge` | cva-based colored badge for enum status values |
774
+ | `ConfirmDialog` + `useConfirm` | Imperative confirmation dialog (Headless UI `Dialog`) |
775
+ | `Modal` / `FormDialog` | Headless UI `Dialog` wrapper for forms |
776
+ | `LoadingOverlay` / `Spinner` | Full-page spinner overlay |
777
+ | `EmptyState` | Empty list placeholder with icon and message |
778
+ | `ErrorBoundary` | React ErrorBoundary with Tailwind fallback UI |
779
+ | `NotificationProvider` | Headless UI `Transition` toast stack renderer |
780
+ | `DataTable` | TanStack Table wrapper (or simple Tailwind table) |
781
+ | `Pagination` | Page navigation control |
782
+ | `ImageUpload` | Drag-and-drop file input with image preview |
783
+ | `SearchInput` | Debounced search text field |
784
+
785
+ ---
786
+
787
+ ## Section 13: Navigation Configuration
788
+
789
+ Generate `src/shared/components/navigationConfig.ts` with the actual navigation items
790
+ from the mockup sidebar files. For each role:
791
+ - List all nav items that role can see
792
+ - Include Heroicons imports (use appropriate icons from `@heroicons/react/24/outline`)
793
+ - Sidebar hrefs use module-based paths only (e.g., `/hero-section`, `/users`)
794
+
795
+ ---
796
+
797
+ ## Section 14: Form Infrastructure
798
+
799
+ Reference `references/component-patterns.md` for the complete RHF controller components.
800
+ Describe:
801
+ - `useForm()` + `zodResolver()` usage pattern
802
+ - All `*Controller` components with full TypeScript generics
803
+ - Form reset pattern for edit modes (`reset(data)` in `useEffect`)
804
+ - Loading state on submit button (`isSubmitting` → disabled + spinner inside `<Button>`)
805
+
806
+ ---
807
+
808
+ ## Section 15: Error Handling Strategy
809
+
810
+ Describe:
811
+ - `ErrorBoundary` component wrapping the router outlet
812
+ - Axios response interceptor for API errors (already in Section 8)
813
+ - Zod error message extraction utility
814
+ - TanStack Query `mutation.error` → displayed in form via `useEffect`
815
+
816
+ ```typescript
817
+ // src/lib/utils/zodErrors.ts
818
+
819
+ import type { ZodError } from 'zod';
820
+
821
+ /**
822
+ * Extract a flat error message from a Zod error or generic Error.
823
+ */
824
+ export function extractErrorMessage(error: unknown): string {
825
+ if (error instanceof Error) return error.message;
826
+ if (typeof error === 'string') return error;
827
+ return 'An unexpected error occurred';
828
+ }
829
+
830
+ /**
831
+ * Map Zod field errors to React Hook Form setError calls.
832
+ */
833
+ export function mapZodErrorsToForm<T extends Record<string, unknown>>(
834
+ error: ZodError,
835
+ setError: (field: keyof T, error: { message: string }) => void,
836
+ ): void {
837
+ for (const issue of error.issues) {
838
+ const field = issue.path[0] as keyof T;
839
+ if (field) {
840
+ setError(field, { message: issue.message });
841
+ }
842
+ }
843
+ }
844
+ ```
845
+
846
+ ---
847
+
848
+ ## Section 16: Notification System
849
+
850
+ Reference `references/component-patterns.md` for:
851
+ - `src/store/notification.store.ts` — full Zustand store
852
+ - `src/shared/components/NotificationProvider.tsx` — Headless UI `Transition` toast stack
853
+ - Usage: `useNotificationStore().push('success', 'Item saved.')` from any component or
854
+ mutation `onSuccess`/`onError` callback
855
+
856
+ ---
857
+
858
+ ## Section 17: Theming & Dark Mode
859
+
860
+ ```tsx
861
+ // src/shared/hooks/useColorMode.ts
862
+ import { useUiStore } from '../../store/ui.store';
863
+
864
+ /** Returns the current theme mode and a toggle action. */
865
+ export function useColorMode() {
866
+ const themeMode = useUiStore((s) => s.themeMode);
867
+ const toggleThemeMode = useUiStore((s) => s.toggleThemeMode);
868
+ return { themeMode, toggleThemeMode };
869
+ }
870
+ ```
871
+
872
+ ```tsx
873
+ // src/shared/components/ThemeToggle.tsx (theme toggle example)
874
+ import { MoonIcon, SunIcon } from '@heroicons/react/24/outline';
875
+ import { useColorMode } from '../hooks/useColorMode';
876
+
877
+ export function ThemeToggle() {
878
+ const { themeMode, toggleThemeMode } = useColorMode();
879
+
880
+ return (
881
+ <button
882
+ type="button"
883
+ onClick={toggleThemeMode}
884
+ aria-label="Toggle theme"
885
+ className="rounded p-2 text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700"
886
+ >
887
+ {themeMode === 'dark' ? (
888
+ <SunIcon className="h-5 w-5" />
889
+ ) : (
890
+ <MoonIcon className="h-5 w-5" />
891
+ )}
892
+ </button>
893
+ );
894
+ }
895
+ ```
896
+
897
+ The `dark` class is toggled on `document.documentElement` in `App.tsx` (see Section 5.5),
898
+ driven by the persisted `themeMode` value in the Zustand UI store.
899
+
900
+ ---
901
+
902
+ ## Section 18: Testing Strategy
903
+
904
+ Overview only — detailed per-feature test patterns in each module's SPEC.md.
905
+
906
+ - **Vitest + React Testing Library**: Unit tests for hooks and components
907
+ - **MSW (Mock Service Worker)**: API mocking for integration tests
908
+ - **Playwright**: E2E test scripts per CO2 workflow
909
+
910
+ ```bash
911
+ # Add to package.json devDependencies:
912
+ # "vitest": "^2.0.0"
913
+ # "@testing-library/react": "^16.0.0"
914
+ # "@testing-library/user-event": "^14.0.0"
915
+ # "msw": "^2.0.0"
916
+ # "jsdom": "^25.0.0"
917
+ ```
918
+
919
+ ---
920
+
921
+ ## Section 19: Build & Deployment
922
+
923
+ ### Vite Build
924
+
925
+ ```bash
926
+ npm run build
927
+ # Output: dist/ — static files ready for deployment
928
+ ```
929
+
930
+ ### nginx Configuration (SPA Routing)
931
+
932
+ ```nginx
933
+ server {
934
+ listen 80;
935
+ root /usr/share/nginx/html;
936
+ index index.html;
937
+
938
+ # All routes fall back to index.html for client-side routing
939
+ location / {
940
+ try_files $uri $uri/ /index.html;
941
+ }
942
+
943
+ # Static assets — cache aggressively (Vite hashes filenames)
944
+ location /assets/ {
945
+ expires 1y;
946
+ add_header Cache-Control "public, immutable";
947
+ }
948
+ }
949
+ ```
950
+
951
+ ### Chunk Splitting (vite.config.ts)
952
+
953
+ ```typescript
954
+ // Optimised chunk splitting — add to build.rollupOptions
955
+ rollupOptions: {
956
+ output: {
957
+ manualChunks: {
958
+ vendor: ['react', 'react-dom', 'react-router-dom'],
959
+ ui: ['@headlessui/react', '@heroicons/react'],
960
+ query: ['@tanstack/react-query', 'axios'],
961
+ forms: ['react-hook-form', '@hookform/resolvers', 'zod'],
962
+ zustand: ['zustand'],
963
+ // [If DataGrid = yes] table: ['@tanstack/react-table'],
964
+ // [If Charts = yes] charts: ['recharts'],
965
+ },
966
+ },
967
+ },
968
+ ```
969
+
970
+ > Tailwind ships no runtime JS — utility classes are compiled to a single CSS file at build
971
+ > time and tree-shaken against the `content` globs, so there is no "ui CSS" vendor chunk to split.
972
+
973
+ ---
974
+
975
+ ## Section 20: Internationalisation [CONDITIONAL — Include only if i18n = yes]
976
+
977
+ ```typescript
978
+ // src/lib/i18n.ts
979
+ import i18n from 'i18next';
980
+ import { initReactI18next } from 'react-i18next';
981
+ import LanguageDetector from 'i18next-browser-languagedetector';
982
+ import HttpBackend from 'i18next-http-backend';
983
+
984
+ i18n
985
+ .use(HttpBackend)
986
+ .use(LanguageDetector)
987
+ .use(initReactI18next)
988
+ .init({
989
+ fallbackLng: 'en',
990
+ ns: ['common'],
991
+ defaultNS: 'common',
992
+ backend: {
993
+ loadPath: '/locales/{{lng}}/{{ns}}.json',
994
+ },
995
+ interpolation: { escapeValue: false },
996
+ });
997
+
998
+ export default i18n;
999
+ ```
1000
+
1001
+ ---
1002
+
1003
+ # Part B: Per-Module SPEC.md Template
1004
+
1005
+ Each module from PRD.md and MODEL.md gets its own `<module-name>/SPEC.md` file.
1006
+
1007
+ ---
1008
+
1009
+ ## Module SPEC.md Structure
1010
+
1011
+ ```markdown
1012
+ # {{ModuleName}} — Module Specification
1013
+
1014
+ > Part of [{{APPLICATION_NAME}} Technical Specification](../SPECIFICATION.md)
1015
+
1016
+ ## Overview
1017
+
1018
+ **Module:** {{ModuleName}}
1019
+ **Feature Path:** `src/features/{{moduleName}}/`
1020
+ **Type:** {{System Module | Business Module}}
1021
+ **Backend Endpoint Base:** `/{{api-path}}` (inferred from model/API context)
1022
+ ```
1023
+
1024
+ ---
1025
+
1026
+ ### Traceability
1027
+
1028
+ ```markdown
1029
+ ## Traceability
1030
+
1031
+ ### User Stories
1032
+ | ID | Version | Description |
1033
+ |---|---|---|
1034
+ | USA000030 | v1.0.0 | Create/update hero section content |
1035
+ | USA000033 | v1.0.0 | View list of hero section content |
1036
+
1037
+ ### Non-Functional Requirements
1038
+ | ID | Version | Description |
1039
+ |---|---|---|
1040
+ | NFRA00021 | v1.0.0 | Image must be exactly 1600x500 pixels |
1041
+ | NFRA00024 | v1.0.0 | Headline max 100 characters |
1042
+
1043
+ ### Constraints
1044
+ | ID | Version | Description |
1045
+ |---|---|---|
1046
+ | CONSA0012 | v1.0.0 | Status values: DRAFT, ACTIVE, EXPIRED |
1047
+
1048
+ ### Removed / Replaced
1049
+ | ID | Removed In | Replaced By | Reason |
1050
+ |---|---|---|---|
1051
+ | CONSA0012 (READY status) | v1.0.4 | — | Auto-computed status; READY removed |
1052
+ _or "None." if no removals_
1053
+
1054
+ ### Data Sources
1055
+ | Artifact | Reference |
1056
+ |---|---|
1057
+ | DB Table | `hero_section` |
1058
+ | Mockup Screen | `admin/content/hero_section.html` |
1059
+ ```
1060
+
1061
+ ---
1062
+
1063
+ ### TypeScript Types
1064
+
1065
+ ```markdown
1066
+ ## TypeScript Types
1067
+
1068
+ File: `src/features/heroSection/heroSection.types.ts`
1069
+
1070
+ (Complete TypeScript interfaces and enums — field-for-field from MODEL.md)
1071
+ ```
1072
+
1073
+ All enum values must match PRD.md constraints exactly (e.g., status DRAFT/ACTIVE/EXPIRED).
1074
+ Include the generic `PaginatedResponse<T>` type in the shared types file, not per-module.
1075
+
1076
+ ---
1077
+
1078
+ ### Zod Schema
1079
+
1080
+ ```markdown
1081
+ ## Zod Schema
1082
+
1083
+ File: `src/features/heroSection/heroSection.schema.ts`
1084
+
1085
+ (Complete Zod schema with all validation rules from PRD.md NFRs and Constraints)
1086
+ ```
1087
+
1088
+ Rules must be explicitly derived from tagged NFR IDs:
1089
+ - Character limits → `.max(N, '...')`
1090
+ - URL format → `.url('...')`
1091
+ - Required fields → `.min(1, '...')`
1092
+ - Cross-field rules → `.refine()`
1093
+
1094
+ ---
1095
+
1096
+ ### API Functions
1097
+
1098
+ ```markdown
1099
+ ## API Functions
1100
+
1101
+ File: `src/features/heroSection/api/heroSectionApi.ts`
1102
+
1103
+ (Complete API client object with all methods matching user stories)
1104
+ ```
1105
+
1106
+ - `list(params)` — for list/search user stories
1107
+ - `getById(id)` — for view detail user stories
1108
+ - `create(payload, imageFile?)` — for create user stories
1109
+ - `update(id, payload, imageFile?)` — for update user stories
1110
+ - `delete(id)` — for delete user stories
1111
+ - `imageUrl(id)` — if the module has image fields stored as blobs/binary
1112
+
1113
+ ---
1114
+
1115
+ ### TanStack Query Hooks
1116
+
1117
+ ```markdown
1118
+ ## TanStack Query Hooks
1119
+
1120
+ Files:
1121
+ - `src/features/heroSection/hooks/useHeroSections.ts`
1122
+ - `src/features/heroSection/hooks/useHeroSectionMutations.ts`
1123
+
1124
+ (Complete query key factory and hook implementations)
1125
+ ```
1126
+
1127
+ - Query key factory object with `all`, `lists()`, `list(params)`, `detail(id)` entries
1128
+ - `use{Entity}s(params)` — paginated list query
1129
+ - `use{Entity}(id)` — single item query (disabled when id is empty)
1130
+ - `useCreate{Entity}()` — create mutation with cache invalidation
1131
+ - `useUpdate{Entity}()` — update mutation with cache invalidation
1132
+ - `useDelete{Entity}()` — delete mutation with cache invalidation
1133
+
1134
+ ---
1135
+
1136
+ ### Page Components
1137
+
1138
+ ```markdown
1139
+ ## Page Components
1140
+
1141
+ Files:
1142
+ - `src/features/heroSection/pages/HeroSectionListPage.tsx`
1143
+ - `src/features/heroSection/pages/HeroSectionFormPage.tsx`
1144
+
1145
+ (Complete page component implementations matching the mockup screens)
1146
+ ```
1147
+
1148
+ **CRITICAL — page component requirements:**
1149
+ 1. Use `PageHeader` with breadcrumbs matching `Dashboard → Module Name`
1150
+ 2. Use `useParams()` in form page to distinguish create vs edit mode
1151
+ 3. Reset form when edit data loads: `useEffect(() => { if (data) reset(mapToFormValues(data)); }, [data, reset])`
1152
+ 4. Navigate back after successful submit: `navigate('/hero-section')`
1153
+ 5. Use `LoadingOverlay` while edit data is loading
1154
+ 6. Use `ConfirmDialog` for delete actions via `useConfirm()`
1155
+ 7. Style all layout with Tailwind utilities; use Headless UI for any modal/menu/dropdown
1156
+
1157
+ Form page pattern for create/edit:
1158
+ ```tsx
1159
+ // The same page handles both create and edit based on the presence of :id param
1160
+ export function HeroSectionFormPage() {
1161
+ const { id } = useParams<{ id: string }>();
1162
+ const isEditMode = !!id;
1163
+ // ...fetch data if isEditMode, reset form when data loads
1164
+ }
1165
+ ```
1166
+
1167
+ ---
1168
+
1169
+ ### Form Component
1170
+
1171
+ ```markdown
1172
+ ## Form Component
1173
+
1174
+ File: `src/features/heroSection/components/HeroSectionForm.tsx`
1175
+
1176
+ (Complete form component using React Hook Form + Zod + Tailwind/Headless UI controllers)
1177
+ ```
1178
+
1179
+ ---
1180
+
1181
+ ### Route Definitions
1182
+
1183
+ ```markdown
1184
+ ## Route Definitions
1185
+
1186
+ Add to `src/router/index.tsx`:
1187
+
1188
+ (Complete route definitions for this module — lazy-loaded, with ProtectedRoute wrapping
1189
+ and requiredRoles matching the mockup role folder access control)
1190
+ ```
1191
+
1192
+ ---
1193
+
1194
+ ### Navigation Items
1195
+
1196
+ ```markdown
1197
+ ## Navigation Items
1198
+
1199
+ Add to `src/shared/components/navigationConfig.ts`:
1200
+
1201
+ (NavItem objects for this module, per role)
1202
+ ```
1203
+
1204
+ ---
1205
+
1206
+ ### Status Badge Map (if module has status enum)
1207
+
1208
+ ```markdown
1209
+ ## Status Configuration
1210
+
1211
+ ```typescript
1212
+ // Status display map for use with <StatusBadge />
1213
+ const HERO_SECTION_STATUS_MAP = {
1214
+ DRAFT: { label: 'Draft', variant: 'neutral' as const },
1215
+ ACTIVE: { label: 'Active', variant: 'success' as const },
1216
+ EXPIRED: { label: 'Expired', variant: 'danger' as const },
1217
+ };
1218
+ ```
1219
+
1220
+ ---
1221
+
1222
+ ### CRITICAL Rules for Module SPEC.md
1223
+
1224
+ 1. **Use real field names** from MODEL.md — not `fieldOne`/`fieldTwo`
1225
+ 2. **Use real table/collection names** from MODEL.md
1226
+ 3. **Map every user story** to a specific API function or hook
1227
+ 4. **Map every NFR constraint** to a Zod rule or component behavior
1228
+ 5. **Use module-based URLs** — `/hero-section`, NOT `/admin/hero-section`
1229
+ 6. **Role guards** come from mockup role folder structure → `requiredRoles` on routes
1230
+ 7. **Version-tag every ID** in traceability tables
1231
+ 8. **Never use `any` type** — use proper TypeScript types or `unknown`
1232
+ 9. **All code samples must be complete** — no `// ...` gaps
1233
+ 10. **Form page handles both create and edit** via `useParams()` unless the mockup
1234
+ has clearly separate screens
1235
+ 11. **Tailwind + Headless UI only** — no MUI/Chakra/Ant; compose classes with `cn()`,
1236
+ variants with `cva`, dark mode via `dark:` variants
1237
+ ```