create-wakii-stack 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (998) hide show
  1. package/README.md +66 -2
  2. package/dist/chunk-7XGW4UJ5.js +75 -0
  3. package/dist/chunk-AKPWS7FJ.js +76 -0
  4. package/dist/chunk-ELM6GGC5.js +50 -0
  5. package/dist/chunk-ON2WTGZH.js +77 -0
  6. package/dist/index.js +385 -0
  7. package/dist/manifest-2JVLRMDB.js +10 -0
  8. package/dist/manifest-O35TPW73.js +10 -0
  9. package/dist/manifest-TXTY67BF.js +10 -0
  10. package/dist/manifest-XWHR7Y3F.js +10 -0
  11. package/package.json +23 -4
  12. package/stack-template/.changeset/config.json +15 -0
  13. package/stack-template/.changeset/vu53-ui-redesign.md +11 -0
  14. package/stack-template/.claude/agents/be-dev.md +56 -0
  15. package/stack-template/.claude/agents/contracts-keeper.md +51 -0
  16. package/stack-template/.claude/agents/e2e-runner.md +61 -0
  17. package/stack-template/.claude/agents/fe-dev.md +53 -0
  18. package/stack-template/.claude/settings.json +77 -0
  19. package/stack-template/.claude/settings.local.json +9 -0
  20. package/stack-template/.claude/skills/add-service/SKILL.md +81 -0
  21. package/stack-template/.claude/skills/sync-contracts/SKILL.md +74 -0
  22. package/stack-template/.editorconfig +21 -0
  23. package/stack-template/.gitattributes +10 -0
  24. package/stack-template/.github/pull_request_template.md +26 -0
  25. package/stack-template/.github/workflow-templates/services-ci.yml.example +69 -0
  26. package/stack-template/.github/workflows/contracts.yml +133 -0
  27. package/stack-template/.github/workflows/convergence.yml +209 -0
  28. package/stack-template/.github/workflows/git-guard.yml +44 -0
  29. package/stack-template/.github/workflows/publish-uikit.yml +96 -0
  30. package/stack-template/.github/workflows/remotes-activity.yml +82 -0
  31. package/stack-template/.github/workflows/remotes-tasks.yml +82 -0
  32. package/stack-template/.github/workflows/services-auth-svc.yml +153 -0
  33. package/stack-template/.github/workflows/services-go-svc.yml +281 -0
  34. package/stack-template/.github/workflows/services-node-svc.yml +173 -0
  35. package/stack-template/.github/workflows/services-spring-svc.yml +132 -0
  36. package/stack-template/.github/workflows/shell.yml +78 -0
  37. package/stack-template/.github/workflows/ui-kit.yml +51 -0
  38. package/stack-template/.husky/commit-msg +14 -0
  39. package/stack-template/.husky/pre-push +51 -0
  40. package/stack-template/.spectral.yaml +17 -0
  41. package/stack-template/AGENTS.md +197 -0
  42. package/stack-template/CLAUDE.md +114 -0
  43. package/stack-template/README.md +172 -0
  44. package/stack-template/app/admin/index.html +12 -0
  45. package/stack-template/app/admin/package.json +40 -0
  46. package/stack-template/app/admin/scripts/verify-chart.mjs +49 -0
  47. package/stack-template/app/admin/src/App.test.tsx +70 -0
  48. package/stack-template/app/admin/src/App.tsx +33 -0
  49. package/stack-template/app/admin/src/data/users.ts +47 -0
  50. package/stack-template/app/admin/src/layout/AdminLayout.tsx +212 -0
  51. package/stack-template/app/admin/src/main.tsx +17 -0
  52. package/stack-template/app/admin/src/pages/ComponentsDemo.tsx +138 -0
  53. package/stack-template/app/admin/src/pages/Dashboard.tsx +182 -0
  54. package/stack-template/app/admin/src/pages/HooksDemo.tsx +153 -0
  55. package/stack-template/app/admin/src/pages/Settings.tsx +156 -0
  56. package/stack-template/app/admin/src/pages/UploadPage.tsx +34 -0
  57. package/stack-template/app/admin/src/pages/Users.test.tsx +66 -0
  58. package/stack-template/app/admin/src/pages/Users.tsx +245 -0
  59. package/stack-template/app/admin/src/styles.css +9 -0
  60. package/stack-template/app/admin/src/tests/setup.ts +15 -0
  61. package/stack-template/app/admin/tsconfig.json +18 -0
  62. package/stack-template/app/admin/vite.config.ts +11 -0
  63. package/stack-template/app/admin/vitest.config.ts +14 -0
  64. package/stack-template/app/create-wakii-app/README.md +71 -0
  65. package/stack-template/app/create-wakii-app/package.json +27 -0
  66. package/stack-template/app/create-wakii-app/scripts/publish-npm.sh +38 -0
  67. package/stack-template/app/create-wakii-app/src/index.ts +127 -0
  68. package/stack-template/app/create-wakii-app/src/options.test.ts +80 -0
  69. package/stack-template/app/create-wakii-app/src/options.ts +117 -0
  70. package/stack-template/app/create-wakii-app/src/scaffold.test.ts +143 -0
  71. package/stack-template/app/create-wakii-app/src/scaffold.ts +194 -0
  72. package/stack-template/app/create-wakii-app/tsconfig.json +17 -0
  73. package/stack-template/app/create-wakii-app/vitest.config.ts +9 -0
  74. package/stack-template/app/create-wakii-stack/package.json +27 -0
  75. package/stack-template/app/create-wakii-stack/src/manifest.ts +101 -0
  76. package/stack-template/app/create-wakii-stack/src/options.ts +106 -0
  77. package/stack-template/app/create-wakii-stack/src/scaffold.ts +315 -0
  78. package/stack-template/app/create-wakii-stack/tsconfig.json +17 -0
  79. package/stack-template/app/create-wakii-stack/vitest.config.ts +9 -0
  80. package/stack-template/app/remotes/activity/Dockerfile +36 -0
  81. package/stack-template/app/remotes/activity/README.md +59 -0
  82. package/stack-template/app/remotes/activity/index.html +11 -0
  83. package/stack-template/app/remotes/activity/nginx.conf +35 -0
  84. package/stack-template/app/remotes/activity/package.json +40 -0
  85. package/stack-template/app/remotes/activity/rspack.config.mjs +152 -0
  86. package/stack-template/app/remotes/activity/src/ActivityPage.tsx +139 -0
  87. package/stack-template/app/remotes/activity/src/api.ts +63 -0
  88. package/stack-template/app/remotes/activity/src/app.css +7 -0
  89. package/stack-template/app/remotes/activity/src/components/FeedItem.tsx +39 -0
  90. package/stack-template/app/remotes/activity/src/components/StatTile.tsx +24 -0
  91. package/stack-template/app/remotes/activity/src/components/Timeline.tsx +53 -0
  92. package/stack-template/app/remotes/activity/src/components/time.ts +30 -0
  93. package/stack-template/app/remotes/activity/src/env.d.ts +5 -0
  94. package/stack-template/app/remotes/activity/src/index.tsx +12 -0
  95. package/stack-template/app/remotes/activity/src/standalone.tsx +36 -0
  96. package/stack-template/app/remotes/activity/tests/ActivityPage.test.tsx +260 -0
  97. package/stack-template/app/remotes/activity/tests/api.test.ts +61 -0
  98. package/stack-template/app/remotes/activity/tests/setup.ts +1 -0
  99. package/stack-template/app/remotes/activity/tests/test-utils.tsx +16 -0
  100. package/stack-template/app/remotes/activity/tsconfig.json +26 -0
  101. package/stack-template/app/remotes/activity/vitest.config.ts +38 -0
  102. package/stack-template/app/remotes/tasks/Dockerfile +36 -0
  103. package/stack-template/app/remotes/tasks/README.md +59 -0
  104. package/stack-template/app/remotes/tasks/index.html +11 -0
  105. package/stack-template/app/remotes/tasks/nginx.conf +35 -0
  106. package/stack-template/app/remotes/tasks/package.json +41 -0
  107. package/stack-template/app/remotes/tasks/rspack.config.mjs +153 -0
  108. package/stack-template/app/remotes/tasks/src/TasksPage.tsx +284 -0
  109. package/stack-template/app/remotes/tasks/src/api.ts +109 -0
  110. package/stack-template/app/remotes/tasks/src/app.css +7 -0
  111. package/stack-template/app/remotes/tasks/src/components/StatusBadge.tsx +20 -0
  112. package/stack-template/app/remotes/tasks/src/components/StatusSelect.tsx +27 -0
  113. package/stack-template/app/remotes/tasks/src/components/TaskForm.tsx +74 -0
  114. package/stack-template/app/remotes/tasks/src/components/TaskItem.tsx +199 -0
  115. package/stack-template/app/remotes/tasks/src/components/TaskList.tsx +60 -0
  116. package/stack-template/app/remotes/tasks/src/components/status.ts +23 -0
  117. package/stack-template/app/remotes/tasks/src/env.d.ts +5 -0
  118. package/stack-template/app/remotes/tasks/src/index.tsx +12 -0
  119. package/stack-template/app/remotes/tasks/src/standalone.tsx +38 -0
  120. package/stack-template/app/remotes/tasks/tests/TasksPage.test.tsx +445 -0
  121. package/stack-template/app/remotes/tasks/tests/api.test.ts +159 -0
  122. package/stack-template/app/remotes/tasks/tests/setup.ts +1 -0
  123. package/stack-template/app/remotes/tasks/tests/test-utils.tsx +16 -0
  124. package/stack-template/app/remotes/tasks/tsconfig.json +26 -0
  125. package/stack-template/app/remotes/tasks/vitest.config.ts +34 -0
  126. package/stack-template/app/shared/README.md +21 -0
  127. package/stack-template/app/shared/package.json +37 -0
  128. package/stack-template/app/shared/src/api-client.ts +66 -0
  129. package/stack-template/app/shared/src/error-envelope.ts +38 -0
  130. package/stack-template/app/shared/src/index.ts +21 -0
  131. package/stack-template/app/shared/src/mf-bootstrap.ts +89 -0
  132. package/stack-template/app/shared/src/refresh-client.ts +170 -0
  133. package/stack-template/app/shared/src/token-storage.ts +57 -0
  134. package/stack-template/app/shell/Dockerfile +37 -0
  135. package/stack-template/app/shell/README.md +79 -0
  136. package/stack-template/app/shell/index.html +11 -0
  137. package/stack-template/app/shell/nginx.conf +23 -0
  138. package/stack-template/app/shell/package.json +43 -0
  139. package/stack-template/app/shell/rspack.config.mjs +147 -0
  140. package/stack-template/app/shell/src/App.tsx +57 -0
  141. package/stack-template/app/shell/src/api.ts +36 -0
  142. package/stack-template/app/shell/src/app.css +11 -0
  143. package/stack-template/app/shell/src/bootstrap.tsx +24 -0
  144. package/stack-template/app/shell/src/components/Layout.tsx +35 -0
  145. package/stack-template/app/shell/src/components/NavBar.tsx +118 -0
  146. package/stack-template/app/shell/src/components/RemoteSlot.tsx +82 -0
  147. package/stack-template/app/shell/src/components/RequireAuth.tsx +14 -0
  148. package/stack-template/app/shell/src/env.d.ts +7 -0
  149. package/stack-template/app/shell/src/index.tsx +3 -0
  150. package/stack-template/app/shell/src/pages/HomePage.tsx +70 -0
  151. package/stack-template/app/shell/src/pages/LoginPage.tsx +217 -0
  152. package/stack-template/app/shell/src/remote-urls.ts +18 -0
  153. package/stack-template/app/shell/tests/a11y.test.tsx +53 -0
  154. package/stack-template/app/shell/tests/api-timeout.test.ts +43 -0
  155. package/stack-template/app/shell/tests/integration.test.tsx +93 -0
  156. package/stack-template/app/shell/tests/login.test.tsx +227 -0
  157. package/stack-template/app/shell/tests/mf-retry.test.ts +76 -0
  158. package/stack-template/app/shell/tests/refresh-client.test.ts +301 -0
  159. package/stack-template/app/shell/tests/remote-slot.test.tsx +109 -0
  160. package/stack-template/app/shell/tests/remote-urls.test.ts +26 -0
  161. package/stack-template/app/shell/tests/setup.ts +15 -0
  162. package/stack-template/app/shell/tests/shell-chrome.test.tsx +126 -0
  163. package/stack-template/app/shell/tsconfig.json +26 -0
  164. package/stack-template/app/shell/vitest.config.ts +42 -0
  165. package/stack-template/app/spike/README.md +35 -0
  166. package/stack-template/app/spike/host/index.html +11 -0
  167. package/stack-template/app/spike/host/package.json +17 -0
  168. package/stack-template/app/spike/host/rspack.config.mjs +34 -0
  169. package/stack-template/app/spike/host/src/bootstrap.jsx +26 -0
  170. package/stack-template/app/spike/host/src/index.jsx +3 -0
  171. package/stack-template/app/spike/remote/package.json +17 -0
  172. package/stack-template/app/spike/remote/rspack.config.mjs +36 -0
  173. package/stack-template/app/spike/remote/src/Hello.jsx +7 -0
  174. package/stack-template/app/spike/remote/src/index.js +2 -0
  175. package/stack-template/app/spike/serve.mjs +31 -0
  176. package/stack-template/app/starter-templates/template-feats/extras/carousel/src/DemoCarousel.tsx +99 -0
  177. package/stack-template/app/starter-templates/template-feats/extras/chart/src/DemoChart.tsx +84 -0
  178. package/stack-template/app/starter-templates/template-feats/extras/editor/src/DemoEditor.tsx +110 -0
  179. package/stack-template/app/starter-templates/template-feats/extras/schedule/src/DemoSchedule.tsx +81 -0
  180. package/stack-template/app/starter-templates/template-feats/router/src/App.tsx +332 -0
  181. package/stack-template/app/starter-templates/template-feats/router/src/main.tsx +14 -0
  182. package/stack-template/app/starter-templates/vite-js/README.md +72 -0
  183. package/stack-template/app/starter-templates/vite-js/index.html +12 -0
  184. package/stack-template/app/starter-templates/vite-js/jsconfig.json +10 -0
  185. package/stack-template/app/starter-templates/vite-js/package.json +22 -0
  186. package/stack-template/app/starter-templates/vite-js/src/App.jsx +158 -0
  187. package/stack-template/app/starter-templates/vite-js/src/main.jsx +10 -0
  188. package/stack-template/app/starter-templates/vite-js/src/styles.css +15 -0
  189. package/stack-template/app/starter-templates/vite-js/src/theme.js +21 -0
  190. package/stack-template/app/starter-templates/vite-js/vite.config.mjs +8 -0
  191. package/stack-template/app/starter-templates/vite-ts/README.md +53 -0
  192. package/stack-template/app/starter-templates/vite-ts/index.html +12 -0
  193. package/stack-template/app/starter-templates/vite-ts/package.json +29 -0
  194. package/stack-template/app/starter-templates/vite-ts/src/App.tsx +181 -0
  195. package/stack-template/app/starter-templates/vite-ts/src/main.tsx +12 -0
  196. package/stack-template/app/starter-templates/vite-ts/src/styles.css +21 -0
  197. package/stack-template/app/starter-templates/vite-ts/src/theme.ts +16 -0
  198. package/stack-template/app/starter-templates/vite-ts/tsconfig.json +25 -0
  199. package/stack-template/app/starter-templates/vite-ts/tsconfig.node.json +11 -0
  200. package/stack-template/app/starter-templates/vite-ts/vite.config.ts +10 -0
  201. package/stack-template/app/ui-kit/.storybook/main.ts +29 -0
  202. package/stack-template/app/ui-kit/.storybook/manager-head.html +97 -0
  203. package/stack-template/app/ui-kit/.storybook/manager.ts +138 -0
  204. package/stack-template/app/ui-kit/.storybook/preview-head.html +57 -0
  205. package/stack-template/app/ui-kit/.storybook/preview.ts +62 -0
  206. package/stack-template/app/ui-kit/.storybook/tailwind-preview.css +3 -0
  207. package/stack-template/app/ui-kit/.storybook/test-runner.config.ts +20 -0
  208. package/stack-template/app/ui-kit/CHANGELOG.md +137 -0
  209. package/stack-template/app/ui-kit/LICENSE +21 -0
  210. package/stack-template/app/ui-kit/MIGRATION.md +84 -0
  211. package/stack-template/app/ui-kit/README.md +173 -0
  212. package/stack-template/app/ui-kit/RELEASE.md +77 -0
  213. package/stack-template/app/ui-kit/USAGE.md +380 -0
  214. package/stack-template/app/ui-kit/eslint.config.js +47 -0
  215. package/stack-template/app/ui-kit/package.json +166 -0
  216. package/stack-template/app/ui-kit/scripts/publish-github.sh +39 -0
  217. package/stack-template/app/ui-kit/scripts/publish-npm.sh +76 -0
  218. package/stack-template/app/ui-kit/scripts/stamp-build.cjs +13 -0
  219. package/stack-template/app/ui-kit/src/KitchenSink.stories.tsx +576 -0
  220. package/stack-template/app/ui-kit/src/Tokens.stories.tsx +193 -0
  221. package/stack-template/app/ui-kit/src/entries/carousel.ts +7 -0
  222. package/stack-template/app/ui-kit/src/entries/chart.ts +4 -0
  223. package/stack-template/app/ui-kit/src/entries/editor.ts +4 -0
  224. package/stack-template/app/ui-kit/src/entries/experience3d.ts +5 -0
  225. package/stack-template/app/ui-kit/src/entries/schedule.ts +5 -0
  226. package/stack-template/app/ui-kit/src/env.d.ts +3 -0
  227. package/stack-template/app/ui-kit/src/hooks/form.stories.tsx +80 -0
  228. package/stack-template/app/ui-kit/src/hooks/hooks-new.stories.tsx +392 -0
  229. package/stack-template/app/ui-kit/src/hooks/hooks.stories.tsx +167 -0
  230. package/stack-template/app/ui-kit/src/hooks/useClickAway.test.tsx +63 -0
  231. package/stack-template/app/ui-kit/src/hooks/useClickAway.ts +30 -0
  232. package/stack-template/app/ui-kit/src/hooks/useControllableState.test.ts +36 -0
  233. package/stack-template/app/ui-kit/src/hooks/useControllableState.ts +41 -0
  234. package/stack-template/app/ui-kit/src/hooks/useCopyToClipboard.test.ts +89 -0
  235. package/stack-template/app/ui-kit/src/hooks/useCopyToClipboard.ts +20 -0
  236. package/stack-template/app/ui-kit/src/hooks/useCountdown.test.ts +88 -0
  237. package/stack-template/app/ui-kit/src/hooks/useCountdown.ts +38 -0
  238. package/stack-template/app/ui-kit/src/hooks/useDebounce.test.ts +71 -0
  239. package/stack-template/app/ui-kit/src/hooks/useDebounce.ts +14 -0
  240. package/stack-template/app/ui-kit/src/hooks/useDefault.test.ts +37 -0
  241. package/stack-template/app/ui-kit/src/hooks/useDefault.ts +15 -0
  242. package/stack-template/app/ui-kit/src/hooks/useEventListener.test.ts +47 -0
  243. package/stack-template/app/ui-kit/src/hooks/useEventListener.ts +28 -0
  244. package/stack-template/app/ui-kit/src/hooks/useFieldArray.test.tsx +160 -0
  245. package/stack-template/app/ui-kit/src/hooks/useFieldArray.ts +85 -0
  246. package/stack-template/app/ui-kit/src/hooks/useFocusTrap.ts +67 -0
  247. package/stack-template/app/ui-kit/src/hooks/useForm.test.tsx +192 -0
  248. package/stack-template/app/ui-kit/src/hooks/useForm.ts +119 -0
  249. package/stack-template/app/ui-kit/src/hooks/useFullscreen.test.tsx +71 -0
  250. package/stack-template/app/ui-kit/src/hooks/useFullscreen.ts +68 -0
  251. package/stack-template/app/ui-kit/src/hooks/useHover.test.tsx +30 -0
  252. package/stack-template/app/ui-kit/src/hooks/useHover.ts +23 -0
  253. package/stack-template/app/ui-kit/src/hooks/useInView.test.tsx +70 -0
  254. package/stack-template/app/ui-kit/src/hooks/useInView.ts +55 -0
  255. package/stack-template/app/ui-kit/src/hooks/useInfiniteScroll.test.tsx +72 -0
  256. package/stack-template/app/ui-kit/src/hooks/useInfiniteScroll.ts +45 -0
  257. package/stack-template/app/ui-kit/src/hooks/useIsFirstRender.test.ts +30 -0
  258. package/stack-template/app/ui-kit/src/hooks/useIsFirstRender.ts +14 -0
  259. package/stack-template/app/ui-kit/src/hooks/useKeyPress.test.ts +45 -0
  260. package/stack-template/app/ui-kit/src/hooks/useKeyPress.ts +31 -0
  261. package/stack-template/app/ui-kit/src/hooks/useLocalStorage.test.ts +102 -0
  262. package/stack-template/app/ui-kit/src/hooks/useLocalStorage.ts +34 -0
  263. package/stack-template/app/ui-kit/src/hooks/useLockBodyScroll.test.ts +42 -0
  264. package/stack-template/app/ui-kit/src/hooks/useLockBodyScroll.ts +13 -0
  265. package/stack-template/app/ui-kit/src/hooks/useMeasure.test.tsx +57 -0
  266. package/stack-template/app/ui-kit/src/hooks/useMeasure.ts +32 -0
  267. package/stack-template/app/ui-kit/src/hooks/useMediaQuery.test.ts +73 -0
  268. package/stack-template/app/ui-kit/src/hooks/useMediaQuery.ts +20 -0
  269. package/stack-template/app/ui-kit/src/hooks/useMountEffect.test.ts +22 -0
  270. package/stack-template/app/ui-kit/src/hooks/useMountEffect.ts +10 -0
  271. package/stack-template/app/ui-kit/src/hooks/useOnlineStatus.test.ts +36 -0
  272. package/stack-template/app/ui-kit/src/hooks/useOnlineStatus.ts +21 -0
  273. package/stack-template/app/ui-kit/src/hooks/usePrevious.test.ts +35 -0
  274. package/stack-template/app/ui-kit/src/hooks/usePrevious.ts +13 -0
  275. package/stack-template/app/ui-kit/src/hooks/useScrollProgress.test.ts +59 -0
  276. package/stack-template/app/ui-kit/src/hooks/useScrollProgress.ts +31 -0
  277. package/stack-template/app/ui-kit/src/hooks/useSessionStorage.test.ts +80 -0
  278. package/stack-template/app/ui-kit/src/hooks/useSessionStorage.ts +34 -0
  279. package/stack-template/app/ui-kit/src/hooks/useThrottle.test.ts +61 -0
  280. package/stack-template/app/ui-kit/src/hooks/useThrottle.ts +30 -0
  281. package/stack-template/app/ui-kit/src/hooks/useTimeout.test.ts +95 -0
  282. package/stack-template/app/ui-kit/src/hooks/useTimeout.ts +38 -0
  283. package/stack-template/app/ui-kit/src/hooks/useTitle.test.ts +34 -0
  284. package/stack-template/app/ui-kit/src/hooks/useTitle.ts +24 -0
  285. package/stack-template/app/ui-kit/src/hooks/useToggle.test.ts +46 -0
  286. package/stack-template/app/ui-kit/src/hooks/useToggle.ts +16 -0
  287. package/stack-template/app/ui-kit/src/hooks/useUpdateEffect.test.ts +25 -0
  288. package/stack-template/app/ui-kit/src/hooks/useUpdateEffect.ts +18 -0
  289. package/stack-template/app/ui-kit/src/hooks/useWindowSize.test.ts +33 -0
  290. package/stack-template/app/ui-kit/src/hooks/useWindowSize.ts +23 -0
  291. package/stack-template/app/ui-kit/src/index.ts +218 -0
  292. package/stack-template/app/ui-kit/src/intro-showcase.stories.tsx +272 -0
  293. package/stack-template/app/ui-kit/src/intro.docs.mdx +247 -0
  294. package/stack-template/app/ui-kit/src/motion/motion-showcase.stories.tsx +234 -0
  295. package/stack-template/app/ui-kit/src/motion/motion.md +38 -0
  296. package/stack-template/app/ui-kit/src/provider/index.tsx +77 -0
  297. package/stack-template/app/ui-kit/src/provider/provider.stories.tsx +87 -0
  298. package/stack-template/app/ui-kit/src/provider/provider.test.tsx +121 -0
  299. package/stack-template/app/ui-kit/src/styles/base.css +171 -0
  300. package/stack-template/app/ui-kit/src/styles/dark-theme.test.ts +21 -0
  301. package/stack-template/app/ui-kit/src/styles/tailwind.css +220 -0
  302. package/stack-template/app/ui-kit/src/styles/themes/dark.css +71 -0
  303. package/stack-template/app/ui-kit/src/styles/tokens.css +133 -0
  304. package/stack-template/app/ui-kit/src/styles/ui-kit.css +10 -0
  305. package/stack-template/app/ui-kit/src/templates/auth.stories.tsx +425 -0
  306. package/stack-template/app/ui-kit/src/templates/crud.stories.tsx +416 -0
  307. package/stack-template/app/ui-kit/src/templates/dashboard.stories.tsx +504 -0
  308. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch1-deep-focus.tsx +96 -0
  309. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch2-living-docs.tsx +134 -0
  310. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch3-team-velocity.tsx +148 -0
  311. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch4-ship-your-app.tsx +100 -0
  312. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch5-future.tsx +67 -0
  313. package/stack-template/app/ui-kit/src/templates/experience/chapters/hero.tsx +434 -0
  314. package/stack-template/app/ui-kit/src/templates/experience/chapters/nav-footer.tsx +85 -0
  315. package/stack-template/app/ui-kit/src/templates/experience/hero.stories.tsx +27 -0
  316. package/stack-template/app/ui-kit/src/templates/experience/hero.test.tsx +108 -0
  317. package/stack-template/app/ui-kit/src/templates/experience/index.stories.tsx +51 -0
  318. package/stack-template/app/ui-kit/src/templates/experience/lib/ChapterShell.tsx +84 -0
  319. package/stack-template/app/ui-kit/src/templates/experience/lib/SideNav.tsx +173 -0
  320. package/stack-template/app/ui-kit/src/templates/experience/lib/chapter-shell.test.tsx +266 -0
  321. package/stack-template/app/ui-kit/src/templates/experience/lib/scroll-mood.tsx +143 -0
  322. package/stack-template/app/ui-kit/src/templates/experience/lib/starfield.test.tsx +31 -0
  323. package/stack-template/app/ui-kit/src/templates/experience/lib/starfield.tsx +190 -0
  324. package/stack-template/app/ui-kit/src/templates/experience/mood-engine.stories.tsx +114 -0
  325. package/stack-template/app/ui-kit/src/templates/experience/shell-nav.stories.tsx +113 -0
  326. package/stack-template/app/ui-kit/src/templates/kanban-project.stories.tsx +352 -0
  327. package/stack-template/app/ui-kit/src/templates/landing.stories.tsx +380 -0
  328. package/stack-template/app/ui-kit/src/templates/parallax-landing.stories.tsx +633 -0
  329. package/stack-template/app/ui-kit/src/templates/settings.stories.tsx +474 -0
  330. package/stack-template/app/ui-kit/src/ui/accordion/accordion.stories.tsx +91 -0
  331. package/stack-template/app/ui-kit/src/ui/accordion/accordion.test.tsx +99 -0
  332. package/stack-template/app/ui-kit/src/ui/accordion/index.tsx +107 -0
  333. package/stack-template/app/ui-kit/src/ui/affix/affix.stories.tsx +104 -0
  334. package/stack-template/app/ui-kit/src/ui/affix/affix.test.tsx +138 -0
  335. package/stack-template/app/ui-kit/src/ui/affix/index.tsx +89 -0
  336. package/stack-template/app/ui-kit/src/ui/alert/alert.stories.tsx +149 -0
  337. package/stack-template/app/ui-kit/src/ui/alert/alert.test.tsx +85 -0
  338. package/stack-template/app/ui-kit/src/ui/alert/index.tsx +118 -0
  339. package/stack-template/app/ui-kit/src/ui/anchor/anchor.stories.tsx +96 -0
  340. package/stack-template/app/ui-kit/src/ui/anchor/anchor.test.tsx +191 -0
  341. package/stack-template/app/ui-kit/src/ui/anchor/index.tsx +144 -0
  342. package/stack-template/app/ui-kit/src/ui/auto-complete/auto-complete.stories.tsx +67 -0
  343. package/stack-template/app/ui-kit/src/ui/auto-complete/auto-complete.test.tsx +94 -0
  344. package/stack-template/app/ui-kit/src/ui/auto-complete/index.tsx +54 -0
  345. package/stack-template/app/ui-kit/src/ui/avatar/avatar.stories.tsx +132 -0
  346. package/stack-template/app/ui-kit/src/ui/avatar/avatar.test.tsx +65 -0
  347. package/stack-template/app/ui-kit/src/ui/avatar/index.tsx +48 -0
  348. package/stack-template/app/ui-kit/src/ui/avatar-group/avatar-group.stories.tsx +113 -0
  349. package/stack-template/app/ui-kit/src/ui/avatar-group/avatar-group.test.tsx +71 -0
  350. package/stack-template/app/ui-kit/src/ui/avatar-group/index.tsx +66 -0
  351. package/stack-template/app/ui-kit/src/ui/backdrop/backdrop.stories.tsx +66 -0
  352. package/stack-template/app/ui-kit/src/ui/backdrop/backdrop.test.tsx +37 -0
  353. package/stack-template/app/ui-kit/src/ui/backdrop/index.tsx +29 -0
  354. package/stack-template/app/ui-kit/src/ui/badge/badge.stories.tsx +105 -0
  355. package/stack-template/app/ui-kit/src/ui/badge/badge.test.tsx +115 -0
  356. package/stack-template/app/ui-kit/src/ui/badge/index.tsx +154 -0
  357. package/stack-template/app/ui-kit/src/ui/blockui/blockui.stories.tsx +34 -0
  358. package/stack-template/app/ui-kit/src/ui/blockui/blockui.test.tsx +29 -0
  359. package/stack-template/app/ui-kit/src/ui/blockui/index.tsx +25 -0
  360. package/stack-template/app/ui-kit/src/ui/bottom-navigation/bottom-navigation.stories.tsx +70 -0
  361. package/stack-template/app/ui-kit/src/ui/bottom-navigation/bottom-navigation.test.tsx +68 -0
  362. package/stack-template/app/ui-kit/src/ui/bottom-navigation/index.tsx +82 -0
  363. package/stack-template/app/ui-kit/src/ui/branch-fill.test.tsx +245 -0
  364. package/stack-template/app/ui-kit/src/ui/breadcrumb/breadcrumb.stories.tsx +103 -0
  365. package/stack-template/app/ui-kit/src/ui/breadcrumb/breadcrumb.test.tsx +49 -0
  366. package/stack-template/app/ui-kit/src/ui/breadcrumb/index.tsx +37 -0
  367. package/stack-template/app/ui-kit/src/ui/busy-box/busy-box.stories.tsx +30 -0
  368. package/stack-template/app/ui-kit/src/ui/busy-box/busy-box.test.tsx +29 -0
  369. package/stack-template/app/ui-kit/src/ui/busy-box/index.tsx +25 -0
  370. package/stack-template/app/ui-kit/src/ui/button/button.stories.tsx +121 -0
  371. package/stack-template/app/ui-kit/src/ui/button/button.test.tsx +207 -0
  372. package/stack-template/app/ui-kit/src/ui/button/index.tsx +128 -0
  373. package/stack-template/app/ui-kit/src/ui/calendar/calendar.stories.tsx +100 -0
  374. package/stack-template/app/ui-kit/src/ui/calendar/calendar.test.tsx +92 -0
  375. package/stack-template/app/ui-kit/src/ui/calendar/index.tsx +163 -0
  376. package/stack-template/app/ui-kit/src/ui/card/card.stories.tsx +203 -0
  377. package/stack-template/app/ui-kit/src/ui/card/card.test.tsx +135 -0
  378. package/stack-template/app/ui-kit/src/ui/card/index.tsx +84 -0
  379. package/stack-template/app/ui-kit/src/ui/carousel/carousel.stories.tsx +533 -0
  380. package/stack-template/app/ui-kit/src/ui/carousel/carousel.test.tsx +148 -0
  381. package/stack-template/app/ui-kit/src/ui/carousel/index.tsx +195 -0
  382. package/stack-template/app/ui-kit/src/ui/cascade-select/cascade-select.stories.tsx +126 -0
  383. package/stack-template/app/ui-kit/src/ui/cascade-select/cascade-select.test.tsx +132 -0
  384. package/stack-template/app/ui-kit/src/ui/cascade-select/index.tsx +87 -0
  385. package/stack-template/app/ui-kit/src/ui/chart/chart-theme.test.tsx +79 -0
  386. package/stack-template/app/ui-kit/src/ui/chart/chart.stories.tsx +278 -0
  387. package/stack-template/app/ui-kit/src/ui/chart/chart.test.tsx +103 -0
  388. package/stack-template/app/ui-kit/src/ui/chart/index.tsx +172 -0
  389. package/stack-template/app/ui-kit/src/ui/checkbox/checkbox.stories.tsx +67 -0
  390. package/stack-template/app/ui-kit/src/ui/checkbox/checkbox.test.tsx +99 -0
  391. package/stack-template/app/ui-kit/src/ui/checkbox/index.tsx +52 -0
  392. package/stack-template/app/ui-kit/src/ui/chips/chips.stories.tsx +53 -0
  393. package/stack-template/app/ui-kit/src/ui/chips/chips.test.tsx +86 -0
  394. package/stack-template/app/ui-kit/src/ui/chips/index.tsx +44 -0
  395. package/stack-template/app/ui-kit/src/ui/collapse/collapse.stories.tsx +93 -0
  396. package/stack-template/app/ui-kit/src/ui/collapse/collapse.test.tsx +128 -0
  397. package/stack-template/app/ui-kit/src/ui/collapse/index.tsx +75 -0
  398. package/stack-template/app/ui-kit/src/ui/color-picker/color-picker.stories.tsx +48 -0
  399. package/stack-template/app/ui-kit/src/ui/color-picker/color-picker.test.tsx +68 -0
  400. package/stack-template/app/ui-kit/src/ui/color-picker/index.tsx +38 -0
  401. package/stack-template/app/ui-kit/src/ui/context-menu/context-menu.stories.tsx +73 -0
  402. package/stack-template/app/ui-kit/src/ui/context-menu/context-menu.test.tsx +93 -0
  403. package/stack-template/app/ui-kit/src/ui/context-menu/index.tsx +79 -0
  404. package/stack-template/app/ui-kit/src/ui/count-up/count-up.stories.tsx +80 -0
  405. package/stack-template/app/ui-kit/src/ui/count-up/count-up.test.tsx +121 -0
  406. package/stack-template/app/ui-kit/src/ui/count-up/index.tsx +70 -0
  407. package/stack-template/app/ui-kit/src/ui/date-picker/date-picker.stories.tsx +154 -0
  408. package/stack-template/app/ui-kit/src/ui/date-picker/date-picker.test.tsx +221 -0
  409. package/stack-template/app/ui-kit/src/ui/date-picker/index.tsx +287 -0
  410. package/stack-template/app/ui-kit/src/ui/date-picker/locale-constants.ts +90 -0
  411. package/stack-template/app/ui-kit/src/ui/date-picker/locale.tsx +15 -0
  412. package/stack-template/app/ui-kit/src/ui/deferred-content/deferred-content.stories.tsx +62 -0
  413. package/stack-template/app/ui-kit/src/ui/deferred-content/deferred-content.test.tsx +94 -0
  414. package/stack-template/app/ui-kit/src/ui/deferred-content/index.tsx +61 -0
  415. package/stack-template/app/ui-kit/src/ui/descriptions/descriptions.stories.tsx +114 -0
  416. package/stack-template/app/ui-kit/src/ui/descriptions/descriptions.test.tsx +75 -0
  417. package/stack-template/app/ui-kit/src/ui/descriptions/index.tsx +48 -0
  418. package/stack-template/app/ui-kit/src/ui/divider/divider.stories.tsx +66 -0
  419. package/stack-template/app/ui-kit/src/ui/divider/divider.test.tsx +83 -0
  420. package/stack-template/app/ui-kit/src/ui/divider/index.tsx +65 -0
  421. package/stack-template/app/ui-kit/src/ui/drag-drop/drag-drop.stories.tsx +145 -0
  422. package/stack-template/app/ui-kit/src/ui/drag-drop/drag-drop.test.tsx +352 -0
  423. package/stack-template/app/ui-kit/src/ui/drag-drop/index.tsx +456 -0
  424. package/stack-template/app/ui-kit/src/ui/drawer/drawer.stories.tsx +108 -0
  425. package/stack-template/app/ui-kit/src/ui/drawer/drawer.test.tsx +132 -0
  426. package/stack-template/app/ui-kit/src/ui/drawer/index.tsx +113 -0
  427. package/stack-template/app/ui-kit/src/ui/dropdown/dropdown.stories.tsx +61 -0
  428. package/stack-template/app/ui-kit/src/ui/dropdown/dropdown.test.tsx +101 -0
  429. package/stack-template/app/ui-kit/src/ui/dropdown/index.tsx +162 -0
  430. package/stack-template/app/ui-kit/src/ui/editor/EditorInner.tsx +93 -0
  431. package/stack-template/app/ui-kit/src/ui/editor/editor.stories.tsx +37 -0
  432. package/stack-template/app/ui-kit/src/ui/editor/editor.test.tsx +84 -0
  433. package/stack-template/app/ui-kit/src/ui/editor/index.tsx +58 -0
  434. package/stack-template/app/ui-kit/src/ui/empty-state/empty-state.stories.tsx +24 -0
  435. package/stack-template/app/ui-kit/src/ui/empty-state/empty-state.test.tsx +48 -0
  436. package/stack-template/app/ui-kit/src/ui/empty-state/index.tsx +22 -0
  437. package/stack-template/app/ui-kit/src/ui/experience3d/experience3d.stories.tsx +66 -0
  438. package/stack-template/app/ui-kit/src/ui/experience3d/experience3d.test.tsx +50 -0
  439. package/stack-template/app/ui-kit/src/ui/experience3d/index.tsx +457 -0
  440. package/stack-template/app/ui-kit/src/ui/field/field-array.stories.tsx +214 -0
  441. package/stack-template/app/ui-kit/src/ui/field/field.stories.tsx +158 -0
  442. package/stack-template/app/ui-kit/src/ui/field/field.test.tsx +68 -0
  443. package/stack-template/app/ui-kit/src/ui/field/index.tsx +48 -0
  444. package/stack-template/app/ui-kit/src/ui/fieldset/fieldset.stories.tsx +49 -0
  445. package/stack-template/app/ui-kit/src/ui/fieldset/fieldset.test.tsx +88 -0
  446. package/stack-template/app/ui-kit/src/ui/fieldset/index.tsx +62 -0
  447. package/stack-template/app/ui-kit/src/ui/flex/flex.stories.tsx +96 -0
  448. package/stack-template/app/ui-kit/src/ui/flex/flex.test.tsx +79 -0
  449. package/stack-template/app/ui-kit/src/ui/flex/index.tsx +45 -0
  450. package/stack-template/app/ui-kit/src/ui/float-button/float-button.stories.tsx +82 -0
  451. package/stack-template/app/ui-kit/src/ui/float-button/float-button.test.tsx +107 -0
  452. package/stack-template/app/ui-kit/src/ui/float-button/index.tsx +124 -0
  453. package/stack-template/app/ui-kit/src/ui/galleria/galleria.stories.tsx +78 -0
  454. package/stack-template/app/ui-kit/src/ui/galleria/galleria.test.tsx +67 -0
  455. package/stack-template/app/ui-kit/src/ui/galleria/index.tsx +47 -0
  456. package/stack-template/app/ui-kit/src/ui/grid/grid.stories.tsx +179 -0
  457. package/stack-template/app/ui-kit/src/ui/grid/grid.test.tsx +286 -0
  458. package/stack-template/app/ui-kit/src/ui/grid/index.tsx +104 -0
  459. package/stack-template/app/ui-kit/src/ui/icons/icons.stories.tsx +52 -0
  460. package/stack-template/app/ui-kit/src/ui/icons/icons.test.tsx +60 -0
  461. package/stack-template/app/ui-kit/src/ui/icons/index.tsx +294 -0
  462. package/stack-template/app/ui-kit/src/ui/image/image.stories.tsx +231 -0
  463. package/stack-template/app/ui-kit/src/ui/image/image.test.tsx +79 -0
  464. package/stack-template/app/ui-kit/src/ui/image/index.tsx +76 -0
  465. package/stack-template/app/ui-kit/src/ui/inplace/index.tsx +33 -0
  466. package/stack-template/app/ui-kit/src/ui/inplace/inplace.stories.tsx +75 -0
  467. package/stack-template/app/ui-kit/src/ui/inplace/inplace.test.tsx +58 -0
  468. package/stack-template/app/ui-kit/src/ui/input/index.tsx +133 -0
  469. package/stack-template/app/ui-kit/src/ui/input/input-search.stories.tsx +112 -0
  470. package/stack-template/app/ui-kit/src/ui/input/input-search.test.tsx +116 -0
  471. package/stack-template/app/ui-kit/src/ui/input/input-search.tsx +116 -0
  472. package/stack-template/app/ui-kit/src/ui/input/input.stories.tsx +176 -0
  473. package/stack-template/app/ui-kit/src/ui/input/input.test.tsx +106 -0
  474. package/stack-template/app/ui-kit/src/ui/input-mask/index.tsx +39 -0
  475. package/stack-template/app/ui-kit/src/ui/input-mask/input-mask.stories.tsx +46 -0
  476. package/stack-template/app/ui-kit/src/ui/input-mask/input-mask.test.tsx +57 -0
  477. package/stack-template/app/ui-kit/src/ui/input-number/index.tsx +125 -0
  478. package/stack-template/app/ui-kit/src/ui/input-number/input-number.stories.tsx +190 -0
  479. package/stack-template/app/ui-kit/src/ui/input-number/input-number.test.tsx +157 -0
  480. package/stack-template/app/ui-kit/src/ui/input-otp/index.tsx +57 -0
  481. package/stack-template/app/ui-kit/src/ui/input-otp/input-otp.stories.tsx +90 -0
  482. package/stack-template/app/ui-kit/src/ui/input-otp/input-otp.test.tsx +66 -0
  483. package/stack-template/app/ui-kit/src/ui/kanban/index.tsx +277 -0
  484. package/stack-template/app/ui-kit/src/ui/kanban/kanban.stories.tsx +219 -0
  485. package/stack-template/app/ui-kit/src/ui/kanban/kanban.test.tsx +234 -0
  486. package/stack-template/app/ui-kit/src/ui/knob/index.tsx +58 -0
  487. package/stack-template/app/ui-kit/src/ui/knob/knob.stories.tsx +49 -0
  488. package/stack-template/app/ui-kit/src/ui/knob/knob.test.tsx +42 -0
  489. package/stack-template/app/ui-kit/src/ui/layout/index.tsx +145 -0
  490. package/stack-template/app/ui-kit/src/ui/layout/layout.stories.tsx +158 -0
  491. package/stack-template/app/ui-kit/src/ui/layout/layout.test.tsx +154 -0
  492. package/stack-template/app/ui-kit/src/ui/link/index.tsx +61 -0
  493. package/stack-template/app/ui-kit/src/ui/link/link.stories.tsx +68 -0
  494. package/stack-template/app/ui-kit/src/ui/link/link.test.tsx +69 -0
  495. package/stack-template/app/ui-kit/src/ui/list/index.tsx +135 -0
  496. package/stack-template/app/ui-kit/src/ui/list/list.stories.tsx +194 -0
  497. package/stack-template/app/ui-kit/src/ui/list/list.test.tsx +164 -0
  498. package/stack-template/app/ui-kit/src/ui/listbox/index.tsx +27 -0
  499. package/stack-template/app/ui-kit/src/ui/listbox/listbox.stories.tsx +57 -0
  500. package/stack-template/app/ui-kit/src/ui/listbox/listbox.test.tsx +49 -0
  501. package/stack-template/app/ui-kit/src/ui/mega-menu/index.tsx +142 -0
  502. package/stack-template/app/ui-kit/src/ui/mega-menu/mega-menu.stories.tsx +137 -0
  503. package/stack-template/app/ui-kit/src/ui/mega-menu/mega-menu.test.tsx +130 -0
  504. package/stack-template/app/ui-kit/src/ui/mention/index.tsx +76 -0
  505. package/stack-template/app/ui-kit/src/ui/mention/mention.stories.tsx +44 -0
  506. package/stack-template/app/ui-kit/src/ui/mention/mention.test.tsx +87 -0
  507. package/stack-template/app/ui-kit/src/ui/menu/index.tsx +256 -0
  508. package/stack-template/app/ui-kit/src/ui/menu/menu.stories.tsx +124 -0
  509. package/stack-template/app/ui-kit/src/ui/menu/menu.test.tsx +251 -0
  510. package/stack-template/app/ui-kit/src/ui/menubar/index.tsx +42 -0
  511. package/stack-template/app/ui-kit/src/ui/menubar/menubar.stories.tsx +66 -0
  512. package/stack-template/app/ui-kit/src/ui/menubar/menubar.test.tsx +65 -0
  513. package/stack-template/app/ui-kit/src/ui/message/index.tsx +123 -0
  514. package/stack-template/app/ui-kit/src/ui/message/message.stories.tsx +104 -0
  515. package/stack-template/app/ui-kit/src/ui/message/message.test.tsx +109 -0
  516. package/stack-template/app/ui-kit/src/ui/modal/index.tsx +142 -0
  517. package/stack-template/app/ui-kit/src/ui/modal/modal.stories.tsx +128 -0
  518. package/stack-template/app/ui-kit/src/ui/modal/modal.test.tsx +166 -0
  519. package/stack-template/app/ui-kit/src/ui/notification/index.tsx +142 -0
  520. package/stack-template/app/ui-kit/src/ui/notification/notification.stories.tsx +155 -0
  521. package/stack-template/app/ui-kit/src/ui/notification/notification.test.tsx +83 -0
  522. package/stack-template/app/ui-kit/src/ui/order-list/index.tsx +38 -0
  523. package/stack-template/app/ui-kit/src/ui/order-list/order-list.stories.tsx +38 -0
  524. package/stack-template/app/ui-kit/src/ui/order-list/order-list.test.tsx +54 -0
  525. package/stack-template/app/ui-kit/src/ui/org-chart/index.tsx +138 -0
  526. package/stack-template/app/ui-kit/src/ui/org-chart/org-chart.stories.tsx +76 -0
  527. package/stack-template/app/ui-kit/src/ui/org-chart/org-chart.test.tsx +98 -0
  528. package/stack-template/app/ui-kit/src/ui/pagination/index.tsx +102 -0
  529. package/stack-template/app/ui-kit/src/ui/pagination/pagination.stories.tsx +103 -0
  530. package/stack-template/app/ui-kit/src/ui/pagination/pagination.test.tsx +112 -0
  531. package/stack-template/app/ui-kit/src/ui/panel-menu/index.tsx +59 -0
  532. package/stack-template/app/ui-kit/src/ui/panel-menu/panel-menu.stories.tsx +96 -0
  533. package/stack-template/app/ui-kit/src/ui/panel-menu/panel-menu.test.tsx +64 -0
  534. package/stack-template/app/ui-kit/src/ui/parallax/index.tsx +62 -0
  535. package/stack-template/app/ui-kit/src/ui/parallax/parallax.stories.tsx +115 -0
  536. package/stack-template/app/ui-kit/src/ui/parallax/parallax.test.tsx +148 -0
  537. package/stack-template/app/ui-kit/src/ui/password/index.tsx +67 -0
  538. package/stack-template/app/ui-kit/src/ui/password/password.stories.tsx +43 -0
  539. package/stack-template/app/ui-kit/src/ui/password/password.test.tsx +45 -0
  540. package/stack-template/app/ui-kit/src/ui/pick-list/index.tsx +103 -0
  541. package/stack-template/app/ui-kit/src/ui/pick-list/pick-list.stories.tsx +59 -0
  542. package/stack-template/app/ui-kit/src/ui/pick-list/pick-list.test.tsx +94 -0
  543. package/stack-template/app/ui-kit/src/ui/popconfirm/index.tsx +102 -0
  544. package/stack-template/app/ui-kit/src/ui/popconfirm/popconfirm.stories.tsx +73 -0
  545. package/stack-template/app/ui-kit/src/ui/popconfirm/popconfirm.test.tsx +127 -0
  546. package/stack-template/app/ui-kit/src/ui/popover/index.tsx +136 -0
  547. package/stack-template/app/ui-kit/src/ui/popover/popover.stories.tsx +114 -0
  548. package/stack-template/app/ui-kit/src/ui/popover/popover.test.tsx +172 -0
  549. package/stack-template/app/ui-kit/src/ui/progress/index.tsx +46 -0
  550. package/stack-template/app/ui-kit/src/ui/progress/progress.stories.tsx +57 -0
  551. package/stack-template/app/ui-kit/src/ui/progress/progress.test.tsx +90 -0
  552. package/stack-template/app/ui-kit/src/ui/qr-code/index.tsx +88 -0
  553. package/stack-template/app/ui-kit/src/ui/qr-code/qr-code.stories.tsx +109 -0
  554. package/stack-template/app/ui-kit/src/ui/qr-code/qr-code.test.tsx +155 -0
  555. package/stack-template/app/ui-kit/src/ui/qr-code/qrcode-core.ts +56 -0
  556. package/stack-template/app/ui-kit/src/ui/qr-code/qrcode-generator.vendor.ts +2300 -0
  557. package/stack-template/app/ui-kit/src/ui/radio/index.tsx +62 -0
  558. package/stack-template/app/ui-kit/src/ui/radio/radio.stories.tsx +94 -0
  559. package/stack-template/app/ui-kit/src/ui/radio/radio.test.tsx +83 -0
  560. package/stack-template/app/ui-kit/src/ui/rating/index.tsx +36 -0
  561. package/stack-template/app/ui-kit/src/ui/rating/rating.stories.tsx +42 -0
  562. package/stack-template/app/ui-kit/src/ui/rating/rating.test.tsx +45 -0
  563. package/stack-template/app/ui-kit/src/ui/result/index.tsx +72 -0
  564. package/stack-template/app/ui-kit/src/ui/result/result.stories.tsx +82 -0
  565. package/stack-template/app/ui-kit/src/ui/result/result.test.tsx +57 -0
  566. package/stack-template/app/ui-kit/src/ui/reveal/index.tsx +83 -0
  567. package/stack-template/app/ui-kit/src/ui/reveal/reveal.stories.tsx +91 -0
  568. package/stack-template/app/ui-kit/src/ui/reveal/reveal.test.tsx +148 -0
  569. package/stack-template/app/ui-kit/src/ui/schedule/index.tsx +104 -0
  570. package/stack-template/app/ui-kit/src/ui/schedule/schedule.fc.test.tsx +95 -0
  571. package/stack-template/app/ui-kit/src/ui/schedule/schedule.stories.tsx +61 -0
  572. package/stack-template/app/ui-kit/src/ui/schedule/schedule.test.tsx +41 -0
  573. package/stack-template/app/ui-kit/src/ui/scroll-page/index.tsx +46 -0
  574. package/stack-template/app/ui-kit/src/ui/scroll-page/scroll-page.stories.tsx +92 -0
  575. package/stack-template/app/ui-kit/src/ui/scroll-page/scroll-page.test.tsx +51 -0
  576. package/stack-template/app/ui-kit/src/ui/scroll-panel/index.tsx +16 -0
  577. package/stack-template/app/ui-kit/src/ui/scroll-panel/scroll-panel.stories.tsx +37 -0
  578. package/stack-template/app/ui-kit/src/ui/scroll-panel/scroll-panel.test.tsx +41 -0
  579. package/stack-template/app/ui-kit/src/ui/scrolltop/index.tsx +27 -0
  580. package/stack-template/app/ui-kit/src/ui/scrolltop/scrolltop.stories.tsx +41 -0
  581. package/stack-template/app/ui-kit/src/ui/scrolltop/scrolltop.test.tsx +37 -0
  582. package/stack-template/app/ui-kit/src/ui/segmented/index.tsx +47 -0
  583. package/stack-template/app/ui-kit/src/ui/segmented/segmented.stories.tsx +126 -0
  584. package/stack-template/app/ui-kit/src/ui/segmented/segmented.test.tsx +77 -0
  585. package/stack-template/app/ui-kit/src/ui/select/index.tsx +302 -0
  586. package/stack-template/app/ui-kit/src/ui/select/select.stories.tsx +268 -0
  587. package/stack-template/app/ui-kit/src/ui/select/select.test.tsx +226 -0
  588. package/stack-template/app/ui-kit/src/ui/sidebar/index.tsx +83 -0
  589. package/stack-template/app/ui-kit/src/ui/sidebar/sidebar.stories.tsx +71 -0
  590. package/stack-template/app/ui-kit/src/ui/sidebar/sidebar.test.tsx +101 -0
  591. package/stack-template/app/ui-kit/src/ui/skeleton/index.tsx +55 -0
  592. package/stack-template/app/ui-kit/src/ui/skeleton/skeleton.stories.tsx +110 -0
  593. package/stack-template/app/ui-kit/src/ui/skeleton/skeleton.test.tsx +74 -0
  594. package/stack-template/app/ui-kit/src/ui/slide-menu/index.tsx +103 -0
  595. package/stack-template/app/ui-kit/src/ui/slide-menu/slide-menu.stories.tsx +92 -0
  596. package/stack-template/app/ui-kit/src/ui/slide-menu/slide-menu.test.tsx +120 -0
  597. package/stack-template/app/ui-kit/src/ui/slider/index.tsx +90 -0
  598. package/stack-template/app/ui-kit/src/ui/slider/slider.stories.tsx +60 -0
  599. package/stack-template/app/ui-kit/src/ui/slider/slider.test.tsx +66 -0
  600. package/stack-template/app/ui-kit/src/ui/space/index.tsx +32 -0
  601. package/stack-template/app/ui-kit/src/ui/space/space.stories.tsx +66 -0
  602. package/stack-template/app/ui-kit/src/ui/space/space.test.tsx +56 -0
  603. package/stack-template/app/ui-kit/src/ui/speed-dial/index.tsx +32 -0
  604. package/stack-template/app/ui-kit/src/ui/speed-dial/speed-dial.stories.tsx +34 -0
  605. package/stack-template/app/ui-kit/src/ui/speed-dial/speed-dial.test.tsx +34 -0
  606. package/stack-template/app/ui-kit/src/ui/spinner/index.tsx +74 -0
  607. package/stack-template/app/ui-kit/src/ui/spinner/spinner.stories.tsx +64 -0
  608. package/stack-template/app/ui-kit/src/ui/spinner/spinner.test.tsx +66 -0
  609. package/stack-template/app/ui-kit/src/ui/split-button/index.tsx +155 -0
  610. package/stack-template/app/ui-kit/src/ui/split-button/split-button.stories.tsx +137 -0
  611. package/stack-template/app/ui-kit/src/ui/split-button/split-button.test.tsx +152 -0
  612. package/stack-template/app/ui-kit/src/ui/splitter/index.tsx +49 -0
  613. package/stack-template/app/ui-kit/src/ui/splitter/splitter.stories.tsx +24 -0
  614. package/stack-template/app/ui-kit/src/ui/splitter/splitter.test.tsx +21 -0
  615. package/stack-template/app/ui-kit/src/ui/statistic/index.tsx +28 -0
  616. package/stack-template/app/ui-kit/src/ui/statistic/statistic.stories.tsx +112 -0
  617. package/stack-template/app/ui-kit/src/ui/statistic/statistic.test.tsx +39 -0
  618. package/stack-template/app/ui-kit/src/ui/steps/index.tsx +50 -0
  619. package/stack-template/app/ui-kit/src/ui/steps/steps.stories.tsx +57 -0
  620. package/stack-template/app/ui-kit/src/ui/steps/steps.test.tsx +55 -0
  621. package/stack-template/app/ui-kit/src/ui/switch/index.tsx +87 -0
  622. package/stack-template/app/ui-kit/src/ui/switch/switch.stories.tsx +123 -0
  623. package/stack-template/app/ui-kit/src/ui/switch/switch.test.tsx +98 -0
  624. package/stack-template/app/ui-kit/src/ui/tab-menu/index.tsx +33 -0
  625. package/stack-template/app/ui-kit/src/ui/tab-menu/tab-menu.stories.tsx +49 -0
  626. package/stack-template/app/ui-kit/src/ui/tab-menu/tab-menu.test.tsx +50 -0
  627. package/stack-template/app/ui-kit/src/ui/table/index.tsx +690 -0
  628. package/stack-template/app/ui-kit/src/ui/table/table-advanced.stories.tsx +91 -0
  629. package/stack-template/app/ui-kit/src/ui/table/table-advanced.test.tsx +188 -0
  630. package/stack-template/app/ui-kit/src/ui/table/table-expandable.stories.tsx +91 -0
  631. package/stack-template/app/ui-kit/src/ui/table/table-expandable.test.tsx +143 -0
  632. package/stack-template/app/ui-kit/src/ui/table/table.stories.tsx +342 -0
  633. package/stack-template/app/ui-kit/src/ui/table/table.test.tsx +465 -0
  634. package/stack-template/app/ui-kit/src/ui/table/types.ts +173 -0
  635. package/stack-template/app/ui-kit/src/ui/tabs/index.tsx +118 -0
  636. package/stack-template/app/ui-kit/src/ui/tabs/tabs.stories.tsx +113 -0
  637. package/stack-template/app/ui-kit/src/ui/tabs/tabs.test.tsx +77 -0
  638. package/stack-template/app/ui-kit/src/ui/tag/index.tsx +68 -0
  639. package/stack-template/app/ui-kit/src/ui/tag/tag.stories.tsx +88 -0
  640. package/stack-template/app/ui-kit/src/ui/tag/tag.test.tsx +126 -0
  641. package/stack-template/app/ui-kit/src/ui/team/debt-board/debt-board.stories.tsx +52 -0
  642. package/stack-template/app/ui-kit/src/ui/team/debt-board/debt-board.test.tsx +72 -0
  643. package/stack-template/app/ui-kit/src/ui/team/debt-board/index.tsx +125 -0
  644. package/stack-template/app/ui-kit/src/ui/team/inbox-thread/inbox-thread.stories.tsx +70 -0
  645. package/stack-template/app/ui-kit/src/ui/team/inbox-thread/inbox-thread.test.tsx +56 -0
  646. package/stack-template/app/ui-kit/src/ui/team/inbox-thread/index.tsx +107 -0
  647. package/stack-template/app/ui-kit/src/ui/team/ping-feed/index.tsx +102 -0
  648. package/stack-template/app/ui-kit/src/ui/team/ping-feed/ping-feed.stories.tsx +57 -0
  649. package/stack-template/app/ui-kit/src/ui/team/ping-feed/ping-feed.test.tsx +60 -0
  650. package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/index.tsx +60 -0
  651. package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/stage-pipeline.stories.tsx +68 -0
  652. package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/stage-pipeline.test.tsx +50 -0
  653. package/stack-template/app/ui-kit/src/ui/team/team-dashboard/index.tsx +103 -0
  654. package/stack-template/app/ui-kit/src/ui/team/team-dashboard/team-dashboard.stories.tsx +72 -0
  655. package/stack-template/app/ui-kit/src/ui/team/team-dashboard/team-dashboard.test.tsx +72 -0
  656. package/stack-template/app/ui-kit/src/ui/time-picker/index.tsx +143 -0
  657. package/stack-template/app/ui-kit/src/ui/time-picker/time-picker.stories.tsx +90 -0
  658. package/stack-template/app/ui-kit/src/ui/time-picker/time-picker.test.tsx +64 -0
  659. package/stack-template/app/ui-kit/src/ui/timeline/index.tsx +91 -0
  660. package/stack-template/app/ui-kit/src/ui/timeline/timeline.stories.tsx +209 -0
  661. package/stack-template/app/ui-kit/src/ui/timeline/timeline.test.tsx +116 -0
  662. package/stack-template/app/ui-kit/src/ui/timesheet/index.tsx +277 -0
  663. package/stack-template/app/ui-kit/src/ui/timesheet/timesheet.stories.tsx +97 -0
  664. package/stack-template/app/ui-kit/src/ui/timesheet/timesheet.test.tsx +103 -0
  665. package/stack-template/app/ui-kit/src/ui/toggle-button/index.tsx +28 -0
  666. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.stories.tsx +85 -0
  667. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.test.tsx +97 -0
  668. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.tsx +81 -0
  669. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button.stories.tsx +46 -0
  670. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button.test.tsx +38 -0
  671. package/stack-template/app/ui-kit/src/ui/toolbar/index.tsx +18 -0
  672. package/stack-template/app/ui-kit/src/ui/toolbar/toolbar.stories.tsx +35 -0
  673. package/stack-template/app/ui-kit/src/ui/toolbar/toolbar.test.tsx +11 -0
  674. package/stack-template/app/ui-kit/src/ui/tooltip/index.tsx +61 -0
  675. package/stack-template/app/ui-kit/src/ui/tooltip/tooltip.stories.tsx +81 -0
  676. package/stack-template/app/ui-kit/src/ui/tooltip/tooltip.test.tsx +120 -0
  677. package/stack-template/app/ui-kit/src/ui/tour/index.tsx +210 -0
  678. package/stack-template/app/ui-kit/src/ui/tour/tour.stories.tsx +153 -0
  679. package/stack-template/app/ui-kit/src/ui/tour/tour.test.tsx +131 -0
  680. package/stack-template/app/ui-kit/src/ui/transition/index.tsx +377 -0
  681. package/stack-template/app/ui-kit/src/ui/transition/transition.stories.tsx +254 -0
  682. package/stack-template/app/ui-kit/src/ui/transition/transition.test.tsx +285 -0
  683. package/stack-template/app/ui-kit/src/ui/tree/index.tsx +68 -0
  684. package/stack-template/app/ui-kit/src/ui/tree/tree.stories.tsx +139 -0
  685. package/stack-template/app/ui-kit/src/ui/tree/tree.test.tsx +77 -0
  686. package/stack-template/app/ui-kit/src/ui/tree-select/index.tsx +251 -0
  687. package/stack-template/app/ui-kit/src/ui/tree-select/tree-select.stories.tsx +105 -0
  688. package/stack-template/app/ui-kit/src/ui/tree-select/tree-select.test.tsx +174 -0
  689. package/stack-template/app/ui-kit/src/ui/tree-table/index.tsx +229 -0
  690. package/stack-template/app/ui-kit/src/ui/tree-table/tree-table.stories.tsx +111 -0
  691. package/stack-template/app/ui-kit/src/ui/tree-table/tree-table.test.tsx +137 -0
  692. package/stack-template/app/ui-kit/src/ui/typography/index.tsx +124 -0
  693. package/stack-template/app/ui-kit/src/ui/typography/typography.stories.tsx +65 -0
  694. package/stack-template/app/ui-kit/src/ui/typography/typography.test.tsx +117 -0
  695. package/stack-template/app/ui-kit/src/ui/upload/index.tsx +39 -0
  696. package/stack-template/app/ui-kit/src/ui/upload/upload-core.tsx +204 -0
  697. package/stack-template/app/ui-kit/src/ui/upload/upload-dropzone.tsx +79 -0
  698. package/stack-template/app/ui-kit/src/ui/upload/upload.stories.tsx +67 -0
  699. package/stack-template/app/ui-kit/src/ui/upload/upload.test.tsx +204 -0
  700. package/stack-template/app/ui-kit/src/ui/virtual-scroll/index.tsx +86 -0
  701. package/stack-template/app/ui-kit/src/ui/virtual-scroll/virtual-scroll.stories.tsx +111 -0
  702. package/stack-template/app/ui-kit/src/ui/virtual-scroll/virtual-scroll.test.tsx +125 -0
  703. package/stack-template/app/ui-kit/src/ui/watermark/index.tsx +182 -0
  704. package/stack-template/app/ui-kit/src/ui/watermark/watermark.stories.tsx +96 -0
  705. package/stack-template/app/ui-kit/src/ui/watermark/watermark.test.tsx +120 -0
  706. package/stack-template/app/ui-kit/src/utils/array.test.ts +88 -0
  707. package/stack-template/app/ui-kit/src/utils/array.ts +51 -0
  708. package/stack-template/app/ui-kit/src/utils/dom.test.tsx +69 -0
  709. package/stack-template/app/ui-kit/src/utils/dom.ts +38 -0
  710. package/stack-template/app/ui-kit/src/utils/format.test.ts +63 -0
  711. package/stack-template/app/ui-kit/src/utils/format.ts +81 -0
  712. package/stack-template/app/ui-kit/tests/setup.ts +15 -0
  713. package/stack-template/app/ui-kit/tsconfig.json +18 -0
  714. package/stack-template/app/ui-kit/tsup.config.ts +37 -0
  715. package/stack-template/app/ui-kit/vercel.json +6 -0
  716. package/stack-template/app/ui-kit/vitest.config.ts +22 -0
  717. package/stack-template/contracts/auth/token-contract.md +119 -0
  718. package/stack-template/contracts/auth/users.json +35 -0
  719. package/stack-template/contracts/db/tasks-schema.sql +62 -0
  720. package/stack-template/contracts/events/fixtures/task.assigned.json +11 -0
  721. package/stack-template/contracts/events/fixtures/task.assignment_failed.json +11 -0
  722. package/stack-template/contracts/events/fixtures/task.created.json +12 -0
  723. package/stack-template/contracts/events/fixtures/task.deleted.json +10 -0
  724. package/stack-template/contracts/events/fixtures/task.updated.json +12 -0
  725. package/stack-template/contracts/events/task-events.md +80 -0
  726. package/stack-template/contracts/openapi/activity.yaml +196 -0
  727. package/stack-template/contracts/openapi/auth.yaml +310 -0
  728. package/stack-template/contracts/openapi/tasks.yaml +316 -0
  729. package/stack-template/contracts/openapi/users.yaml +345 -0
  730. package/stack-template/docs/adr/0001-mixed-stack.md +14 -0
  731. package/stack-template/docs/adr/0002-mf-rspack.md +14 -0
  732. package/stack-template/docs/adr/0003-contract-first.md +14 -0
  733. package/stack-template/docs/adr/0004-readonly-schema-tradeoff.md +14 -0
  734. package/stack-template/docs/adr/0005-fail-closed.md +14 -0
  735. package/stack-template/docs/adr/0006-fire-and-forget-events.md +14 -0
  736. package/stack-template/docs/adr/0007-fork-not-upgrade.md +14 -0
  737. package/stack-template/docs/adr/0008-kafka-outbox-saga.md +24 -0
  738. package/stack-template/docs/adr/0009-ui-kit-split.md +39 -0
  739. package/stack-template/docs/adr/README.md +15 -0
  740. package/stack-template/docs/ai/recipes.md +956 -0
  741. package/stack-template/docs/ai/table-Theming.md +25 -0
  742. package/stack-template/docs/ai/table-datadisplay-mz.md +20 -0
  743. package/stack-template/docs/ai/table-feedback.md +20 -0
  744. package/stack-template/docs/ai/table-forms.md +26 -0
  745. package/stack-template/docs/git-flow.md +70 -0
  746. package/stack-template/docs/parity-matrix.md +102 -0
  747. package/stack-template/docs/superpowers/contexts/auth-real/gap-answer.md +195 -0
  748. package/stack-template/docs/superpowers/contexts/auth-real/sf-1.md +21 -0
  749. package/stack-template/docs/superpowers/contexts/auth-real/sf-2.md +21 -0
  750. package/stack-template/docs/superpowers/contexts/auth-real/sf-3.md +17 -0
  751. package/stack-template/docs/superpowers/contexts/auth-real/sf-4.md +20 -0
  752. package/stack-template/docs/superpowers/contexts/auth-real/sf-5.md +21 -0
  753. package/stack-template/docs/superpowers/contexts/experience-design.md +85 -0
  754. package/stack-template/docs/superpowers/contexts/sf-1.md +39 -0
  755. package/stack-template/docs/superpowers/contexts/sf-2.md +42 -0
  756. package/stack-template/docs/superpowers/contexts/sf-3.md +42 -0
  757. package/stack-template/docs/superpowers/contexts/sf-4.md +26 -0
  758. package/stack-template/docs/superpowers/contexts/sf-5.md +36 -0
  759. package/stack-template/docs/superpowers/contexts/sf-6.md +36 -0
  760. package/stack-template/docs/superpowers/contexts/sf-7.md +35 -0
  761. package/stack-template/docs/superpowers/contexts/sf-cin-overview.md +21 -0
  762. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-1.md +46 -0
  763. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-2.md +44 -0
  764. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-3.md +47 -0
  765. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-4.md +44 -0
  766. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-5.md +36 -0
  767. package/stack-template/docs/superpowers/designs/direction-approved.md +11 -0
  768. package/stack-template/docs/superpowers/designs/ui-redesign/drafts/a-roulette-soundviz.html +353 -0
  769. package/stack-template/docs/superpowers/designs/ui-redesign/drafts/b-reference.html +347 -0
  770. package/stack-template/docs/superpowers/designs/ui-redesign/drafts/c-designer.html +375 -0
  771. package/stack-template/docs/superpowers/designs/ui-redesign/ds-demo.html +140 -0
  772. package/stack-template/docs/superpowers/designs/ui-redesign-direction.md +93 -0
  773. package/stack-template/docs/superpowers/improvements-log.md +158 -0
  774. package/stack-template/docs/superpowers/mindmaps/auth-real.wakii +115 -0
  775. package/stack-template/docs/superpowers/mindmaps/kafka-outbox-saga.wakii +110 -0
  776. package/stack-template/docs/superpowers/mindmaps/micro-boilerplate.wakii +171 -0
  777. package/stack-template/docs/superpowers/mindmaps/ui-redesign.wakii +116 -0
  778. package/stack-template/docs/superpowers/mindmaps/vu53-cinematic-experience.wakii +32 -0
  779. package/stack-template/docs/superpowers/plans/2026-10-12-sf-1-contracts-platform-plan.md +44 -0
  780. package/stack-template/docs/superpowers/plans/2026-10-12-sf-3-spring-svc-impact.md +69 -0
  781. package/stack-template/docs/superpowers/plans/2026-10-12-sf-3-spring-svc-plan.md +27 -0
  782. package/stack-template/docs/superpowers/plans/2026-10-12-sf-4-go-svc-plan.md +99 -0
  783. package/stack-template/docs/superpowers/plans/2026-10-12-sf-5-fe-shell-plan.md +64 -0
  784. package/stack-template/docs/superpowers/plans/2026-10-12-sf-6-fe-remotes-plan.md +83 -0
  785. package/stack-template/docs/superpowers/plans/2026-10-12-sf-7-convergence-plan.md +59 -0
  786. package/stack-template/docs/superpowers/plans/2026-10-12-sf2-node-svc-plan.md +19 -0
  787. package/stack-template/docs/superpowers/plans/2026-10-13-sf-1-kafka-foundation-plan.md +30 -0
  788. package/stack-template/docs/superpowers/plans/2026-10-13-sf-1-ui-redesign-plan.md +28 -0
  789. package/stack-template/docs/superpowers/plans/2026-10-13-sf-2-node-outbox-plan.md +46 -0
  790. package/stack-template/docs/superpowers/plans/2026-10-13-sf-3-go-consumer-plan.md +31 -0
  791. package/stack-template/docs/superpowers/plans/2026-10-13-sf-4-spring-tx-plan.md +96 -0
  792. package/stack-template/docs/superpowers/plans/2026-10-13-sf-5-convergence-plan.md +21 -0
  793. package/stack-template/docs/superpowers/plans/2026-10-14-sf-2-ui-redesign-plan.md +32 -0
  794. package/stack-template/docs/superpowers/plans/2026-10-14-sf-3-ui-redesign-plan.md +34 -0
  795. package/stack-template/docs/superpowers/plans/2026-10-14-sf-5-ui-redesign-plan.md +35 -0
  796. package/stack-template/docs/superpowers/plans/2026-10-17-auth-real-plan.md +112 -0
  797. package/stack-template/docs/superpowers/plans/2026-10-17-ui-kit-split-plan.md +18 -0
  798. package/stack-template/docs/superpowers/reviews/2026-10-18-data-display-coverage.md +52 -0
  799. package/stack-template/docs/superpowers/reviews/code-reviewer-sf-5-r1.md +65 -0
  800. package/stack-template/docs/superpowers/reviews/security-audit-sf-5-auth-real.md +39 -0
  801. package/stack-template/docs/superpowers/specs/2026-10-12-boilerplate-microservice-mfe.md +110 -0
  802. package/stack-template/docs/superpowers/specs/2026-10-12-sf-3-spring-svc-design.md +160 -0
  803. package/stack-template/docs/superpowers/specs/2026-10-12-sf-7-convergence-spec.md +114 -0
  804. package/stack-template/docs/superpowers/specs/2026-10-12-sf2-node-svc-spec.md +42 -0
  805. package/stack-template/docs/superpowers/specs/2026-10-13-kafka-outbox-saga.md +111 -0
  806. package/stack-template/docs/superpowers/specs/2026-10-13-ui-redesign.md +173 -0
  807. package/stack-template/docs/superpowers/specs/2026-10-14-sf-3-ui-redesign.md +46 -0
  808. package/stack-template/docs/superpowers/specs/2026-10-14-sf-5-ui-redesign.md +30 -0
  809. package/stack-template/docs/superpowers/specs/2026-10-17-antd-look-tokens.md +28 -0
  810. package/stack-template/docs/superpowers/specs/2026-10-17-auth-real-design.md +124 -0
  811. package/stack-template/docs/superpowers/specs/2026-10-17-tailwind-migration.md +32 -0
  812. package/stack-template/docs/superpowers/specs/2026-10-17-ui-kit-split.md +44 -0
  813. package/stack-template/docs/superpowers/specs/2026-10-18-0.3.0-release-notes.md +77 -0
  814. package/stack-template/docs/toolchain.md +28 -0
  815. package/stack-template/docs/wakii-playbook.md +172 -0
  816. package/stack-template/docs/walkthrough.md +204 -0
  817. package/stack-template/orca.yaml +146 -0
  818. package/stack-template/package.json +19 -0
  819. package/stack-template/platform/.env.example +72 -0
  820. package/stack-template/platform/conventions/01-dockerfile-pattern.md +78 -0
  821. package/stack-template/platform/conventions/02-healthcheck.md +26 -0
  822. package/stack-template/platform/conventions/03-logging.md +41 -0
  823. package/stack-template/platform/conventions/04-error-envelope.md +41 -0
  824. package/stack-template/platform/conventions/05-ports.md +38 -0
  825. package/stack-template/platform/conventions/06-configuration.md +25 -0
  826. package/stack-template/platform/conventions/07-cors.md +23 -0
  827. package/stack-template/platform/conventions/08-gateway-and-remotes.md +33 -0
  828. package/stack-template/platform/conventions/09-async-messaging.md +42 -0
  829. package/stack-template/platform/conventions/README.md +15 -0
  830. package/stack-template/platform/docker-compose.yml +255 -0
  831. package/stack-template/platform/gateway/nginx/nginx.conf +137 -0
  832. package/stack-template/platform/postgres/init/01-init.sh +55 -0
  833. package/stack-template/pnpm-lock.yaml +15992 -0
  834. package/stack-template/pnpm-workspace.yaml +24 -0
  835. package/stack-template/scripts/scaffold/scaffold.sh +110 -0
  836. package/stack-template/scripts/smoke/e2e.sh +305 -0
  837. package/stack-template/scripts/snapshot-stack-template.sh +84 -0
  838. package/stack-template/services/auth-svc/.dockerignore +5 -0
  839. package/stack-template/services/auth-svc/Dockerfile +32 -0
  840. package/stack-template/services/auth-svc/README.md +101 -0
  841. package/stack-template/services/auth-svc/drizzle/0000_init.sql +25 -0
  842. package/stack-template/services/auth-svc/drizzle/meta/0000_snapshot.json +190 -0
  843. package/stack-template/services/auth-svc/drizzle/meta/_journal.json +13 -0
  844. package/stack-template/services/auth-svc/drizzle.config.ts +10 -0
  845. package/stack-template/services/auth-svc/package.json +35 -0
  846. package/stack-template/services/auth-svc/pnpm-lock.yaml +2425 -0
  847. package/stack-template/services/auth-svc/src/app.test.ts +403 -0
  848. package/stack-template/services/auth-svc/src/app.ts +103 -0
  849. package/stack-template/services/auth-svc/src/auth-crypto.test.ts +32 -0
  850. package/stack-template/services/auth-svc/src/auth-crypto.ts +25 -0
  851. package/stack-template/services/auth-svc/src/db/client.ts +24 -0
  852. package/stack-template/services/auth-svc/src/db/migrate.ts +72 -0
  853. package/stack-template/services/auth-svc/src/db/schema.ts +39 -0
  854. package/stack-template/services/auth-svc/src/db/seed.ts +60 -0
  855. package/stack-template/services/auth-svc/src/env.test.ts +55 -0
  856. package/stack-template/services/auth-svc/src/env.ts +57 -0
  857. package/stack-template/services/auth-svc/src/logger.ts +31 -0
  858. package/stack-template/services/auth-svc/src/plugins/auth.ts +70 -0
  859. package/stack-template/services/auth-svc/src/repo.drizzle.integration.test.ts +182 -0
  860. package/stack-template/services/auth-svc/src/repo.drizzle.ts +144 -0
  861. package/stack-template/services/auth-svc/src/repo.test-support.ts +168 -0
  862. package/stack-template/services/auth-svc/src/repo.ts +60 -0
  863. package/stack-template/services/auth-svc/src/routes/auth.ts +193 -0
  864. package/stack-template/services/auth-svc/src/routes/health.ts +40 -0
  865. package/stack-template/services/auth-svc/src/server.ts +54 -0
  866. package/stack-template/services/auth-svc/tsconfig.json +20 -0
  867. package/stack-template/services/go-svc/.dockerignore +5 -0
  868. package/stack-template/services/go-svc/Dockerfile +19 -0
  869. package/stack-template/services/go-svc/README.md +93 -0
  870. package/stack-template/services/go-svc/cmd/server/main.go +105 -0
  871. package/stack-template/services/go-svc/go.mod +12 -0
  872. package/stack-template/services/go-svc/internal/api/auth.go +83 -0
  873. package/stack-template/services/go-svc/internal/api/auth_test.go +92 -0
  874. package/stack-template/services/go-svc/internal/api/envelope.go +61 -0
  875. package/stack-template/services/go-svc/internal/api/envelope_test.go +51 -0
  876. package/stack-template/services/go-svc/internal/api/fakes_test.go +105 -0
  877. package/stack-template/services/go-svc/internal/api/feed.go +98 -0
  878. package/stack-template/services/go-svc/internal/api/feed_test.go +118 -0
  879. package/stack-template/services/go-svc/internal/api/health.go +34 -0
  880. package/stack-template/services/go-svc/internal/api/health_test.go +46 -0
  881. package/stack-template/services/go-svc/internal/api/json.go +13 -0
  882. package/stack-template/services/go-svc/internal/api/middleware.go +82 -0
  883. package/stack-template/services/go-svc/internal/api/middleware_test.go +48 -0
  884. package/stack-template/services/go-svc/internal/api/openapi/activity.yaml +196 -0
  885. package/stack-template/services/go-svc/internal/api/openapi.go +29 -0
  886. package/stack-template/services/go-svc/internal/api/openapi_test.go +38 -0
  887. package/stack-template/services/go-svc/internal/api/router.go +86 -0
  888. package/stack-template/services/go-svc/internal/api/stats.go +63 -0
  889. package/stack-template/services/go-svc/internal/api/stats_test.go +83 -0
  890. package/stack-template/services/go-svc/internal/api/types.go +32 -0
  891. package/stack-template/services/go-svc/internal/apperr/apperr.go +9 -0
  892. package/stack-template/services/go-svc/internal/config/config.go +115 -0
  893. package/stack-template/services/go-svc/internal/config/config_test.go +92 -0
  894. package/stack-template/services/go-svc/internal/consumer/envelope.go +78 -0
  895. package/stack-template/services/go-svc/internal/consumer/envelope_test.go +154 -0
  896. package/stack-template/services/go-svc/internal/consumer/handler.go +91 -0
  897. package/stack-template/services/go-svc/internal/consumer/handler_test.go +136 -0
  898. package/stack-template/services/go-svc/internal/consumer/producer.go +117 -0
  899. package/stack-template/services/go-svc/internal/consumer/runner.go +194 -0
  900. package/stack-template/services/go-svc/internal/consumer/runner_test.go +351 -0
  901. package/stack-template/services/go-svc/internal/logging/logging.go +49 -0
  902. package/stack-template/services/go-svc/internal/model/model.go +37 -0
  903. package/stack-template/services/go-svc/internal/resolve/resolver.go +134 -0
  904. package/stack-template/services/go-svc/internal/resolve/resolver_test.go +82 -0
  905. package/stack-template/services/go-svc/internal/resolve/token.go +130 -0
  906. package/stack-template/services/go-svc/internal/resolve/token_test.go +151 -0
  907. package/stack-template/services/go-svc/internal/store/events.go +71 -0
  908. package/stack-template/services/go-svc/internal/store/migrate.go +90 -0
  909. package/stack-template/services/go-svc/internal/store/migrate_test.go +34 -0
  910. package/stack-template/services/go-svc/internal/store/migrations/0001_create_events.sql +20 -0
  911. package/stack-template/services/go-svc/internal/store/migrations/0002_widen_action_cascade.sql +14 -0
  912. package/stack-template/services/go-svc/internal/store/store.go +65 -0
  913. package/stack-template/services/go-svc/internal/store/tasks.go +109 -0
  914. package/stack-template/services/go-svc/internal/swagger/assets/LICENSE +202 -0
  915. package/stack-template/services/go-svc/internal/swagger/assets/NOTICE +2 -0
  916. package/stack-template/services/go-svc/internal/swagger/assets/favicon-16x16.png +0 -0
  917. package/stack-template/services/go-svc/internal/swagger/assets/favicon-32x32.png +0 -0
  918. package/stack-template/services/go-svc/internal/swagger/assets/swagger-ui-bundle.js +2 -0
  919. package/stack-template/services/go-svc/internal/swagger/assets/swagger-ui.css +3 -0
  920. package/stack-template/services/go-svc/internal/swagger/index.html +28 -0
  921. package/stack-template/services/go-svc/internal/swagger/swagger.go +38 -0
  922. package/stack-template/services/go-svc/test/integration/integration_test.go +523 -0
  923. package/stack-template/services/node-svc/.dockerignore +5 -0
  924. package/stack-template/services/node-svc/Dockerfile +27 -0
  925. package/stack-template/services/node-svc/README.md +155 -0
  926. package/stack-template/services/node-svc/drizzle/0000_init.sql +17 -0
  927. package/stack-template/services/node-svc/drizzle/0001_status-assignment-failed.sql +2 -0
  928. package/stack-template/services/node-svc/drizzle/0002_outbox-table.sql +7 -0
  929. package/stack-template/services/node-svc/drizzle/meta/0000_snapshot.json +136 -0
  930. package/stack-template/services/node-svc/drizzle/meta/0001_snapshot.json +136 -0
  931. package/stack-template/services/node-svc/drizzle/meta/0002_snapshot.json +180 -0
  932. package/stack-template/services/node-svc/drizzle/meta/_journal.json +27 -0
  933. package/stack-template/services/node-svc/drizzle.config.ts +10 -0
  934. package/stack-template/services/node-svc/package.json +39 -0
  935. package/stack-template/services/node-svc/pnpm-lock.yaml +2706 -0
  936. package/stack-template/services/node-svc/src/app.test.ts +611 -0
  937. package/stack-template/services/node-svc/src/app.ts +126 -0
  938. package/stack-template/services/node-svc/src/clients/spring.ts +53 -0
  939. package/stack-template/services/node-svc/src/compensation-consumer.test.ts +157 -0
  940. package/stack-template/services/node-svc/src/compensation-consumer.ts +170 -0
  941. package/stack-template/services/node-svc/src/db/client.ts +23 -0
  942. package/stack-template/services/node-svc/src/db/migrate.ts +63 -0
  943. package/stack-template/services/node-svc/src/db/schema-diff.test.ts +252 -0
  944. package/stack-template/services/node-svc/src/db/schema.ts +64 -0
  945. package/stack-template/services/node-svc/src/env.ts +52 -0
  946. package/stack-template/services/node-svc/src/logger.ts +18 -0
  947. package/stack-template/services/node-svc/src/outbox-relay.test.ts +141 -0
  948. package/stack-template/services/node-svc/src/outbox-relay.ts +182 -0
  949. package/stack-template/services/node-svc/src/plugins/auth.ts +76 -0
  950. package/stack-template/services/node-svc/src/repo.drizzle.test.ts +182 -0
  951. package/stack-template/services/node-svc/src/repo.drizzle.ts +158 -0
  952. package/stack-template/services/node-svc/src/repo.ts +73 -0
  953. package/stack-template/services/node-svc/src/routes/health.ts +42 -0
  954. package/stack-template/services/node-svc/src/routes/tasks.ts +287 -0
  955. package/stack-template/services/node-svc/src/server.ts +91 -0
  956. package/stack-template/services/node-svc/src/types/api.d.ts +391 -0
  957. package/stack-template/services/node-svc/src/types/log.ts +3 -0
  958. package/stack-template/services/node-svc/tsconfig.json +20 -0
  959. package/stack-template/services/spring-svc/.dockerignore +5 -0
  960. package/stack-template/services/spring-svc/.mvn/wrapper/maven-wrapper.properties +20 -0
  961. package/stack-template/services/spring-svc/Dockerfile +22 -0
  962. package/stack-template/services/spring-svc/README.md +121 -0
  963. package/stack-template/services/spring-svc/mvnw +332 -0
  964. package/stack-template/services/spring-svc/mvnw.cmd +206 -0
  965. package/stack-template/services/spring-svc/pom.xml +144 -0
  966. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/SpringSvcApplication.java +12 -0
  967. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/Team.java +64 -0
  968. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/TeamRepository.java +34 -0
  969. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/User.java +72 -0
  970. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/UserRepository.java +10 -0
  971. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/logging/LowercaseLevelJsonProvider.java +24 -0
  972. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/security/JwtAuthFilter.java +89 -0
  973. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/security/JwtVerifier.java +48 -0
  974. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/service/TeamService.java +84 -0
  975. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ApiError.java +15 -0
  976. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ApiException.java +37 -0
  977. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/DevCorsConfig.java +41 -0
  978. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ErrorEnvelope.java +27 -0
  979. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/GlobalExceptionHandler.java +90 -0
  980. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/HealthController.java +46 -0
  981. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ReadinessService.java +40 -0
  982. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/TeamController.java +79 -0
  983. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/UserController.java +187 -0
  984. package/stack-template/services/spring-svc/src/main/java/db/migration/V2__SeedUsers.java +66 -0
  985. package/stack-template/services/spring-svc/src/main/resources/application.yml +42 -0
  986. package/stack-template/services/spring-svc/src/main/resources/db/migration/V1__init.sql +24 -0
  987. package/stack-template/services/spring-svc/src/main/resources/logback-spring.xml +34 -0
  988. package/stack-template/services/spring-svc/src/main/resources/openapi/users.yaml +345 -0
  989. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/logging/LogShapeTest.java +39 -0
  990. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/security/JwtAuthFilterTest.java +106 -0
  991. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/seed/SeedMatchIntegrationTest.java +68 -0
  992. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/service/TeamServiceRollbackTest.java +122 -0
  993. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/DevCorsTest.java +45 -0
  994. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/HealthCheckTest.java +56 -0
  995. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/TeamApiTest.java +139 -0
  996. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/TestPingController.java +21 -0
  997. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/UserApiTest.java +182 -0
  998. package/stack-template/stack-manifest.json +285 -0
@@ -0,0 +1,112 @@
1
+ # Auth Real — Implementation Plan (epic auth thật thay auth-mock) — rev 2
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Thay auth-mock bằng auth-svc thật — register/login/refresh(rotation CAS)/logout + RBAC demo, giữ nguyên surface `:8090 /api/auth/*`.
6
+
7
+ **Architecture:** CC archetype (wakii-playbook §2): SF-1 contracts là hiệp ước → SF-2/3/4 song song theo vùng file → SF-5 hội tụ + decommission + **CI swap**. auth-svc mirror node-svc patterns.
8
+
9
+ **Tech Stack:** Fastify 5 · TypeScript · Drizzle (Postgres) · argon2 · HS256 verify giữ nguyên (`iss` **PINNED `"auth-mock"`** — đổi = follow-up riêng) · vitest/node-test.
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-10-17-auth-real-design.md` **rev 2** — ĐỌC TRƯỚC: 10 decision points (7-10 thêm từ spec-critic + plan-critic: iss pinned, response shape v2, giữ GET /users drop openid, password default demo-password).
12
+
13
+ ---
14
+
15
+ ### Task 1 = SF-1 (tier 0): Contracts + hiệp ước + gap-answer ĐẦY ĐỦ
16
+
17
+ **Files:**
18
+ - Modify: `contracts/openapi/auth.yaml` (v2 — 5 endpoint mới + giữ `GET /users` + **xoá `/.well-known/openid-configuration`** + response shape v2)
19
+ - Modify: `contracts/auth/token-contract.md` (v2 — chi tiết dưới)
20
+ - Modify: `platform/.env.example` (+`AUTH_DEV_PASSWORD` default **`demo-password`** theo pattern `${VAR:-demo-password}`; +`ACCESS_TOKEN_TTL=30m`; **rename `AUTH_MOCK_PORT`→`AUTH_PORT`, `AUTH_MOCK_DEV_PASSWORD`→`AUTH_DEV_PASSWORD`**)
21
+ - Modify: `.github/workflows/contracts.yml` — **schemathesis scope hẹp lại**: chỉ chạy paths auth-mock đang implement (paths mới thêm sẽ 404 → job đỏ oan). Exclude `register|refresh|logout` khỏi include-path đến SF-5
22
+ - Prepare (KHÔNG commit — gap-answer doc cho coordinator duyệt, SF-5 thực thi): compose entry `auth-mock`→`auth-svc` + key `gateway.depends_on.auth-mock`→`auth-svc` + nginx upstream + go-svc env `AUTH_MOCK_URL` value → `http://auth-svc:8090` + users.json volume mount cho auth-svc + init 01-init.sh thêm role `auth_svc`/schema `auth` + `AUTH_SVC_DB_PASSWORD`
23
+
24
+ - [x] **Step 1: auth.yaml** — schemas `RegisterRequest{email,password(minLength 8,maxLength 72),displayName}`, `TokenPair{accessToken,refreshToken}`, `RefreshRequest{refreshToken}`; paths `POST /register|/login|/refresh|/logout|/logout-all`; **response login/register = `{user: UserRef, accessToken, refreshToken}` — DROP `tokenType`/`expiresIn` (decision #8, KHÔNG thuần additive)**; `GET /users` giữ (description: serve từ schema auth); xoá discovery stub + cập nhật disclaimer header.
25
+ - [x] **Step 2: mirror healthz/readyz** dưới prefix `/api/auth/` (conventions/02 rule 6).
26
+ - [x] **Step 3: token-contract.md v2** — access TTL `30m`; refresh: opaque 256-bit, **lưu sha256 hash**, TTL **7d**, rotation **CAS atomic** (`UPDATE ... WHERE id=$old AND revoked_at IS NULL RETURNING` — 0 rows = reuse), **reuse → revoke TẤT CẢ refresh_tokens của user + 401** (strict; FE single-flight giảm xác suất — documented); `iss` **PINNED `"auth-mock"`** (3 service + CI hardcode — đổi tên là follow-up riêng); `localStorage['bp.rt']` rationale pin (accepted-for-demo, httpOnly-cookie = upgrade path); ghi "RS256/JWKS = path OIDC, claims không đổi".
27
+ - [x] **Step 4: .env.example** — như Files ở trên (default `demo-password` — KHÔNG `change-me-*`: e2e + svc-activity + seed cùng một nguồn, acceptance #3 phụ thuộc).
28
+ - [x] **Step 5: soạn gap-answer doc đầy đủ** (list ở Files — 8 mục) → FLAG coordinator duyệt. KHÔNG commit compose/nginx/init trong SF-1.
29
+ - [x] **Step 6: Verify** — `pnpm lint:contracts` xanh; CI `contracts` xanh với schemathesis SCOPED (verify job không 404).
30
+
31
+ ### Task 2 = SF-2 (tier 1, song song — vùng `services/auth-svc/**` mới + 2 shared files 1 dòng): auth-svc
32
+
33
+ **Files:**
34
+ - Create: `services/auth-svc/` (mirror node-svc: src/{db,plugins,routes}, drizzle/, Dockerfile, README, `.github/workflows/services-auth-svc.yml` từ workflow-templates)
35
+ - Modify: `pnpm-workspace.yaml` (+`- "services/auth-svc"` — 1 dòng, SF-3/SF-4 không đụng file này → an toàn song song)
36
+ - Modify: `pnpm-lock.yaml` (install sinh)
37
+
38
+ - [x] **Step 1: khung boot** — mirror node-svc: env/logger/JWT plugin (**verify issuer giữ literal `"auth-mock"`**)/envelope (HttpError.statusCode, pino cast) + `/healthz` `/readyz` naked+prefix. `drizzle.config.ts` schema `auth`.
39
+ - [x] **Step 2: migration 0000 + seed** — SQL như spec §Kiến trúc (`roles text[] NOT NULL DEFAULT '{"user"}'`); seed từ users.json giữ UUID, `password_hash = argon2id(AUTH_DEV_PASSWORD)`, idempotent `ON CONFLICT (id) DO NOTHING`.
40
+ - [x] **Step 3: TDD rotation/reuse (RED trước)** —
41
+
42
+ ```ts
43
+ // refresh lần 1 (CAS): old.revoked_at != null + cặp mới + replaced_by=old.id
44
+ // 2 request CAS cùng old id: 1 thắng, 1 về 0-rows → reuse-detect
45
+ // reuse old sau rotate: 401 + TẤT CẢ refresh_tokens user bị revoked_at != null
46
+ // logout trên token đã revoked: 204 (idempotent)
47
+ ```
48
+ Rotation query: `UPDATE auth.refresh_tokens SET revoked_at=now(), replaced_by=$new WHERE id=$old AND revoked_at IS NULL RETURNING *` — 0 rows → reuse-detect: `UPDATE ... SET revoked_at=now() WHERE user_id=$u AND revoked_at IS NULL` + 401. Hash sha256, KHÔNG lưu raw.
49
+ - [x] **Step 4: 5 endpoints** — register (argon2id; email lowercase-normalize; 409 UNIQUE; password 8–72), login (sign HS256 TTL `ACCESS_TOKEN_TTL`, iss `"auth-mock"`, + refresh `crypto.randomBytes(32)`), refresh (CAS + reuse-detect), logout (204 idempotent), logout-all (Bearer sub). Envelope conventions/04; không log password/refreshToken.
50
+ - [x] **Step 5: Verify** — `pnpm --filter auth-svc test` 37/37 (27 unit + 10 integration postgres thật, XANH trên DB fresh ×2 — executor + reviewer tự chạy); `docker build` OK; boot-smoke chuỗi register→refresh→reuse→401→logout PASS **trên image**. ⚠️ "Workflow xanh trên nhánh": GitHub Actions **disabled repo-wide** (`gh api …/actions/permissions → enabled:false`, 10/10 workflows `disabled_manually` — không push nào fire CI) → chứng minh = 3 jobs chạy tương đương local; coordinator enable Actions (hoặc để SF-5 CI swap) → re-run để có run xanh thật. Chi tiết `docs/superpowers/evidence/sf-2-auth-real/test-run.txt`.
51
+
52
+ ### Task 3 = SF-3 (tier 1, song song — vùng `services/node-svc/**`): RBAC demo
53
+
54
+ **Files:**
55
+ - Modify: `services/node-svc/src/plugins/auth.ts` (verify request.user có roles — decode hiện có)
56
+ - Modify: `services/node-svc/src/routes/tasks.ts` (DELETE guard)
57
+ - Test: `services/node-svc/src/app.test.ts`
58
+
59
+ - [x] **Step 1: RED** — test DELETE với token roles `["user"]` → 403 `{code:"FORBIDDEN"}`; alice (admin) → 200. Chạy FAIL.
60
+ - [x] **Step 2: guard** — preHandler DELETE: `if (!user.roles?.includes('admin')) throw createError(403, 'FORBIDDEN', 'Chỉ admin được xoá task')`.
61
+ - [x] **Step 3: GREEN** — suite node xanh (e2e.sh hiện tại KHÔNG có bước DELETE — compat mặc nhiên đúng, không cần assert gì thêm ở SF-3).
62
+ - [x] **Step 4: Verify** — `pnpm --filter node-svc test && pnpm --filter node-svc build`.
63
+
64
+ *(SF-3 nhỏ hơn chuẩn 8-15 steps — giữ riêng vì vùng file tách bạch là trục song song với SF-2/4; chạy tier co-giãn Standard.)*
65
+
66
+ ### Task 4 = SF-4 (tier 1, song song — vùng `app/shared/src/refresh-client.ts` mới + `app/shell/**`): FE refresh wrapper
67
+
68
+ **Files:**
69
+ - Create: `app/shared/src/refresh-client.ts` + export qua `index.ts`
70
+ - Modify: `app/shell/src/pages/LoginPage.tsx` (+tab Register; response v2 shape — không còn tokenType/expiresIn) · `app/shell/src/api.ts`
71
+ - Test: `app/shell/tests/` (mock fetch)
72
+
73
+ - [x] **Step 1: refresh-client API** —
74
+
75
+ ```ts
76
+ export interface AuthSession { accessToken: string; refreshToken: string; }
77
+ export async function login(email: string, password: string): Promise<AuthSession>;
78
+ export async function register(email: string, password: string, displayName: string): Promise<AuthSession>;
79
+ // 401 → refresh ĐÚNG MỘT LẦN (single-flight promise lock) → retry
80
+ export async function withRefresh<T>(fn: (token: string) => Promise<T>): Promise<T>;
81
+ export async function logout(): Promise<void>; // revoke + clear 2 key
82
+ ```
83
+ Access → `tokenStorage` (API có sẵn); refresh → `localStorage['bp.rt']` (rationale pin token-contract.md).
84
+ - [x] **Step 2: tests** — mock fetch: login/register lưu cặp đúng key; 401 → /refresh đúng 1 lần → retry OK; refresh cũng 401 → clear 2 key + throw Unauthorized; logout revoke + clear.
85
+ - [x] **Step 3: LoginPage** — tab Login/Register; response v2 shape; lỗi 401/409 theo messages contract.
86
+ - [x] **Step 4: Verify** — `pnpm --filter shell test && typecheck`; **coverage gate đúng ngưỡng config (lines/statements/branches 90, functions 80)**; **a11y test** (tab/form mới phải qua suite a11y sẵn có).
87
+
88
+ ### Task 5 = SF-5 (tier 2): Convergence + decommission + CI swap + docs
89
+
90
+ **Files:**
91
+ - Modify: `scripts/smoke/e2e.sh` (+bước auth-real: register→refresh→reuse→401→logout; đánh số lại — **bảo toàn contract: exit N = fail bước N (<255), marker `SAGA_TASK_ID=`, `SMOKE_SAGA=0` vẫn exit 0**)
92
+ - Modify: `platform/docker-compose.yml` + `platform/gateway/nginx/nginx.conf` + `platform/postgres/init/01-init.sh` + go-svc env — **thực thi gap-answer SF-1 đã duyệt** (8 mục)
93
+ - Modify: `.github/workflows/contracts.yml` (boot auth-svc thay auth-mock; nới schemathesis full) + `services-go-svc.yml` + `services-spring-svc.yml` (boot auth-svc)
94
+ - Modify: docs — `walkthrough.md` (+register/refresh flow + gotcha `down -v` + sync "số bước PASS"), `CLAUDE.md` (auth-mock → auth-svc), `orca.yaml` (services entry auth-svc + gotcha down-v + test_all + auth-svc), `README.md`, `docs/toolchain.md`
95
+ - Delete: `platform/auth-mock/`
96
+ - Modify: `platform/.env.example` (đồng bộ rename đã làm ở SF-1 — nếu conflict thì merge)
97
+
98
+ - [x] **Step 1: decommission** — xoá `platform/auth-mock/` + entry compose (kèm `depends_on` key) + upstream nginx + go-svc env value; boot compose (volume MỚI hoặc `down -v`): auth-svc healthcheck xanh thay vị trí cũ.
99
+ - [x] **Step 2: e2e mở rộng** — sau login: register `smoke-<ts>@demo.local` → refresh → reuse old → 401 → logout → register user roles `["user"]` DELETE task → 403; alice DELETE → 200.
100
+ - [x] **Step 3: CI swap** — 3 workflow boot auth-svc; contracts.yml nới schemathesis full paths; **toàn bộ CI main phải xanh sau merge** (acceptance #9).
101
+ - [x] **Step 4: docs sync CÙNG commit** — list ở Files; grep `auth-mock` = rỗng trên: docs/*.md, CLAUDE.md, orca.yaml, README.md, .env.example, .github/workflows/ (token-contract.md + users.json $comment giữ note lịch sử nếu muốn — ghi rõ).
102
+ - [x] **Step 5: Full suite + security pass + human walkthrough 2 tab** (register→login→tab 2→logout-all→tab 1 chết ở request kế tiếp) — evidence `docs/superpowers/evidence/auth-real/`.
103
+
104
+ ---
105
+
106
+ ## Ràng buộc xuyên suốt (rev 2)
107
+
108
+ - Contracts TRƯỚC code; `iss` **PINNED `"auth-mock"`** — mọi verify/serving giữ nguyên giá trị; drift-guard activity.yaml không liên quan.
109
+ - users.json: KHÔNG thêm password; UUID không đổi; `$comment` ghi mapping password → `AUTH_DEV_PASSWORD` (update $comment thuộc SF-5 docs).
110
+ - Gateway/compose/init/workspace/CI = shared files: SF-1 soạn gap-answer → coordinator duyệt → SF thực thi đúng mục sở hữu; KHÔNG 2 SF cùng đụng 1 shared file trong 1 tier.
111
+ - Mỗi SF: evidence `docs/superpowers/evidence/auth-real/sf-N/` + test-run.txt ghi HEAD tại code-commit cuối; story-verify B1–B3; executor không merge — dest → main qua PR (git-flow).
112
+ - TDD: RED→GREEN từng behavior; `tdd: skipped-tdd: CI-only <lý do>` nếu cần.
@@ -0,0 +1,18 @@
1
+ # Plan: ui-kit split + Storybook Phase 1
2
+
3
+ Spec: `docs/superpowers/specs/2026-10-17-ui-kit-split.md` · Nhánh: `__STACK_ORG__/ui-kit-split` · 2026-10-17
4
+
5
+ | # | Task | Exit criteria |
6
+ |---|------|---------------|
7
+ | T1 | Spec + plan (docs này) | Được duyệt trong chat, committed |
8
+ | T2 | `app/ui-kit`: git mv `src/ui` + `src/styles` từ shared; package.json (qua source, exports `.` + `./styles/*.css`); src/index.ts barrel; env.d.ts; tsconfig; vitest.config + tests/setup; **move** `primitives.test.tsx` từ shell/tests; README | `pnpm --filter @wakii/ui-kit test && typecheck` PASS |
9
+ | T3 | `app/shared` slim: package.json bỏ exports `./ui` + `./styles/*`; index.ts bỏ re-export ui; README rewrite (logic-only, pointer ui-kit); 4 file logic KHÔNG đụng (READ-LOCKED) | shared typecheck đứng yên OK; không còn `src/ui` |
10
+ | T4 | Consumers đổi imports: shell (bootstrap css, RemoteSlot Skeleton, pages nếu có, tests, package.json +dep), remote-tasks (TasksPage EmptyState/Skeleton + tokens.css, TaskItem Spinner, standalone.tsx, api.test? chỉ UI imports, package.json), remote-activity (tương tự) | grep `fe-shared` còn đúng logic-only; suites shell 43/tasks 36/activity 22 PASS; typecheck + build ×3 OK |
11
+ | T5 | `pnpm install` (lockfile: importer ui-kit + deps consumers) → frozen PASS sau đó | install --frozen-lockfile PASS |
12
+ | T6 | Dockerfiles ×3: COPY app/ui-kit (package.json trước, full sau) | `docker compose build shell tasks activity` PASS |
13
+ | T7 | convergence copy-dir: typecheck standalone fe-shared + ui-kit (mini workspace catalog + @types/react + --jsx) | local repro EXIT=0 cả hai |
14
+ | T8 | CI `ui-kit.yml`: typecheck + test + build-storybook, paths `app/ui-kit/**` | workflow yaml parse + chạy xanh trên push |
15
+ | T9 | Storybook: `.storybook/{main,preview}.ts` (react-vite + addon-docs, preview import tokens+base); stories: Badge 9 variants, EmptyState/Skeleton/Spinner states, Tokens docs page; script `build-storybook` | `pnpm --filter @wakii/ui-kit build-storybook` PASS; dev screenshot evidence |
16
+ | T10 | ADR-0009 + sync descriptor: CLAUDE.md (READ-LOCKED + docs map + CI bảng), orca.yaml (frontend.shared/ui-kit), agents/fe-dev, scaffold SCAFFOLD.md, README root | descriptor khớp thực tế; review pass |
17
+
18
+ Thứ tự: T2→T3→T4→T5 (core, verify mỗi bước) → T6/T7/T8 (infra) → T9 (storybook) → T10 (docs). Merge main sau khi toàn bộ xanh + CI收敛.
@@ -0,0 +1,52 @@
1
+ # Case-coverage audit — Data Display cluster (2026-10-18)
2
+
3
+ Worker V2 · đối chiếu benchmark antd / MUI / PrimeReact cho 20 component data-display.
4
+ Hành động: **bổ API + stories EN + tests hành vi** cho case benchmark quan trọng còn thiếu.
5
+ Verify: vitest cluster **23 file / 240 tests PASS** · eslint cụm **0 errors** · tsc: 0 lỗi ở file sửa.
6
+
7
+ ## Bảng tổng hợp
8
+
9
+ | Component | Case benchmark (antd/MUI/PrimeReact) | Đã có trước | Đã bổ đợt này | Còn tồn + lý do |
10
+ |---|---|---|---|---|
11
+ | Avatar | src fallback onError, size/shape, icon | children/initials, src, alt, size, shape | **onError fallback** — src fail → initials (API + test `fireEvent.error` + story `BrokenSrcFallback`) | icon prop riêng (initials đủ) |
12
+ | AvatarGroup | max +N tooltip, overlap, per-avatar tooltip | đầy đủ benchmark lite | — | — |
13
+ | Badge | count, overflowCount 99+, showZero, dot, offset, status×5 + text | variant pill ×9 (task/activity) | **count mode**: `count`·`overflowCount`·`showZero`·`dot`·`offset`·`status`+`text` (API + 8 tests + 4 stories EN) | color preset tùy ý (variant map đủ hệ tokens) |
14
+ | Card | cover, actions, hoverable, loading, size, type inner, Meta | cover, actions, hoverable, bordered, extra | **`loading`** (skeleton body, aria-busy) + **`size="small"`** (dense padding) — tests + 2 stories EN | `type="inner"` (Card lồng + className đạt được), `Meta` composite — backlog |
15
+ | Carousel | autoplay, dots, navigators, keyboard, vertical, per-view, pauseOnHover | đầy đủ benchmark lite | — | effect `fade` (chỉ slide) — backlog |
16
+ | Collapse | accordion, disabled item, controlled keys, ghost | items, defaultActiveKeys | **`accordion`** + per-item **`disabled`** (tests + 2 stories EN) | controlled `activeKeys` (uncontrolled đủ recipe) · ghost/extra — backlog |
17
+ | Descriptions | bordered, colon, size, column, layout, span | bordered, title, items | **`size="small"`** + **`colon`** (tests + 1 story EN) | `column` nhiều cột + layout vertical + span — backlog lớn (ghi trong file) |
18
+ | Divider | type, dashed, orientation left/right | type, dashed, children-center | **`orientation="left|right|center"`** (tests + 1 story EN) | `plain` — giá trị thấp |
19
+ | EmptyState | title/description/action/custom image | đầy đủ benchmark lite | — | — |
20
+ | Galleria | indicators, thumbnails, fullscreen, caption, autoplay | images + dot indicators cơ bản | — | thumbnails/fullscreen/autoplay — heavy backlog |
21
+ | Image | preview, fallback onError, placeholder, group | preview overlay ✓ | — KHÔNG ĐỤNG (W8 đang viết lại stories) | fallback onError + PreviewGroup — chờ W8 xong |
22
+ | List | renderItem, pagination, loading, grid, actions/meta | renderItem, pagination, loading+EmptyState | — KHÔNG ĐỤNG (S đang thêm virtual) | grid mode — backlog |
23
+ | Segmented | options disabled, size, block | options/value/onChange | **per-option `disabled`** (test hành vi; stories bị giữ — không thêm story) | `size`/`block` — backlog nhỏ |
24
+ | Skeleton | variant×5, count, active, compose | variant×5 + count + classNames slots | — | — |
25
+ | Statistic | precision, separator, loading, countdown | title/value/prefix/suffix/valueStyle | — | `precision`/`separator` (cần quyết format locale) · countdown — component riêng |
26
+ | Table | fixed header, summary, frozen cols, virtual, expandable, selection | fixed header ✓ (scrollHeight + sticky — story 7 + test có sẵn), frozen ✓, virtual ✓, filter/sort/pagination ✓ | — KHÔNG ĐỤNG index/types (worker khác đang WIP `expandable`) | **`summary` row** — cần API mới, bị chặn tranh chấp file; làm ngay sau khi expandable merge |
27
+ | Tabs | type card, position, closable, disabled tab | items, activeKey, classNames slots | — KHÔNG ĐỤNG stories (session khác giữ) | disabled tab + type card + closable — backlog |
28
+ | Tag | color preset, closable, Checkable, icon | closable, Checkable, icon ✓ | — | color preset mở rộng — cần quyết design tokens |
29
+ | Timeline | mode left/right/alternate, pending, reverse, label | items color/label (label dưới content) | **`mode`** ×3 (label column, alternate parity antd) + **`pending`** (hollow dot) — 5 tests + 2 stories EN | `reverse` — nhỏ, đợt sau |
30
+ | Tree | showLine, checkable, draggable, selectedKeys | data/expand/click | **`showLine`** connector borders (API + 2 tests + 1 story EN) | checkable + draggable + selectedKeys — backlog lớn (ghi rõ trong comment file) |
31
+
32
+ ## File tranh chấp — tôn trọng trong đợt này
33
+
34
+ - `list/index.tsx` — S (virtual WIP) · `image/image.stories.tsx` — W8 (ảnh thật) · `select.stories.tsx` — L
35
+ - `table/index.tsx` + `table/types.tsx` — worker khác đang thêm `expandable` (phát hiện qua git status, không có trong cảnh báo ban đầu)
36
+ - `segmented/skeleton/tabs.stories.tsx` — M bởi session khác → chỉ bổ API + test, không đụng stories
37
+
38
+ ## Verify (paste)
39
+
40
+ ```
41
+ Test Files 23 passed (23)
42
+ Tests 240 passed (240)
43
+ Duration 4.82s
44
+ (vitest run: badge card timeline tree avatar avatar-group collapse divider
45
+ descriptions segmented table statistic tag tabs skeleton empty-state
46
+ carousel galleria list image)
47
+
48
+ npx eslint <cụm> → 0 errors
49
+ npx tsc --noEmit → 0 lỗi ở mọi file đợt này
50
+ (còn 6 lỗi TS ở src/KitchenSink.stories.tsx — file untracked tạo 16:51 bởi
51
+ session khác: thiếu import Paragraph/Slider, onChange setState — không thuộc đợt)
52
+ ```
@@ -0,0 +1,65 @@
1
+ # Code Review round 1 — SF-5 (VU-64) (outbox từ code-reviewer agent, 2026-10-17)
2
+
3
+ Scope: ce9ce7e..560694d (a494dab chính + b64d872 comment + 560694d security). 43 files, +282/-1337.
4
+ Coverage 43/43 file (bảng đầy đủ trong transcript agent); các vị trí position-verified tại HEAD.
5
+
6
+ ## P1 (1)
7
+ - [P1][high] e2e.sh exit-code collision — vi phạm contract "exit N = fail bước N" mà commit tự
8
+ tuyên bố bảo toàn: fail 7 ×6 (bước 6 stats VÀ bước 7 register), fail 8 (refresh VÀ saga
9
+ create/PATCH), fail 9 (reuse VÀ saga poll), fail 10 (logout VÀ DLQ); header claim "exit tới 15"
10
+ sai (max thực tế 12). Fix đề xuất: exit = nhãn + 1 tới 16 + sửa header.
11
+
12
+ ## P2 (5)
13
+ - walkthrough.md:50 "alice 200" — script assert 204 (tasks.yaml)
14
+ - .claude/agents/e2e-runner.md:36 "PASS = 8 bước" — giờ 15
15
+ - app/shell/README.md:13 env cũ AUTH_MOCK_DEV_PASSWORD (đã rename AUTH_DEV_PASSWORD từ SF-1)
16
+ - README.md:21 mermaid authsvc còn trong subgraph platform; :7 header "6 services" không nhắc auth
17
+ - contracts.yml:91-93 register curl thiếu --max-time (pattern-consistent, không chặn)
18
+
19
+ ## Deterministic (reviewer tự chạy lại)
20
+ bash -n SYNTAX-OK · compose config -q OK · init set -euo pipefail + đủ env ở 3 CI caller ·
21
+ Dockerfile node:22-alpine có wget · ci.compose.override.yml không tham chiếu auth-mock ·
22
+ token extraction shape-v2-safe (spring jq/go json.load/contracts sed) · convergence pipefail có ·
23
+ repo-wide auth-mock residue đúng ranh giới (iss-pinned + historical + services README stale
24
+ [go README:37 AUTH_MOCK_DEV_PASSWORD, spring README:12 TTL 8h — follow-up coordinator]).
25
+
26
+ ## CHECKLIST-4Q
27
+ Q1 PASS (0 dòng service code; init SQL thuần 1 heredoc) · Q2 PASS (e2e CURL --max-time 5;
28
+ contracts register thiếu max-time = P2) · Q3 PASS (DLQ best-effort in stderr + ủy quyền CI qua
29
+ marker; logout-204-on-revoked là contract chủ đích) · Q4 PASS (user smoke-<ts> tồn lại by-design;
30
+ không partial-fail mới).
31
+
32
+ VERDICT: CHANGES-REQUESTED — P1: e2e.sh exit codes trùng — renumber unique + sửa header.
33
+
34
+ ## Disposition (executor, commit 4cb0912)
35
+ P1: renumber theo rule exit = label+1 (register→8 … DLQ→16), header "exit = label+1 (tới 16,
36
+ unique từng bước)". Meta-test: grep fail N — mỗi code đúng 1 block; e2e re-run 15/15 PASS.
37
+ Cả 5 P2 fix cùng commit. → re-review round 2.
38
+
39
+ ---
40
+
41
+ # Code Review round 2 — RE-REVIEW (2026-10-17)
42
+
43
+ Scope delta: 560694d..4cb0912 (9 files). Full story diff: ce9ce7e..4cb0912.
44
+
45
+ ## P1 r1 — ĐÃ ĐÓNG (position-verified tại HEAD)
46
+ Mapping exit-code unique đúng rule exit = nhãn+1: 1=prereq · 2=ready · 3=login · 4=baseline ·
47
+ 5=create · 6=feed · 7=stats · 8=register · 9=refresh · 10=reuse · 11=logout · 12=RBAC-user ·
48
+ 13=RBAC-alice · 14=saga · 15=poll · 16=DLQ. Header đúng sự thật. Meta-test reviewer tự chạy:
49
+ grep uniq per block ✓ + e2e 15/15 exit 0.
50
+
51
+ ## P2 r1 — cả 5 ĐÃ ĐÓNG (walkthrough 204 / e2e-runner 15 bước / shell README env /
52
+ README mermaid+header / contracts --max-time 10).
53
+
54
+ ## 3 file thêm trong 4cb0912 soi riêng: improvements-log (learnings đúng format) ·
55
+ plan.md (CHỈ tick, KHÔNG rewrite prose sai — audit-trail sạch) · evidence walkthrough (out of scope code).
56
+
57
+ ## CHECKLIST-4Q (round 2)
58
+ Q1 PASS · Q2 PASS (--max-time 5 + 10; poll 3) · Q3 PASS (DLQ best-effort + marker CI) · Q4 PASS.
59
+
60
+ Follow-up ngoài SF-5 (coordinator): services/{go,spring,node}-svc README stale
61
+ (AUTH_MOCK_DEV_PASSWORD / TTL 8h / auth-mock) — ngoài touch map READ-ONLY; gom cụm iss-rename
62
+ hoặc docs-hygiene.
63
+
64
+ VERDICT: APPROVED — P1 + 5 P2 đã đóng đều position-verified, mapping exit-code unique đúng
65
+ rule, không finding mới trong 4cb0912.
@@ -0,0 +1,39 @@
1
+ # Security Audit — SF-5 auth-real VU-59/VU-64 (outbox từ security-audit agent, 2026-10-17)
2
+
3
+ ## Executive Summary
4
+ **Overall Risk**: Low · **Vulnerabilities Found**: 4 (0 Critical, 0 High, 4 P2 hygiene/defense-in-depth)
5
+ **Kết luận acceptance**: **PASS** — **0 P0 / 0 P1**. Diff là thuần expose/swap (auth-mock → auth-svc):
6
+ compose entry, postgres init role, nginx upstream, CI swap, e2e mở rộng 15 bước, docs sync.
7
+ Không có code auth-svc trong diff (của SF trước, đúng phạm vi). 5 quyết định đã-accepted
8
+ (localStorage bp.rt / iss pinned / AUTH_DEV_PASSWORD default / gateway presence-check /
9
+ schemathesis full) đều verify đúng ghi nhận — không reopen.
10
+
11
+ ## A1–A6
12
+ - **A1 heredoc injection (01-init.sh:24)**: vector cú pháp CÓ, không attacker-reachable (input = .env operator
13
+ + CI hardcode); password chứa `'` → ON_ERROR_STOP fail-closed. Pattern tiền-existing ×5 role → P2-1.
14
+ - **A2 temp files + leak**: trap ĐỦ (REGISTER_BODY/REFRESH_BODY/RBAC_403_BODY init trước trap, đủ trong rm -f);
15
+ bước 9/10 `-o /dev/null`; say không in token. Lỗ hẹp: fail-branch cat body register/refresh nếu service
16
+ buggy trả success-code-sai kèm token → **P2-2** (cùng pattern contracts.yml:93).
17
+ - **A3 secret leak trong log/healthcheck**: sạch — healthcheck probe không secret, không shell tracing,
18
+ login response không in. `echo "$PAYLOAD"` in JWT claims (không signature) ra CI log → **P2-3**.
19
+ - **A4 docs mở lỗ**: walkthrough 4a hướng dẫn dán token vào curl → shell history (bp.rt dài hạn) → **P2-4**.
20
+ - **A5 RBAC assert**: ĐỦ — 403 status + envelope FORBIDDEN + alice 204; CI coverage qua convergence e2e.
21
+ - **A6 exposure auth_svc/cross-schema**: sạch — GRANT chỉ schema auth, search_path auth, users.json :ro
22
+ không password, PG16 thu hồi CREATE public khỏi PUBLIC.
23
+
24
+ ## P2 (đề xuất fix)
25
+ | ID | Issue | Location |
26
+ |---|---|---|
27
+ | P2-1 | SQL literal breakout qua password chứa `'` (fail-closed, operator-controlled) | platform/postgres/init/01-init.sh:24 |
28
+ | P2-2 | Fail-branch cat body register/refresh có thể in token nếu service buggy | scripts/smoke/e2e.sh:172,183 + contracts.yml:93 |
29
+ | P2-3 | echo JWT claims ra CI log (không signature — hygiene) | contracts.yml:100 |
30
+ | P2-4 | Docs demo dán token vào curl → shell history | docs/walkthrough.md:111-114 |
31
+
32
+ Repo-hygiene: 0 .env/pem/key trong diff; exec-bit 0; không chmod/sudo/curl|sh; lockfile chỉ XOÁ (auth-mock).
33
+
34
+ ## Disposition (executor, commit 560694d)
35
+ Cả 4 P2 đã fix: P2-2 fail-branch in field-names thay body (e2e.sh + contracts.yml, + rm /tmp/reg.json);
36
+ P2-3 bỏ echo payload; P2-4 mẫu read -rs + unset; P2-1 comment ràng buộc quote (psql :'var' binding cho
37
+ cả 5 role = follow-up — fix 1/5 role thôi sẽ lệch style trong cùng file).
38
+
39
+ VERDICT: FINDINGS — P0: 0 · P1: 0 · P2: 4 — sạch cho acceptance SF-5
@@ -0,0 +1,110 @@
1
+ # Epic Spec — Boilerplate Microservice + Micro-frontend
2
+
3
+ > Story: pending epic ID · tạo 2026-10-12 · pipeline: story-workflow CREATE
4
+ > Rev 2 — sau spec-critic vòng 1 (NO-GO): sửa 2 P0 (fe-shared ownership, activity event flow) + 7 P1 (auth claims, seed users, failure semantics, schema grants, standalone-copy, gateway topology, smoke/scaffold semantics)
5
+ > Rev 3 — sau plan-critic (NO-GO): P0 canonical tasks DDL + edge SF-7→SF-3; P1 compose pre-seed (không 3 SF cùng sửa compose), boot-smoke CI per service, event-push fire-and-forget, CORS dev có chủ, spike fe-shared ở SF-1, grant qua default privileges, users fixture chung, smoke = script committed, exit criteria CI-verifiable
6
+ > Repo: `__STACK_ORG__/architecture-overview` (greenfield — chỉ README, 1 commit)
7
+
8
+ ## IDEA-BRIEF (8 chiều)
9
+
10
+ - **Task**: Phát triển boilerplate (khung mẫu copy-able) cho kiến trúc microservice + micro-frontend: contracts → platform → 3 services polyglot → FE shell + remotes → convergence + scaffold.
11
+ - **Output**: Cây thư mục code trong repo này — `docker compose up` (hoặc chạy native từng service) cho demo end-to-end qua browser; CI GitHub Actions xanh.
12
+ - **Users**: Dev team nội bộ — copy boilerplate để khởi tạo dự án mới; fresh-clone walkthrough checklist phải chạy được từ đầu đến cuối (SF-7).
13
+ - **Constraints**: Mixed-stack (Node/TS + Spring Boot + Go, mỗi stack 1 service); Module Federation 2.0 (Rspack, KHÔNG trộn bundler); multi-repo convention trong 1 repo (mỗi thư mục con = repo-con độc lập tooling, contract = OpenAPI contract-first); mock JWT + điểm cắm OIDC (không Keycloak thật); Docker Compose + CI cơ bản, k8s out-of-scope.
14
+ - **Input**: Không Figma, không code cũ. Domain sample: **task management**.
15
+ - **Context**: README hiện tại chỉ có docs Mermaid; Docker KHÔNG có trên dev machine (verify docker build qua CI; local demo chạy native); GH Actions enabled, quyền ADMIN.
16
+ - **Success criteria**: (1) `docker compose up` (trên CI/máy có Docker) → mở shell → login mock → CRUD task → activity feed — xuyên 3 service qua nginx gateway. (2) CI path-filtered xanh (build + test + docker build per stack). (3) Mỗi repo-con copy ra dùng độc lập được (kèm `frontend/shared` nếu nó import shared). (4) Scaffold script sinh project mới từ boilerplate, cùng flow chạy được.
17
+ - **Out-of-scope**: k8s/Helm; Keycloak thật; sản phẩm task management thật (chỉ sample đủ demo); message broker (Kafka…) — inter-service dùng REST sync; mobile app; i18n.
18
+
19
+ ## Quyết định đã chốt (user, 2026-10-12)
20
+
21
+ | # | Quyết định | Chọn |
22
+ |---|---|---|
23
+ | 1 | Mục đích | Template nội bộ + sample e2e |
24
+ | 2 | Stack BE | Mixed: Node/TS + Spring Boot + Go (mỗi stack 1 service) |
25
+ | 3 | Micro-frontend | Module Federation (Rspack + @module-federation/enhanced) |
26
+ | 4 | Layout | Multi-repo convention — FE một phía, services một phía |
27
+ | 5 | Infra | Docker Compose + GitHub Actions CI; k8s out-of-scope |
28
+ | 6 | Nơi đặt | Repo này (mỗi thành phần = thư mục con = repo-con) |
29
+ | 7 | Auth | Mock JWT + điểm cắm OIDC |
30
+
31
+ Tự quyết theo conventions (ADR ghi ở SF-7): JDK 21 + Spring Boot 3.x (Web MVC, không reactive); Node 22 LTS + pnpm; Go 1.24.x + chi; React 19; Rspack (không Vite-MF); drizzle-orm (node-svc); Flyway (spring-svc); go-svc serve OpenAPI spec + swagger-ui static; Postgres 16 dùng chung (mỗi service 1 schema + migration); nginx gateway-lite; sample domain = task management; 1 story 7 SF, phased-release 3 phase.
32
+
33
+ ## Kiến trúc sample (e2e flow chứng minh)
34
+
35
+ ```
36
+ Browser → nginx gateway :8080
37
+ ├─ / → shell static (MF host)
38
+ ├─ /remotes/* → remote static (mỗi remote 1 nginx container riêng, remoteEntry.js)
39
+ └─ /api/* → services
40
+ ├─ /api/tasks/* → node-svc :3001 (task CRUD, Postgres schema `tasks`)
41
+ │ └─ sau khi mutate task: POST /api/activity/events → go-svc (event "task.created")
42
+ ├─ /api/users/* → spring-svc :8081 (users + teams CRUD, Postgres schema `users`)
43
+ │ └─ node-svc gọi REST validate user (timeout 2s; spring down → 503 fail-closed, ADR ghi phương án degrade)
44
+ └─ /api/activity/* → go-svc :8082 (feed + stats; OWNS schema `activity` migration;
45
+ ĐỌC-ONLY schema `tasks` qua postgres readonly role — grants cấp bởi compose init script SF-1)
46
+ Auth: auth-mock cấp JWT HS256 (claims: sub = user id spring, email, roles; TTL 8h; secret chia qua
47
+ compose env .env không-commit). Enforcement 2 lớp: gateway chặn thiếu-token (401), từng service
48
+ TỰ verify signature + expiry (không tin gateway). Token contract file trong contracts/.
49
+ ```
50
+
51
+ Contract-first: `contracts/openapi/*.yaml` (tasks, users, activity, auth) là source of truth duy nhất cho API surface; **`contracts/db/tasks-schema.sql` là canonical DDL cho bảng `tasks`** — interface chung thật sự giữa node-svc (migration phải sinh ra đúng DDL) và go-svc (stats query theo đúng DDL); **`contracts/auth/users.json` là fixture users chung** — auth-mock và seed migration spring đọc CÙNG file. Mỗi service codegen models từ OpenAPI (không gen full client); CI lint (spectral) + contract test (schemathesis). Event push node→go là **fire-and-forget**: fail → JSON log warn, KHÔNG chặn mutation task, KHÔNG retry (ADR ghi trade-off).
52
+
53
+ ## SF split (7 SF — rubric C1-C5/V1-V3, anti-duplicate áp dụng)
54
+
55
+ ### Phase 1 — backend demo được (checkpoint: compose/CI build xanh + swagger + contract test)
56
+
57
+ **SF-1 · Contracts & Platform Foundation** (tier 0, ~16 tasks — deliberate bottleneck, trade-off ghi ADR: tách fe-shared thành SF riêng không đáng thêm 1 handoff)
58
+ - OpenAPI specs (tasks, users, activity — **event payload + feed response chứa đủ user-display fields FE cần render**, auth) + spectral rules + contract-test scaffold (schemathesis)
59
+ - **Canonical DDL** `contracts/db/tasks-schema.sql` (bảng `tasks` — nguồn cho migration node-svc và query go-svc)
60
+ - **Users fixture** `contracts/auth/users.json` (auth-mock + seed spring đọc chung)
61
+ - **Auth token contract file**: claims (sub/email/roles), TTL, secret phân phối, enforcement 2 lớp — commit trong `contracts/`
62
+ - Conventions pack: Dockerfile multi-stage pattern, healthcheck `/healthz`+`/readyz`, JSON log shape, error envelope, **port table (đủ: 3 svc + auth-mock + shell + 2 remotes dev + prod)**, env config qua env-var, **CORS dev-profile rule**
63
+ - **Gateway routing table** (`/` shell, `/remotes/*`, `/api/*`) + **remote registry** (tên MF remote + URL dev/prod, env-configurable)
64
+ - docker-compose **PRE-SEED đủ khung 3 services + postgres + nginx + auth-mock** (env inventory đầy đủ trong `.env.example`; **SF-2/3/4 KHÔNG sửa compose — chỉ điền impl**); postgres init script: tạo schemas + readonly role go-svc dùng **`ALTER DEFAULT PRIVILEGES IN SCHEMA tasks`** (grant vẫn hiệu lực khi bảng sinh sau bởi migration)
65
+ - nginx gateway config; auth-mock service (đọc users fixture)
66
+ - **`frontend/shared` (fe-shared)**: api client wrapper, MF bootstrap helper, token storage; kèm **spike tối thiểu hello-world remote load được** để pin React 19 + @module-federation/enhanced + Rspack CÓ CĂN CỨ ở tier 0; `pnpm-workspace.yaml` globs khai báo đủ `frontend/*`
67
+ - `.gitignore`/`.gitattributes` (eol=lf)/`.editorconfig`
68
+ - CI templates: path-filtered per service + **boot-smoke job pattern (container up + curl `/healthz` + `/readyz` + migration chạy xong)** + gitleaks
69
+ - README cập nhật kiến trúc thật
70
+
71
+ **SF-2 · node-svc — task API** (tier 1, ~9 tasks): Fastify+TS, codegen models, CRUD tasks, validate user qua spring-svc (timeout 2s, fail-closed 503), migration sinh đúng canonical DDL (exit: diff schema vs `contracts/db/tasks-schema.sql` = 0), push event fire-and-forget (log warn khi go-svc down), healthcheck, JSON logging, CORS dev-profile, tests (unit + contract), Dockerfile, **boot-smoke CI job**, swagger, README standalone (exit: docs đủ — chứng minh copy-dir là việc SF-7).
72
+
73
+ **SF-3 · spring-svc — user API** (tier 1, ~9 tasks): Spring Boot 3 Web MVC, users + teams CRUD, **seed migration đọc `contracts/auth/users.json`** (exit: id trùng khớp fixture), Postgres schema `users` + Flyway, healthcheck (actuator + `/readyz`), logback JSON shape chung, CORS dev-profile, tests (@SpringBootTest + contract), Dockerfile multi-stage với mvnw, **boot-smoke CI job**, swagger, README standalone.
74
+
75
+ **SF-4 · go-svc — activity API** (tier 1, ~9 tasks): Go 1.24 + chi, activity feed + stats (query theo canonical DDL), schema `activity` MÌNH migrate, nhận `POST /activity/events` (contract activity), healthcheck, slog JSON shape chung, CORS dev-profile, tests (unit + contract), Dockerfile multi-stage distroless, **boot-smoke CI job**, swagger-ui static, README standalone. **Exit criterion chứng minh readonly đọc được: seed rows bằng owner role → stats trả về đúng.**
76
+
77
+ ### Phase 2 — FE demo được (checkpoint: shell chạy, 2 remote load, gọi service thật qua gateway)
78
+
79
+ **SF-5 · FE shell — MF host** (tier 2, ~9 tasks): Rspack + @module-federation/enhanced host; **task đầu: re-validation spike của SF-1 + fe-shared fit-check** (export API đủ dùng cho shell chưa — lệch phát hiện sớm, không giữa run); pnpm catalog ép singleton deps; routing + layout + nav; login mock JWT (dùng token-storage + api client từ `frontend/shared`); a11y baseline **có test**: route focus + skip link (vitest); error boundary + fallback khi remote load fail; tests; Dockerfile (nginx static); compose entry đã pre-seed — SF-5 chỉ điền impl + **boot-smoke CI job**; README standalone.
80
+
81
+ **SF-6 · FE remotes — tasks + activity** (tier 2, ~10 tasks): 2 remote apps cùng pattern; remote `tasks`: danh sách + tạo/sửa task (gọi node-svc qua gateway `/api/tasks`, đính JWT); remote `activity`: feed + stats (`/api/activity`); **cả hai import shared utilities từ `frontend/shared` (READ-ONLY với SF-6 — SF-1 sở hữu, sửa = flag)**; shared singletons theo catalog; mỗi remote tests + Dockerfile + compose impl (pre-seeded) + **boot-smoke CI job** + README standalone. Remote URLs đọc từ remote registry (env); dev server proxy theo conventions (native mode không cần CORS mở vì đi qua dev proxy). *Lưu ý vận hành: SF-5 ∥ SF-6 cùng regenerate root `pnpm-lock.yaml` — coordinator resolve theo checklist (lấy 1 phía + `pnpm install` lại), không gộp tay.*
82
+
83
+ **`frontend/shared` (fe-shared)**: package riêng, repo-con thứ 7, **SF-1 sở hữu** (api client wrapper, MF bootstrap helper, token storage, catalog). Standalone-copy định nghĩa: remote/shell copy KÈM fe-shared. — Đây là sửa P0-1 (spec-critic): không còn import chéo shell↔remote, không có dependency edge ẩn trong tier 2.
84
+
85
+ ### Phase 3 — convergence (checkpoint: STORY-COMPLETE candidates)
86
+
87
+ **SF-7 · Convergence & Scaffold** (tier 3, ~10 tasks; **depends-on: SF-5, SF-6, VÀ TƯỜM MINH SF-2, SF-3, SF-4** — smoke chain login→tạo task→đọc feed cần đủ 3 service sống): compose e2e smoke **API-level qua gateway — script committed `scripts/smoke/e2e.sh` + CI job** (curl: login → tạo task → đọc feed), không ad-hoc tại checkpoint; browser walkthrough là human gate tại checkpoint, không vào CI; CI hoàn chỉnh (path-filter + docker build per stack + contract test + gitleaks + copy-dir standalone smoke: copy 1 service + fe-shared ra tmp → build/test); docs đồng bộ (README Mermaid = kiến trúc thật + ADR các quyết định + toolchain doc + fresh-clone walkthrough); scaffold script `scripts/scaffold/` (copy + rename + prune, không generator framework) — **Acceptance #7 yêu cầu script chạy được; nếu trễ thì scope-flag lên user, KHÔNG auto-complete bằng manual fallback**; security-audit checkpoint (secrets/exec-bit/lockfile); rà multi-stage + pinned base images.
88
+
89
+ ## Phased-release
90
+
91
+ - Phase 1 COMPLETE = SF-1..4 merged + compose build xanh (CI) + swagger demo + contract test pass → **RELEASE CHECKPOINT 1** (security-audit gồm trong checkpoint).
92
+ - Phase 2 COMPLETE = SF-5..6 merged + shell demo 2 remote (local native dev servers nếu chưa có Docker) → **CHECKPOINT 2**.
93
+ - Phase 3 COMPLETE → STORY-COMPLETE candidates.
94
+
95
+ ## Acceptance (epic-level, user-visible)
96
+
97
+ 1. Mở shell trong browser → login (mock user) → thấy nav + 2 remote render.
98
+ 2. Tạo task mới → hiện trong danh sách (đi qua node-svc, user được spring-svc validate).
99
+ 3. Mở activity → thấy feed/stats phản ánh task vừa tạo (node-svc push event sang go-svc).
100
+ 4. Toàn bộ request đi qua nginx gateway :8080 một cổng duy nhất; gateway chặn thiếu-token; service tự verify JWT (sai/hết hạn → 401 từ service).
101
+ 5. Push → CI xanh: lint contract, test per service, build docker image per stack, **smoke e2e API-level**.
102
+ 6. Copy một repo-con (service hoặc FE kèm `frontend/shared`) ra dùng riêng được theo README của nó — **CI có job copy-dir smoke chứng minh**.
103
+ 7. Scaffold script sinh project mới (đổi tên) chạy được cùng flow e2e.
104
+
105
+ ## Boundary epic-level
106
+
107
+ - Không merge vào `main` — mọi thứ trên nhánh đích `story-<epic-id>-micro-boilerplate`, PR do NGƯỜI merge.
108
+ - Docker không có trên dev machine: mọi verify docker qua CI; local demo = native per-service. Nếu user cài Docker Desktop giữa chừng → verify lại compose local trước checkpoint.
109
+ - Thiếu JDK/Go local: build/test Java+Go chạy trong Docker (CI) hoặc toolchain-in-Docker local; mvnw đi kèm spring-svc.
110
+ - `frontend/shared` chỉ SF-1 sửa; SF-5/6 tiêu thụ READ-ONLY (đụng = flag lên coordinator).
@@ -0,0 +1,160 @@
1
+ # Spec — SF-3 spring-svc — user API (Spring Boot 3) (FI-71)
2
+
3
+ > Story FI-62 · epic spec rev 3 · slice: `docs/superpowers/contexts/sf-3.md` · impact: `docs/superpowers/plans/2026-10-12-sf-3-spring-svc-impact.md`
4
+ > Status: Approved — brainstorm autonomous (brief FI-62: decisions đã chốt ở epic, KHÔNG hỏi lại; SF slice của spec rev 3 đã qua spec-critic + plan-critic 2 vòng ở epic level).
5
+
6
+ ## 0. Root cause / strategy
7
+
8
+ Không có service nào sở hữu users/teams → node-svc không validate được assignee (acceptance #2 gãy),
9
+ JWT service-side enforcement (acceptance #4) chưa chứng minh. Chiến lược: **contract-first slice** —
10
+ impl đúng `contracts/openapi/users.yaml`, seed đọc file fixture thật, verify bằng CI (không Docker/JDK local).
11
+
12
+ ## 1. Problem
13
+
14
+ spring-svc = source-of-truth users/teams cho toàn hệ thống. Auth-mock cấp JWT với `sub` = id fixture;
15
+ mọi consumer tin rằng id đó tồn tại trong DB của spring-svc. Thiếu spring-svc → 2 acceptance gãy.
16
+
17
+ ## 2. Scope
18
+
19
+ **In**: scaffold Spring Boot 3 Web MVC + mvnw; codegen models (maven plugin, types); CRUD users + teams
20
+ đúng contract; Flyway (DDL + seed Java migration đọc `USERS_FIXTURE_PATH`); JWT HS256 service-side verify;
21
+ healthz/readyz + actuator liveness; logback JSON; error envelope; CORS dev-profile; tests
22
+ (@SpringBootTest trên Postgres thật trong CI + seed-id-match assert); Dockerfile multi-stage;
23
+ CI workflow (build-test + docker-build + boot-smoke + drift-guard); README; snapshot `users.yaml` trong build context.
24
+
25
+ **Out**: node-svc/go-svc/FE; Keycloak; compose/conventions/contracts edits; DELETE endpoints (contract không có);
26
+ copy-dir proof (SF-7); scaffold script.
27
+
28
+ **Success criteria (CI-verifiable)**:
29
+ 1. CI `services-spring-svc` xanh: build-test (mvnw verify trên Postgres service container), docker-build, boot-smoke (up + healthz/readyz 200 `{"status":"ok"}` + login auth-mock → GET fixture user 200 + no-token/garbage-token → 401 TỪ SERVICE direct :8081).
30
+ 2. Seed-id-match test: DB ids == fixture ids 100% (assert trong test, đọc cùng file contracts/auth/users.json).
31
+ 3. Swagger UI mở được qua host port 8081 (`/swagger-ui/index.html`); api-docs JSON chứa đúng FINAL path
32
+ table §4.5 (`/api/users/users`, `/api/users/teams`, …) — chứng minh mount khớp contract.
33
+ 4. mvnw wrapper hoạt động trong CI Linux (toolchain path chính); README ghi rõ.
34
+
35
+ ## 3. Touch map
36
+
37
+ Xem impact doc mục 2. Sở hữu: `services/spring-svc/**`, `.github/workflows/services-spring-svc.yml`,
38
+ `docs/superpowers/evidence/sf-3/**`, snapshot `services/spring-svc/src/main/resources/openapi/users.yaml`.
39
+
40
+ ## 4. Design
41
+
42
+ ### 4.1 Stack & layout
43
+ - Spring Boot **3.5.x** (Web MVC, không reactive), **Java 21**, Maven wrapper 3.3.x (script-only, tự tải).
44
+ - Package: `com.example.springsvc` (template-neutral, copy-able).
45
+ - Deps: web, data-jpa, validation, actuator, flyway (+flyway-database-postgresql), postgresql (runtime),
46
+ jjwt 0.12.x (api/impl/jackson), logstash-logback-encoder, springdoc-openapi 2.8.x, openapi-generator-maven-plugin.
47
+ - Tên bảng/cột snake_case khớp DDL tự viết (Hibernate `ddl-auto: none` — Flyway là schema owner).
48
+
49
+ ### 4.2 Codegen + snapshot drift-guard
50
+ Docker context = `services/spring-svc` (compose `build: ../services/spring-svc`) — không thấy `contracts/`.
51
+ → commit **snapshot BIT-IDENTICAL** `src/main/resources/openapi/users.yaml` — KHÔNG thêm comment/header
52
+ trong file YAML (thêm = drift-guard fail ngay run đầu); provenance + quy tắc sync ghi ở README.md.
53
+ Plugin: generatorName `spring`, `interfaceOnly=true, skipDefaultInterface=true, useSpringBoot3=true,
54
+ useTags=true, openApiNullable=false, useBeanValidation=true` → models (`api.model`) + API interfaces (`api`)
55
+ — controllers implement interface → compile-error nếu lệch contract signature. (ADR 1 dòng: slice viết
56
+ "types only" — interfaceOnly là supersét, models + interface mapping, giữ contract-sync compile-time;
57
+ base-path mặc định `${openapi.usersAPI.base-path:/api/users}` verify lúc task 1 context-load.)
58
+
59
+ ### 4.3 Schema & seed
60
+ ```sql
61
+ -- V1__init.sql (schema users qua role search_path — init script SF-1 đã SET search_path = users)
62
+ CREATE TABLE users (id uuid PRIMARY KEY, email varchar(255) NOT NULL UNIQUE,
63
+ display_name varchar(255) NOT NULL, roles text[] NOT NULL);
64
+ CREATE TABLE teams (id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name varchar(255) NOT NULL);
65
+ CREATE TABLE team_members (team_id uuid NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
66
+ user_id uuid NOT NULL, PRIMARY KEY (team_id, user_id));
67
+ ```
68
+ - **V2__SeedUsers.java** (Flyway `BaseJavaMigration`): đọc env `USERS_FIXTURE_PATH` (compose mount
69
+ `/app/contracts/auth/users.json`; native `../../contracts/auth/users.json`), parse Jackson với
70
+ `FAIL_ON_UNKNOWN_PROPERTIES=false` (fixture có key `$comment`), insert
71
+ qua JDBC (`createArrayOf("text")` cho roles). Thiếu/sai file → fail migration → fail boot (fail-fast, conventions/06).
72
+ Fixture evolution: thêm user vào fixture SAU khi V2 đã applied → V3 migration riêng (README ADR ghi quy trình).
73
+ - Compose entry đã inject mọi env cần (verified) — KHÔNG sửa compose.
74
+
75
+ ### 4.4 JWT enforcement (lớp 2 — token-contract §4)
76
+ - `JwtVerifier`: jjwt — HS256, `SecretKeySpec(JWT_SECRET UTF-8 bytes)` (khớp node `jsonwebtoken`),
77
+ tự check `exp`, `requireIssuer("auth-mock")`. `JWT_SECRET` thiếu → fail-fast lúc boot.
78
+ - `JwtAuthFilter` (OncePerRequestFilter): mọi route TRỪ `/healthz`, `/readyz`, `/actuator/**`,
79
+ `/v3/api-docs/**`, `/swagger-ui/**`, VÀ mọi `OPTIONS` preflight (preflight không mang Authorization —
80
+ chặn = CORS native gãy hoàn toàn; có test). Business data không lộ qua swagger docs (chỉ schema tài
81
+ liệu; auth-mock precedent).
82
+ Fail bất kỳ (missing/bad-format/bad-sig/expired/wrong-iss) → **401 envelope** `{error:{code:"UNAUTHORIZED",
83
+ message, requestId}}` — 401 TỪ SERVICE, không tin gateway.
84
+ - ADR (README): filter tự viết thay spring-security resource server — mock 1 secret HS256, điểm cắm OIDC
85
+ = đổi filter sang JWKS/RS256, claims giữ nguyên.
86
+
87
+ ### 4.5 API surface — FINAL PATH TABLE (P0 fix spec-critic: OpenAPI servers.url + path = full path)
88
+ Contract-resolved (khớp gateway pass-through `/api/users/*` + codegen base-path default `/api/users`):
89
+
90
+ | Method | FINAL path (mounted) | Ghi chú |
91
+ |--------|---------------------|---------|
92
+ | GET/POST | `/api/users/users` | list (limit/offset) / create |
93
+ | GET/PATCH | `/api/users/users/{userId}` | get / update |
94
+ | GET/POST | `/api/users/teams` | list / create |
95
+ | GET | `/api/users/teams/{teamId}` | kèm memberIds |
96
+ | GET | `/healthz`, `/readyz` | **naked, hand-written** (conventions/02) — generated `getHealthz/getReadyz` mirror cùng handler (qua gateway sẽ 401 khi thiếu token — bình thường, probe dùng naked) |
97
+
98
+ - ⚠️ `/api/teams` (spec-literal) KHÔNG tồn tại: gateway không route → mọi consumer đi đúng contract path trên.
99
+ - Users behavior: POST thiếu `roles` → default `["user"]` server-side (contract default — codegen không apply
100
+ khi deserialize; test case riêng); PATCH minProperties 1 → 400 nếu body rỗng; `limit` ngoài [1,100] → 400
101
+ (`@Validated` method-validation); POST teams `memberIds` dedupe trước insert (tránh PK violation 500);
102
+ email uniqueness case-sensitive (DB UNIQUE — ghi README; auth-mock login lowercase là đủ demo).
103
+ - Error envelope (conventions/04) qua `@RestControllerAdvice`: 400 VALIDATION_ERROR / 401 UNAUTHORIZED /
104
+ 404 NOT_FOUND / 409 CONFLICT / 500 INTERNAL (không lộ stack); echo `X-Request-Id` vào `requestId` + MDC log.
105
+
106
+ ### 4.6 Health & logging & CORS
107
+ - `/healthz` → `{"status":"ok"}` (shape CỐ ĐỊNH — CI grep); `/readyz` → thật: query `SELECT 1` trên
108
+ DataSource + Flyway applied, fail → 503 envelope; actuator liveness `/actuator/health/liveness` (probes enabled).
109
+ - Logback: `LogstashEncoder` fieldNames `timestamp=ts, message=msg`, customFields `service=spring-svc`,
110
+ MDC `requestId`; `LOG_LEVEL` env → `logging.level.root` (relaxed binding). **Level lowercase** —
111
+ LogstashEncoder mặc định emit `INFO` uppercase, conventions/03 bắt buộc `info`: custom
112
+ `LowercaseLevelJsonProvider` (provider class tự viết ~10 dòng, đăng ký trong logback-spring.xml).
113
+ Không log token; email mask.
114
+ - CORS: `WebMvcConfigurer` bean `@Profile("dev")` — đọc `CORS_DEV_ORIGIN` (comma list), methods
115
+ GET/POST/PATCH, headers Authorization/Content-Type/X-Request-Id. Compose (default profile) → list rỗng →
116
+ không emit ACAO (deny-by-default, conventions/07).
117
+
118
+ ### 4.7 Test strategy (CI = Postgres thật, KHÔNG H2)
119
+ - CI service container `postgres:16-alpine` **mount `platform/postgres/init/`** → init script chạy thật
120
+ — container env PHẢI ĐỦ cho `set -euo pipefail` init: `POSTGRES_USER/PASSWORD/DB` + 4 password
121
+ `NODE_SVC_DB_PASSWORD, SPRING_SVC_DB_PASSWORD, GO_SVC_DB_PASSWORD, GO_READONLY_DB_PASSWORD`, ports 5432:5432.
122
+ Datasource test: `SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/boilerplate`,
123
+ `SPRING_DATASOURCE_USERNAME=spring_svc`, `SPRING_DATASOURCE_PASSWORD=<giá trị SPRING_SVC_DB_PASSWORD env>`.
124
+ - `@SpringBootTest` (webEnvironment MOCK, MockMvc): seed-id-match (đọc `contracts/auth/users.json` thật
125
+ qua `USERS_FIXTURE_PATH`); JWT filter 5 case (valid/expired/garbage/missing/wrong-iss) + OPTIONS preflight
126
+ skip; users API (list/get/post/patch/404/409/400 + POST-no-roles default); teams API (list/get/post +
127
+ duplicate memberIds); healthz/readyz shape; envelope shape.
128
+ - **Test isolation**: CRUD/PATCH tests `@Transactional` (rollback sau mỗi test) → không làm bẩn bảng
129
+ `users`/`teams`; seed-id-match test KHÔNG transactional + chạy độc lập (assert bảng users == fixture).
130
+ - Local không JDK → test chỉ chạy CI (README ghi rõ; toolchain-in-Docker là đường chính theo brief).
131
+
132
+ ### 4.8 Docker & CI
133
+ - Dockerfile theo conventions/01 nguyên văn (deps `dependency:go-offline` → build `package -DskipTests`
134
+ → runtime temurin-21-jre-alpine, USER 1001, EXPOSE 8081). `.dockerignore`: target, .git, test artifacts.
135
+ - `.github/workflows/services-spring-svc.yml` từ template: (1) build-test `./mvnw -B verify` + postgres
136
+ service container (env đủ 4 DB password — §4.7) + init mount + `USERS_FIXTURE_PATH` tuyệt đối;
137
+ (2) docker-build; (3) boot-smoke compose up postgres+auth-mock+spring-svc+gateway → naked healthz/readyz
138
+ → login auth-mock qua gateway → GET `/api/users/users/{aliceId}` 200 → direct :8081 no-token/garbage-token
139
+ → 401; (4) drift-guard snapshot diff.
140
+ - **Path-filter** (`on.push.paths` + `pull_request.paths`): `services/spring-svc/**`, compose entry,
141
+ workflow file, **`contracts/openapi/users.yaml`** (template không có — thêm, để drift-guard không mù khi
142
+ đổi contract mà không đụng spring-svc).
143
+
144
+ ## 5. Impl outline
145
+
146
+ 9 tasks: (1) scaffold+pom+wrapper+codegen; (2) V1 DDL+entities+repos; (3) V2 seed+match-test;
147
+ (4) JWT filter+tests; (5) users API+tests; (6) teams API+tests; (7) health/logging/CORS+tests;
148
+ (8) swagger+Dockerfile+README; (9) CI workflow+evidence. Commit atomically per task, `feat(sf-3): …`.
149
+
150
+ ## 6. Risks & unverified assumptions
151
+
152
+ | # | Risk/assumption | Xử lý |
153
+ |---|-----------------|-------|
154
+ | 1 | Version pin (Boot 3.5.x, springdoc 2.8.x, ogp 7.x) không tồn tại trên Maven Central | Chỉ dùng version đã release trước 6/2026; sai → CI fail rõ ràng, bump 1 lần |
155
+ | 2 | openapi-generator spring + useSpringBoot3 + jjwt/jackson conflict | Generator chỉ emit POJO + annotation; verify ở task 1 (compile green gate) |
156
+ | 3 | Hibernate + `text[]` mapping | `@JdbcTypeCode(SqlTypes.ARRAY)` Hibernate 6.6; seed test chặn ngay task 3 |
157
+ | 4 | Flyway Java migration reflection (no-arg ctor, không thấy Spring beans) | Dùng System.getenv + plain JDBC qua `Context.getConnection()` — đúng API BaseJavaMigration |
158
+ | 5 | JWT interop với auth-mock | Verified: node jsonwebtoken HS256 = UTF-8 bytes; boot-smoke login thật là proof cuối |
159
+ | 6 | CI-only verify loop chậm | Gom test đủ dày mỗi commit; escape-hatch 2-fail-same-cause của workflow |
160
+ | 7 | Codegen base-path không khớp FINAL path table | Verify ngay task 1 (context-load + api-docs paths assertion ở test) |