create-wakii-stack 0.0.0-stage → 0.1.1

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 +391 -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,114 @@
1
+ # SF-7 Spec — Convergence & Scaffold (FI-75)
2
+
3
+ > Story FI-62 · SF-7/7 (tier 3, phase 3/3) · 2026-10-12
4
+ > Source: epic spec rev 3 (`2026-10-12-boilerplate-microservice-mfe.md`) + context pack `docs/superpowers/contexts/sf-7.md`
5
+ > Status: Approved — autonomous mode (epic-level đã qua spec-critic rev 3 + plan-critic; SF slice hội tụ, KHÔNG thêm quyết định mới ngoài epic). Brainstorm self-answered theo Phase 2 mandate.
6
+
7
+ ## 0. Root cause analysis
8
+
9
+ **5 Whys**: Vì sao cần SF-7? → Vì SF-1..6 xây song song, mỗi SF chứng minh phần MÌNH. → Không artifact nào chứng minh CHUỖI 3 service chạy liền mạch như code committed. → Docs viết ở thời SF-1 đã lệch thực tế (README còn nói "khung rỗng"). → Người copy boilerplate không có đường đi từ fresh-clone đến demo chạy được. → Vấn đề thật: **hội tụ + chứng minh + bàn giao**, không phải viết thêm tính năng.
10
+
11
+ Hiện trạng (dest @ec7c3d3): 6 services impl xong + CI per-stack xanh + browser e2e SF-6 verify native; thiếu: smoke script committed, copy-dir proof trong CI, health-gated compose chain, ADR/toolchain/walkthrough, scaffold, security-audit cuối.
12
+
13
+ Chiến lược: **hội tụ tại chỗ** (không re-architect); mọi bug business logic thấy được ở `services/`/`frontend/` = report coordinator, KHÔNG fix (SF sở hữu fix).
14
+
15
+ ## 1. Problem
16
+
17
+ Người mua boilerplate (dev team nội bộ) phải: (a) tin chuỗi e2e chạy được — chưa có proof committed; (b) copy 1 repo-con ra dùng riêng — chưa được chứng minh trong CI; (c) sinh project mới từ boilerplate — chưa có script; (d) đọc docs để tự chạy từ fresh-clone — docs đang stale; (e) nhận được code sạch bảo mật — chưa có audit cuối.
18
+
19
+ ## 2. Scope
20
+
21
+ **In:**
22
+ 1. `scripts/smoke/e2e.sh` — curl API-level qua gateway: login auth-mock → POST task (node-svc, assignee validate qua spring) → GET feed (go-svc); assert task title xuất hiện trong feed + stats đúng.
23
+ 2. CI convergence workflow (file RIÊNG, không đụng template SF-1): job e2e-smoke (docker compose up + chạy e2e.sh), job copy-dir-smoke (copy ≥1 service + `frontend/shared` ra tmp → build/test pass), job scaffold-verify (chạy scaffold → output `pnpm install` + build được).
24
+ 3. `platform/docker-compose.yml`: healthcheck wget busybox `/readyz` cho **node-svc + spring-svc** (đã probe: node:22-alpine + eclipse-temurin:21-jre-alpine đều có busybox wget) + health-gated `depends_on` — CHỈ phần này được sửa trong compose. **go-svc NGOẠI LỆ có chủ đích** (P0 spec-critic): runtime distroless không shell/wget, Dockerfile READ-ONLY → healthcheck in-container bất khả; gateway gate `service_started` cho go-svc; readiness go-svc chứng minh bằng e2e.sh poll `/api/activity/stats` trước feed assert (retry). **Gateway KHÔNG thêm healthcheck** (P1 spec-critic vòng 2: nginx proxy thuần không route /readyz — probe sẽ 404 deadlock; wait đã do e2e.sh poll `/api/auth/readyz` đảm nhiệm). Exception ghi vào conventions/02 rule 3.
25
+ 4. Docs: ADR 7 quyết định (mixed stack, MF/Rspack, contract-first, readonly schema trade-off, fail-closed vs degrade, fire-and-forget events, fork-not-upgrade), toolchain doc (JDK/Go/Node/pnpm/docker cần ở đâu), fresh-clone walkthrough checklist, README sync (Mermaid + hướng dẫn chạy = kiến trúc thật).
26
+ 5. Scaffold script `scripts/scaffold/` — copy + rename + prune thuần (bash), sinh project đặt tên mới, cùng flow chạy được. Trễ = scope-flag lên user, KHÔNG auto-complete manual fallback.
27
+ 6. Xử lý 2 findings SF-1-owned — **nguồn uỷ quyền: story brief FI-62 (.story-brief.md dòng 3) chỉ đích danh SF-7 xử lý** (commit ec7c3d3 là recovery của chính brief): conventions/02 mirror rule healthcheck paths (improvements-log SF-4 finding #4); canonical DDL note tách CREATE SCHEMA khỏi tables (improvements-log SF-4 finding #5). Rà thêm các [p6-flag] conventions sync cùng nguồn uỷ quyền (dòng "rà các [p6-flag] conventions sync"): conventions/01 standalone-lockfile variant (SF-2 flag), conventions/08 requiredVersion:false singleton (SF-6 flag). Sửa compose thì cập nhật banner ownership (SF-7 convergence).
28
+ 7. Security-audit checkpoint (secrets/exec-bit/lockfile/deps OWASP surface) — 0 P0/P1 mở.
29
+ 8. Rà multi-stage + pinned base images toàn bộ Dockerfile (report, không sửa trừ khi P0).
30
+ 9. Rule 0: smoke chạy THẬT native local + evidence; browser walkthrough = human gate — ghi hướng dẫn sẵn cho user.
31
+
32
+ **Out:** browser trong CI; fix business logic services/FE; merge main/PR; tính năng mới; k8s; Keycloak thật.
33
+
34
+ ## 3. Touch map
35
+
36
+ | File | Hành động |
37
+ |---|---|
38
+ | `scripts/smoke/e2e.sh` | tạo [SỞ HỮU] |
39
+ | `scripts/scaffold/**` | tạo [SỞ HỮU] |
40
+ | `.github/workflows/convergence.yml` | tạo [SỞ HỮU — file convergence riêng] |
41
+ | `docs/adr/**`, `docs/toolchain.md`, `docs/walkthrough.md` | tạo [SỞ HỮU] |
42
+ | `README.md` | sửa (sync cuối) |
43
+ | `platform/docker-compose.yml` | sửa — CHỈ healthcheck + depends_on chain |
44
+ | `platform/conventions/02-healthcheck.md`, `01-dockerfile-pattern.md`, `08-gateway-and-remotes.md` | sửa — sync findings [p6-flag] |
45
+ | `contracts/db/tasks-schema.sql` | sửa — note CREATE SCHEMA (comment-only, không đổi DDL) |
46
+ | `services/*`, `frontend/*` | READ-ONLY |
47
+ | `.github/workflow-templates/` | READ-ONLY (thiếu gì = flag) |
48
+
49
+ ## 4. Design
50
+
51
+ ### 4.1 e2e smoke script (API-level)
52
+ - Bash thuần + curl + jq-light (grep/python-free fallback? — dùng grep + sed, tránh jq dependency; CI ubuntu có jq nhưng script phải chạy được local Git Bash). Quyết: dùng `node -e` KHÔNG — giữ curl+grep thuần; JSON assert bằng grep pattern ổn định theo contract (accessToken, title echo, feed items chứa title).
53
+ - Env: `GATEWAY_URL` (mặc định `http://localhost:8080`), `SMOKE_EMAIL`/`SMOKE_PASSWORD` (mặc định alice@demo.local/demo-password), `SMOKE_TITLE` prefix unique theo `date +%s` để re-run được.
54
+ - Chain assert: login 200 + accessToken → POST /api/tasks 201 (assigneeId = bob UUID để đi qua spring validate) → GET /api/activity/feed có item action `task.created` chứa title — **poll 10×1s** (P1 spec-critic: node push fire-and-forget KHÔNG await, go-svc persist async → assert ngay = flaky CI) → GET /api/activity/stats: fetch **baseline totalTasks TRƯỚC khi tạo task**, assert sau ≥ baseline+1. Exit non-zero + message rõ khi fail ở bước nào. Wait-before-assert: poll `/api/auth/readyz` QUA gateway :8080 (gateway không có /readyz riêng — P2 critic).
55
+ - Cùng 1 script dùng cả native lẫn qua gateway: chỉ cần GATEWAY_URL trỏ đúng.
56
+
57
+ ### 4.2 Health-gated compose
58
+ - Healthcheck `/readyz` (wget busybox) **CHỈ node-svc + spring-svc** — đã probe Dockerfile: cả hai runtime alpine có busybox wget.
59
+ - **go-svc: `service_started`** (distroless, Dockerfile READ-ONLY — P0 spec-critic); readiness chứng minh ở e2e.sh poll stats.
60
+ - **Gateway: KHÔNG healthcheck** (nginx không route /readyz — probe 404 deadlock, P1 critic vòng 2); wait do e2e.sh đảm nhiệm.
61
+ - Chain: postgres (healthy) → auth-mock (healthy, existing) → node/spring (healthy, mới); node-svc depends_on spring-svc healthy (readyz node kiểm spring reachable); gateway depends_on auth-mock + node + spring `service_healthy`, go-svc `service_started`.
62
+ - Validate: `docker compose --env-file platform/.env.example config -q` (KHÔNG cần Docker daemon) + CI chạy thật.
63
+
64
+ ### 4.3 CI convergence.yml
65
+ - Trigger: `branches: ["**"]` + workflow_dispatch (workflow hội tụ — chạy full, không path-filter; P2 critic: tránh CI âm thầm không chạy khi branch rename).
66
+ - Job `e2e-smoke`: checkout → `docker compose --env-file platform/.env.example up -d --build` (reuse .env.example — P2 critic, thay "sinh .env 10 biến") → poll `/api/auth/readyz` qua :8080 → `bash scripts/smoke/e2e.sh` → dump logs khi fail (compose gọi lại CÙNG `--env-file` — p6-flag SF-2).
67
+ - Job `copy-dir-smoke`: copy `services/node-svc` + `frontend/shared` → `$RUNNER_TEMP/standalone` → node-svc: `pnpm install --ignore-workspace && pnpm test && pnpm build` (theo README standalone); fe-shared: typecheck `tsc --noEmit` (fe-shared không có scripts riêng; GHI RÕ trong job: fe-shared inert cho node-svc — proof FE copy-dir mạnh hơn = remote-tasks kèm shared, để làm follow-up nếu CI budget cho phép; Acceptance #6 context pack là "≥1 service + fe-shared").
68
+ - Job `scaffold-verify`: chạy `scripts/scaffold/scaffold.sh --name demo-app --out $RUNNER_TEMP/demo-app` → `pnpm install --no-frozen-lockfile` + build FE shell + `docker compose config -q` trong output → pass. **Narrowing tường minh (cite context pack sf-7.md ACCEPTANCE: "CI verify scaffold output build được")**: CI chỉ chứng minh build + compose-config trên output; full e2e trên scaffold output = **human gate** cần Docker — hướng dẫn nằm trong SCAFFOLD.md + walkthrough.
69
+ - Không browser, không secret ngoài placeholder CI.
70
+
71
+ ### 4.4 Scaffold
72
+ - `scripts/scaffold/scaffold.sh <new-name> [--out dir]`: **cp/tar-based (KHÔNG rsync — không có mặc định trong Git Bash Windows, P2 critic)** trừ `.git`, `.github/workflow-templates`, `docs/superpowers`, `node_modules`, `frontend/spike`, `.story-brief.md`; **prune `.github/workflows/convergence.yml`** (pin story branch — chết trong repo mới; giữ per-service workflows + contracts.yml vì generic + path-filtered); rename: package names `@boilerplate/*` → `@<new-name>/*` (kể cả root `package.json` name — P2 critic), compose `name:`, README title; xử lý root `pnpm-lock.yaml` importers (strip spike + rename scope — probe tại task); giữ contracts + platform + services + frontend/shell + remotes + shared + scripts/smoke; ghi `SCAFFOLD.md` nguồn gốc + ngày + hướng dẫn full-e2e human gate. Không generator framework.
73
+ - Windows dev: bash script chạy Git Bash (docs ghi rõ); CI chạy ubuntu. exec-bit không set từ Windows — CI/README gọi `bash scripts/...` (ghi vào audit).
74
+
75
+ ### 4.5 Docs
76
+ - `docs/adr/README.md` index + 7 ADR ngắn (1 file/quyết định, format: Context/Decision/Consequences).
77
+ - `docs/toolchain.md`: bảng tool × ai cần (dev native / CI / copy-user).
78
+ - `docs/walkthrough.md`: fresh-clone checklist số bước, cả compose lẫn native, khớp đúng lệnh đã verify trong evidence.
79
+ - README: cập nhật kiến trúc (6 services đủ), mục Chạy (compose + native + smoke), repo map mới, xoá state SF-1 stale.
80
+
81
+ ### 4.6 Findings + conventions sync
82
+ - conventions/02: thêm mirror rule — service expose `/healthz`+`/readyz` naked VÀ mirror dưới prefix `/api/<svc>/*` (auth-mock precedent) để OpenAPI servers.url + schemathesis khớp.
83
+ - tasks-schema.sql: comment note — phần CREATE SCHEMA tách Apply context (db-level CREATE privilege) khỏi table DDL (schema-level); CI apply-as-role chạy 2 phần bằng user khác nhau.
84
+ - conventions/01: variant standalone lockfile (COPY local lockfile khi build context = thư mục con).
85
+ - conventions/08: singleton remote khai `requiredVersion: false` tường minh (`catalog:` literal rò vào requiredVersion).
86
+ - 04-error-envelope: note additionalProperties decision? — chỉ ghi khi quyết chung đã có ở node-svc; KHÔNG tự chốt thay 3 service (flag nếu chưa chốt).
87
+
88
+ ### 4.7 Security checkpoint
89
+ - security-audit agent trên toàn diff + repo scan: secrets (gitleaks đã có CI — review kết quả), exec-bit scripts, .env không commit, lockfile sync, deps surface (OWASP theo tính năng: JWT HS256 shared secret, CORS dev-profile, gateway 401).
90
+ - 0 P0/P1 mở mới được DONE.
91
+
92
+ ## 5. Implementation outline
93
+
94
+ 10 tasks (DAG):
95
+ 1. `docs-sync` — conventions sync + DDL note (T1) — không phụ thuộc
96
+ 2. `compose-health` — health-gated compose (T2) — phụ thuộc đọc Dockerfile 3 svc (probe trong task)
97
+ 3. `smoke-script` — e2e.sh (T3) — không phụ thuộc
98
+ 4. `ci-smoke` — convergence.yml job e2e-smoke (T4) — phụ thuộc T2+T3
99
+ 5. `ci-copydir` — job copy-dir-smoke (T5) — phụ thuộc đọc README node-svc
100
+ 6. `scaffold` — scaffold.sh (T6) — không phụ thuộc
101
+ 7. `ci-scaffold` — job scaffold-verify (T7) — phụ thuộc T6
102
+ 8. `adr-toolchain` — ADR 7 + toolchain.md (T8) — không phụ thuộc
103
+ 9. `readme-walkthrough` — README sync + walkthrough.md (T9) — phụ thuộc T8 (link ADR) + T3 (lệnh smoke)
104
+ 10. `verify-evidence` — Rule 0 native smoke + evidence + security-audit + independent review (T10) — phụ thuộc T1-T9
105
+
106
+ Test strategy: smoke script chạy thật native (evidence); `docker compose config` validate compose; CI xanh sau push là gate thật cho 3 job mới; docs không có test — walkthrough phải khớp lệnh đã chạy.
107
+
108
+ ## 6. Risks
109
+
110
+ - Dockerfile image base có/không curl/wget cho healthcheck → probe từng Dockerfile trước khi viết compose (không đoán).
111
+ - Feed action string thật ("task.created"?) → đọc node-svc source event push (READ-ONLY) trước khi viết assert.
112
+ - CI compose job dùng `.env` — compose `${VAR:?}` fail hard nếu thiếu → job phải sinh .env đủ 10 biến.
113
+ - pnpm-lock trong scaffold output — copy nguyên lockfile + `pnpm install` lại (importers giữ nguyên tên workspace? rename `@boilerplate/*` phá lockfile importers → scaffold phải update importers trong lockfile hoặc chạy `pnpm install --no-frozen-lockfile` trong job verify; quyết tại T6, probe trước).
114
+ - Native toolchain `~/Tools/sf6-e2e` phải còn sống (đã verify ✓) — start scripts tái dùng.
@@ -0,0 +1,42 @@
1
+ # SF-2 Spec — node-svc task API (FI-70)
2
+
3
+ > Derived từ epic spec `2026-10-12-boilerplate-microservice-mfe.md` rev 3 (đã user-approved + spec-critic + plan-critic ở epic level) + context pack `docs/superpowers/contexts/sf-2.md`. SF dispatch 2026-10-12, worktree `__STACK_ORG__/sf-2-node-svc`. Spec-critic vòng 1: FIX-P0-FIRST → 2 P0 đã resolve + P1/P2 pinned (xem §Decisions).
4
+
5
+ ## Problem
6
+ `services/node-svc/` là khung rỗng. Epic cần service task CRUD chạy được qua gateway để chứng minh acceptance #2 (tạo task → user được spring validate).
7
+
8
+ ## Scope (in)
9
+ 1. Scaffold Fastify + TypeScript, Node 22 LTS, pnpm (workspace entry đã khai trong `pnpm-workspace.yaml`).
10
+ 2. Codegen types từ `contracts/openapi/tasks.yaml` (`openapi-typescript`, types only) — **output commit** (`src/types/api.d.ts`, contracts/ ngoài docker build context nên không gen trong image); CI re-generate + `git diff --exit-code` chống drift.
11
+ 3. CRUD: POST/GET/GET-by-id/PATCH/DELETE `/api/tasks/*` (service tự mount prefix — gateway pass-through), port 3001. Non-uuid `taskId` → 400 `VALIDATION_ERROR`; không thấy task → 404 code `TASK_NOT_FOUND` (đúng ví dụ tasks.yaml; conventions/04 catalog là "tối thiểu").
12
+ 4. Validate user: tạo/sửa khi có `assigneeId` → gọi `GET {SPRING_SVC_URL}/api/users/{id}` timeout 2s. spring 404 → **422 UNPROCESSABLE**; spring down/timeout → **503 DEPENDENCY_DOWN fail-closed** (task KHÔNG ghi; ADR degrade ghi README).
13
+ 5. Event push fire-and-forget: sau mutate thành công → `POST {GO_SVC_URL}/api/activity/events`, payload `ActivityEventInput` (activity.yaml), action `task.created|task.updated|task.deleted`. **Không await** (đáp trả ngay sau khi DB commit), fetch có `AbortSignal.timeout(2000)` (không leak socket khi go-svc hang), `.catch` → pino warn `event push failed`, không retry.
14
+ 6. Postgres schema `tasks` + migration drizzle-orm khớp canonical DDL `contracts/db/tasks-schema.sql`. **Diff methodology (spec-critic P1): so sánh cấu trúc chuẩn hoá** — schema/columns(type/nullability/default)/CHECK definition/3 indexes (incl. `created_at DESC`) — đã implement trong `src/db/schema-diff.test.ts` (bỏ khác biệt cosmetic: quote/comment/USING btree/NULLS LAST/tên constraint). Migration `CREATE SCHEMA IF NOT EXISTS` (idempotent với schema init script 01-init.sh đã tạo sẵn). id = uuid v4 app-generated; status varchar + CHECK; bảng do role `node_svc` tạo (search_path tasks) — xem §Decisions D1 về compose bug.
15
+ 7. `/healthz` naked 200 `{"status":"ok"}`; `/readyz` naked = DB migrated + SELECT ok (503 envelope khi fail); **mirror `/api/tasks/healthz` + `/api/tasks/readyz`** (pattern auth-mock — contract fixtures theo tasks.yaml servers.url chạy được). Boot-time spring reachability check 1 lần + log warn, KHÔNG gate ready (deviation so với conventions/02 + summary tasks.yaml — cite cả hai trong README; fail-closed enforce ở request-time mục 4). Lưu ý: check này chỉ có tác dụng observability — executor KHÔNG tự invent gating.
16
+ 8. JWT: tự verify HS256 (JWT_SECRET) + exp + iss=`auth-mock` trên mọi business route; 401 envelope `UNAUTHORIZED`. healthz/readyz (cả naked lẫn mirror) không auth.
17
+ 9. JSON log pino shape conventions/03 (ts/level/service/msg/requestId từ X-Request-Id); error handler map mọi error (kể cả FST_ERR_*) sang envelope conventions/04.
18
+ 10. CORS `@fastify/cors` origin từ `CORS_DEV_ORIGIN` (deny-by-default khi rỗng), methods GET/POST/PATCH/DELETE, headers Authorization/Content-Type/X-Request-Id.
19
+ 11. Swagger UI `/api/tasks/docs` (mirror tối thiểu tasks.yaml). **Acceptance "swagger mở được" = native** `localhost:3001/api/tasks/docs` (browser-verify khi chạy local); qua gateway :8080 thì cần Bearer header (CI curl-verify được — gateway presence-check chặn browser không token).
20
+ 12. Tests vitest: unit routes (happy CRUD, 400/401/404/422/503 với fake spring inject, fire-and-forget go-svc down → vẫn 201 + warn), healthz/readyz (DB fail → 503), schema-diff. Mọi external call inject qua app factory opts (không network thật).
21
+ 13. Dockerfile multi-stage theo conventions/01 (node:22-alpine, `pnpm install --frozen-lockfile`, build dist, USER node, EXPOSE 3001) + `.dockerignore`. **Lockfile strategy (spec-critic P0-2):** local standalone `services/node-svc/pnpm-lock.yaml` (sinh bằng `pnpm install --ignore-workspace`) vì compose build context = `services/node-svc` không thấy root lockfile; root `pnpm-lock.yaml` (workspace) phục vụ dev/CI native — **root lockfile là file touched**, commit cả hai.
22
+ 14. CI `.github/workflows/services-node-svc.yml`: (a) build+test native (root `pnpm install --frozen-lockfile` + `pnpm --filter node-svc test` + build + typegen drift check); (b) docker build; (c) **boot-smoke**: `docker compose up -d --build postgres node-svc` (init thật tạo role node_svc; DATABASE_URL từ compose — GAP-ANSWER D1: coordinator đã fix @ab207d8 thành `postgres://node_svc:${NODE_SVC_DB_PASSWORD}@...`) → healthz/readyz 200 trên localhost:3001 → ký JWT CI (node crypto, không deps) → POST task **KHÔNG assigneeId** → 201 (với go-svc vắng mặt = evidence fire-and-forget) → GET list thấy → DELETE 204.
23
+ 15. README `services/node-svc/`: chạy native + docker, env vars (+ default native SPRING_SVC_URL/GO_SVC_URL `localhost:8081/8082`), API summary, failure semantics + ADR degrade, readyz deviation note (cite conventions/02 + tasks.yaml), ghi chú PATCH không thể null `assigneeId` (UpdateTaskRequest.assigneeId non-nullable trong tasks.yaml). Exit: docs đủ standalone (copy-dir là việc SF-7).
24
+
25
+ ## Env consumed (đã pre-seed trong compose — KHÔNG thêm biến mới vào .env.example)
26
+ `PORT`(3001), `DATABASE_URL` (role node_svc), `JWT_SECRET`, `SPRING_SVC_URL`, `GO_SVC_URL`, `CORS_DEV_ORIGIN`, `LOG_LEVEL`.
27
+
28
+ ## Out of scope / boundary
29
+ - KHÔNG sửa compose, contracts, conventions, gateway, postgres init, fe-shared, .env.example, pnpm-workspace.yaml (đụng = FLAG coordinator).
30
+ - KHÔNG implement spring-svc/go-svc/FE. KHÔNG CORS-wide. KHÔNG docker local.
31
+
32
+ ## Decisions (spec-critic vòng 1, 2026-10-12)
33
+ - **D1 (P0) compose DATABASE_URL sai credential semantics — RESOLVED**: flag đã gửi coordinator; GAP-ANSWER 2026-10-12: fix landed trên dest @ab207d8 (`postgres://node_svc:${NODE_SVC_DB_PASSWORD}@...` khớp init roles). SF-2 đã merge dest; boot-smoke dùng compose entry chuẩn, KHÔNG override.
34
+ - **D2 (P0) lockfile vs build context**: giữ workspace membership (SF-1 seeded); thêm local standalone lockfile cho Docker path (mục 13). Đã verify root `pnpm install --frozen-lockfile` vẫn sạch với local lockfile tồn tại.
35
+ - **D3 (P1) readyz**: ready = DB only; spring check boot-time warn-only — SF-3 song song chưa tồn tại, readyz gate cứng vào spring làm boot-smoke CI không thể xanh.
36
+
37
+ ## Acceptance (mirror context pack)
38
+ - Swagger node-svc mở được (native, mục 11); tạo task với user fixture → task hiện trong list; assignee không tồn tại → 422 rõ.
39
+ - Spring down (mocked test) → 503, không ghi nửa chừng.
40
+ - CI xanh: build+test + docker build + boot-smoke (healthz/readyz 200, migration xong, task create/list/delete smoke, 201 khi go-svc vắng).
41
+ - Migration khớp 100% canonical DDL (schema-diff test, methodology mục 6).
42
+ - go-svc down → tạo task VẪN thành công (warn log) — fire-and-forget.
@@ -0,0 +1,111 @@
1
+ # Epic Spec — Kafka + Transactional Outbox + Saga (mở rộng FI-62)
2
+
3
+ > Story: pending epic ID · tạo 2026-10-13 · pipeline: story-workflow CREATE
4
+ > Repo: `__STACK_ORG__/architecture-overview` (main @0785930 — boilerplate FI-62 đã merge)
5
+ > Phase 0: analyst xong (3 P0 đã hấp thụ: CHECK constraint 2 đầu, resolver bearer, CI go-svc hard-code ingest)
6
+ > Rev 2 — sau spec-critic (FIX-P0-FIRST): varchar(40) cho action; PATCH event matrix chốt; TaskStatus tách writable/extended; ownership activity.yaml→SF-3, DDL-node-cụm→SF-2 nguyên tử; go workflow 3 touch points pin phương án; resolver login backoff + lazy re-login; compensation UPDATE conditional
7
+ > Rev 3 — sau plan-critic (FIX-P0-FIRST, 5 P0): SF-1 pre-add env consumers (compose+.env.example); SF-2 thêm task services-node-svc.yml kafka boot-smoke + pin schema-diff.test whitelist outbox; SF-1 golden envelope fixtures (2 đầu test load chung); FE remote-tasks badge → SF-3; SF-4 cắt false dep (tier 0 song song SF-1); checkpoint-1 convergence đỏ tạm ghi rõ; e2e assert DLQ; activity.yaml ×2 file + diff-guard
8
+
9
+ ## IDEA-BRIEF (8 chiều)
10
+
11
+ - **Task**: Nâng luồng event của boilerplate từ REST fire-and-forget (ADR-0006 tự nhận mất-mất) lên **Kafka + Transactional Outbox + Saga choreography**; thêm demo @Transactional nhiều step cho spring-svc.
12
+ - **Output**: Boilerplate vẫn `compose up` được (10 services), có topic `task-events` + DLQ, outbox pattern, saga compensation demo, ADR-0008; CI toàn green.
13
+ - **Users**: Team copy boilerplate — học được: transactional outbox, at-least-once + idempotency, consumer retry/DLQ, saga compensation, @Transactional.
14
+ - **Constraints**: Kafka single-node **KRaft** (`apache/kafka`, KHÔNG expose 9092 ra host); JSON envelope + `schemaVersion` (không Avro/Registry); outbox relay **tự viết** poll 500ms; saga **choreography**; CI-only verify (user máy yếu); không service nào `depends_on: kafka: service_healthy` (chain 9 service nguyên vẹn, connect lazy).
15
+ - **Input**: Code main @0785930 (đã probe: node push tại `routes/tasks.ts:222-234` ×3 điểm, go ingest `internal/api/events.go`, spring chưa có service layer, compose 9 services health-gated).
16
+ - **Context**: RAM CI 7GB — Kafka heap ~512MB; user không chạy local.
17
+ - **Success criteria**: (1) compose up 10 services xanh; (2) tạo task → event qua outbox → Kafka → go consume → feed hiện (at-least-once + idempotent — duplicate event không nhân đôi feed); (3) saga fail path: assign cho fixture fail-user → go fail ×3 → DLQ → compensating → task status `assignment_failed` thấy trên FE; (4) spring @Transactional rollback demo test xanh; (5) CI all green gồm convergence sửa đổi.
18
+ - **Out-of-scope**: Schema Registry/Avro; Debezium; Kafka UI; SASL/SSL (PLAINTEXT compose-internal); multi-broker; Exactly-once semantics.
19
+
20
+ ## Quyết định đã chốt (user, 2026-10-12/13)
21
+
22
+ | # | Quyết định | Chọn |
23
+ |---|---|---|
24
+ | U1 | Model kết quả compensation | Giá trị mới `assignment_failed` của `tasks.status` (cascade có kiểm soát ~6 file) |
25
+ | U2 | Saga entry point | Reuse PATCH `assigneeId` hiện có (không thêm endpoint) |
26
+ | U3 | REST ingest `/api/activity/events` | **Xóa sạch** (việc sửa CI go-svc hard-code thuộc SF-3) |
27
+ | U4 | Kafka image + port | `apache/kafka` KRaft, compose-internal only (không expose 9092) |
28
+
29
+ Tự quyết theo conventions (ADR-0008 ghi): `schemaVersion: 1` integer; topics `task-events` + `task-events.dlq`; 1 partition; consumer groups `go-svc-activity` + `node-svc-compensation`; `auto.offset.reset: earliest`; **manual commit sau DB tx**; retry in-memory ×3 rồi DLQ; envelope JSON `{schemaVersion, id, type, occurredAt, payload}` — `id` sinh ở NODE (UUID) để go dedupe `ON CONFLICT DO NOTHING` (at-least-once + idempotent); thư viện go = `segmentio/kafka-go` (ADR ghi franz-go là path production); outbox table trong schema `tasks` (cột `published_at`, purge note); ADR-0008 supersede ADR-0006.
30
+
31
+ ## Thiết kế chính
32
+
33
+ ### Saga flow "assign task" (choreography) — event matrix CHỐT (rev 2)
34
+
35
+ **Event matrix (mỗi mutation → event, envelope id do node sinh MỖI event):**
36
+ | Mutation | Event(s) trong cùng 1 outbox tx |
37
+ |---|---|
38
+ | POST create | `task.created` |
39
+ | PATCH có `assigneeId` trong body | `task.assigned` (+ `task.updated` nếu body còn có field khác đổi) |
40
+ | PATCH không có assigneeId | `task.updated` |
41
+ | DELETE | `task.deleted` |
42
+ | Unassign (assigneeId=null) | **KHÔNG trong scope** — schema hiện nhận string, không null; ghi rõ để executor không bịa `task.unassigned` |
43
+ **Trigger predicate: PRESENCE-BASED** (body có assigneeId = bắn event, kể cả same-value). Same-value re-PATCH → event mới id mới → feed 2 dòng — chấp nhận, ADR-0008 ghi "value-compare là path production". Không cần đọc row cũ trong tx (repo đổi nhẹ hơn).
44
+
45
+ **Pipeline:**
46
+ ```
47
+ PATCH /api/tasks/{id} (body có assigneeId) — node-svc:
48
+ [1 tx: UPDATE task + INSERT outbox(task.assigned + task.updated?)] ← Situation A demo
49
+ relay (500ms poll) → publish task-events
50
+ go-svc consumer (group go-svc-activity, filter-by-type: bỏ qua task.assignment_failed):
51
+ [1 tx: INSERT activity (ON CONFLICT DO NOTHING bằng envelope id) + simulate notify]
52
+ notify fail? → retry ×3 (in-memory) → publish task.assignment_failed (vào task-events) → DLQ original
53
+ node-svc consumer (group node-svc-compensation, CHỈ nhận task.assignment_failed):
54
+ [tx: UPDATE task SET status='assignment_failed' WHERE id=? AND assignee_id=<event.assigneeId>
55
+ AND status NOT IN ('assignment_failed')] ← CONDITIONAL guard: chống stale compensation
56
+ ```
57
+ Re-assign sau `assignment_failed`: PATCH assigneeId hợp lệ (writable path) → saga chạy lại từ đầu.
58
+
59
+ **TaskStatus tách (U1a cascade đúng):** `contracts/openapi/tasks.yaml` tách `TaskStatus` (3 giá trị — query param + PATCH body, WRITABLE) / `TaskStatusExtended` (4 giá trị + `assignment_failed` — chỉ `Task.status` response, READ-ONLY). PATCH **KHÔNG nhận** `assignment_failed` (system-owned); route hard-code 3 giá trị giữ cho query/body, chỉ response nới.
60
+
61
+ **Simulate fail hook (deterministic cho e2e):** assign cho fixture user `svc-fail` (email `fail@demo.local`, trong users.json) → go consumer cố tình fail. Fixture users thêm 2 dòng: `svc-fail` + `svc-activity` (service user —cascade users.json một file, spring seed + auth-mock đọc tự nhiên).
62
+
63
+ ### Resolver bearer (P0 analyst): go consumer không có HTTP request
64
+ go-svc **login bằng fixture service user `svc-activity` (password env) — retry backoff lúc boot, KHÔNG crash nếu auth-mock chưa lên (go chỉ depends_on postgres); lazy re-login khi resolver gặp 401/expiry** → cache JWT → resolver dùng token này enrich userName. Dạy pattern service-identity. auth-mock cấp token cho mọi fixture user — không sửa auth-mock ngoài fixture (SF-1).
65
+
66
+ ### Status cascade `assignment_failed` (U1a — ownership NGUYÊN TỬ, rev 2)
67
+ - **SF-2 sở hữu NGUYÊN CỤM node-side**: canonical DDL `contracts/db/tasks-schema.sql` CHECK + `schema.ts` mirror + migration CHECK + `contracts/openapi/tasks.yaml` (TaskStatus split writable/extended) — sửa một cụm để schema-diff.test không đỏ giữa chừng. SF-1 KHÔNG đụng DDL/tasks.yaml.
68
+ - **SF-3 sở hữu NGUYÊN CỤM activity-side**: `internal/store/migrations/0002` — **`ALTER COLUMN action TYPE varchar(40)`** (`task.assignment_failed` = 22 ký tự > varchar(20) hiện tại — chỉ sửa CHECK mà quên width = InsertEvent chết runtime) + CHECK drop/recreate thêm `task.assigned`/`task.assignment_failed` + `contracts/openapi/activity.yaml` TRỌN GÓI (xóa `/events` path + `ActivityEventInput` + `EventAccepted`, sửa enum action, description, stats keys) + `store/tasks.go` status map + FE remotes tests/tile verify.
69
+ - SF-5 verify FE tổng thể.
70
+
71
+ ### P0 bắt buộc (mỗi mục 1 task tường minh, không drive-by)
72
+ 1. **CHECK + column width 2 đầu**: SF-2 (tasks.status CHECK + TaskStatus split) / SF-3 (activity.action **varchar(40)** + CHECK mới).
73
+ 2. **Resolver service-token** với login backoff + lazy re-login (trên).
74
+ 3. **`services-go-svc.yml` 3 điểm chạm** (rev 2 — enumerate đủ): (a) step event→feed→stats roundtrip POST /events → **thay bằng kafka console producer publish test event** (image apache/kafka có sẵn script) + kafka vào subset boot; (b) stats assert exact-equality 3 keys → nới cho key thứ 4; (c) chấp nhận chỉ khi boot-smoke còn ≥1 proof event→feed (chống thoái hóa). SF-3 sở hữu.
75
+ 4. **Compose ownership header**: SF-1 cập nhật header (sở hữu story này).
76
+ 5. **Kafka KHÔNG vào readyz/depends_on** — connect lazy + retry; `KAFKA_HEAP_OPTS` ~512MB.
77
+
78
+ ## SF split (5 SF — anti-duplicate checked: không pattern lặp ≥50%; SF-4 mỏng nhất 8 tasks vẫn giữ riêng vì stack/độc lập Kafka)
79
+
80
+ ### Tier 0 — SF-1 · Kafka foundation + async contracts (~12 tasks)
81
+ Kafka entry compose (apache/kafka KRaft, heap 512m, healthcheck `/opt/kafka/bin/kafka-broker-api-versions.sh` full-path, KHÔNG depend_on, KHÔNG expose 9092) + `.env.example` env mới + header ownership; **PRE-ADD env cho downstream consumers (P0 plan-critic): KAFKA_BROKERS vào node-svc + go-svc entries; AUTH_MOCK_URL + SVC_ACTIVITY_PASSWORD vào go-svc — 1 lần sửa compose duy nhất để SF-2/3 không đụng compose**; `contracts/events/task-events.md` (envelope `{schemaVersion,id,type,occurredAt,payload}`, payload shape theo event type — CẦN TRƯỚC consumer go; filter-by-type convention 2 group cùng đọc task-events; topic/DLQ naming); **golden fixtures `contracts/events/fixtures/*.json`** — mỗi event type 1 file, SF-2 relay test + SF-3 consumer test + CI console-producer ĐỀU load chung (contract machine-checkable 2 đầu); `platform/conventions/09-async-messaging.md`; fixture `svc-fail` + `svc-activity` users (users.json — roles ["user"] khớp enum; spring V2 seed + auth-mock đọc tự nhiên); ADR-0008 supersede 0006 (ghi simplifications: presence-based trigger, in-memory retry count, plaintext); README compose section. KHÔNG đụng DDL/tasks.yaml/activity.yaml.
82
+
83
+ ### Tier 1 — SF-2 · node-svc Outbox + Producer + compensation consumer (~12 tasks)
84
+ **Cụm nguyên tử node-side cascade**: canonical DDL CHECK `assignment_failed` + `schema.ts` mirror + migration + `tasks.yaml` TaskStatus split (writable 3 / extended 4 — PATCH cấm assignment_failed, route hard-code 3 giữ). **Pin schema-diff.test scope (P0 plan-critic): whitelist outbox với expected-def riêng, KHÔNG thêm vào canonical DDL, index-3 assert giữ nguyên** — hướng NGƯỢC làm đỏ copy-dir. Outbox table migration (schema tasks: id UUID do node sinh, type, payload jsonb, created_at, published_at nullable) + drizzle schema; **transactional repo API** (drizzle `.transaction()` gốc — đổi interface `TaskRepo` + fake; fake có seam tiêm lỗi cho test rollback; envelope id sinh trong repo); event matrix presence-based; relay worker poll 500ms (kafkajs) publish fixture-format + mark published_at (purge note); xóa `clients/activity.ts` + 5 refs; compensation consumer (group node-svc-compensation, conditional UPDATE guard) → `assignment_failed`; **task `services-node-svc.yml` kafka boot-smoke (P0 plan-critic): `up -d postgres kafka node-svc` + assert outbox row `published_at IS NOT NULL` (relay thật, không fake)**; tests: tx rollback (seam fail giữa 2 step), relay unit (fake producer load golden fixture), consumer unit; `KAFKA_BROKERS` lazy (env đã có từ SF-1); docs: README node-svc standalone ghi dependency contracts/db (FLAG sẵn có convergence.yml:62).
85
+
86
+ ### Tier 1 — SF-3 · go-svc Consumer + Saga + thanh lý ingest (~12 tasks)
87
+ **Cụm nguyên tử activity-side cascade**: migration `0002` — `ALTER COLUMN action TYPE varchar(40)` + CHECK drop/recreate (`task.assigned`, `task.assignment_failed`) + **activity.yaml ×2 FILE** (canonical `contracts/openapi/activity.yaml` + snapshot nhúng `services/go-svc/internal/api/openapi/activity.yaml` — sửa 1 bỏ 1 = docs endpoint lệch im lặng; thêm diff-guard vào go workflow theo precedent spring) TRỌN GÓI (xóa /events path + ActivityEventInput + EventAccepted; enum action; description; stats keys) + `store/tasks.go` map + **FE remote-tasks badge `assignment_failed` (P0 plan-critic: type + statusLabel map + tests — gán đích danh SF-3)** + remote-activity action labels. Consumer package (segmentio/kafka-go, group go-svc-activity, manual commit sau tx, ON CONFLICT DO NOTHING bằng envelope id, filter-by-type, test load golden fixture); retry ×3 → publish `task.assignment_failed` vào task-events → DLQ original; resolver service-token (login svc-activity backoff + lazy re-login 401); xóa `api/events.go` ingest + wiring + tests cập nhật; **`services-go-svc.yml` 3 điểm chạm + diff-guard** (console producer publish golden fixture + kafka vào subset + tạo topic tường minh + stats assert nới — giữ ≥1 proof event→feed); simulate fail hook svc-fail; tests: consumer unit, idempotency (duplicate event 1 feed row).
88
+
89
+ ### Tier 0 — SF-4 · spring-svc @Transactional demo (~8 tasks)
90
+ **KHÔNG depends-on SF-1 (false dep cắt — plan-critic): trigger rollback dùng alice@demo.local có sẵn**, không đụng kafka/compose/file nào SF-1 sửa → chạy song song SF-1 từ tier 0. `service/TeamService` (mới — service layer); endpoint tạo team + members qua N step, fail giữa chừng (member trùng email alice@demo.local) → **rollback toàn bộ**; controller delegate sang service; tests: happy + rollback assert (team không tồn tại sau fail) trên postgres service container; README. KHÔNG dính Kafka.
91
+
92
+ ### Tier 2 — SF-5 · Convergence + ADR sync + docs (~10 tasks)
93
+ `convergence.yml`: boot 10 services, kafka heap, poll budget nới (outbox 500ms + Kafka latency), copy-dir giữ contracts/db (outbox KHÔNG vào canonical DDL — node-internal infra); `scripts/smoke/e2e.sh`: happy path (tạo task → feed) + saga path (assign svc-fail → poll status assignment_failed **+ assert DLQ: kafka-console-consumer đọc task-events.dlq thấy event gốc** — acceptance #3 đủ 2 nửa); FE remotes verify tổng thể trên stack thật; walkthrough + README sync (+ note Flyway V2 seed 1 lần — pgdata volume CŨ thiếu svc users → hướng dẫn `down -v` sau pull); ADR-0008 consistency rà; security pass cuối (9092 không expose, secrets không vào envelope); scaffold probe (kafka entry tự flow).
94
+
95
+ ## Phased-release
96
+ - Phase 1 COMPLETE = SF-1..4 merged + **services workflows** xanh (node/go có Kafka trong boot-smoke riêng) → CHECKPOINT 1. **Ghi rõ (plan-critic): convergence.yml chạy trên mọi push — giữa lúc SF-2 merged mà SF-3 chưa, convergence đỏ cấu trúc (node publish, chưa có consumer) là ĐỘNG đã biết, KHÔNG tính verify-fail; merge SF-2/SF-3 cận nhau; tiêu chí checkpoint 1 = services workflows xanh.**
97
+ - Phase 2 COMPLETE = SF-5 merged + convergence xanh 10 services + saga e2e 2 chiều (kèm DLQ assert) → STORY-COMPLETE candidates.
98
+
99
+ ## Acceptance (epic-level, user-visible)
100
+ 1. `compose up` 10 services xanh (Kafka không chặn chain — connect lazy).
101
+ 2. Tạo task → activity feed hiện **qua Kafka** (outbox → topic → consumer), duplicate event không nhân đôi feed (bằng chứng: go consumer unit test idempotency — ON CONFLICT DO NOTHING bằng envelope id).
102
+ 3. Assign task cho `svc-fail` → sau retry ×3 → task status `assignment_failed` (FE/PATCH GET thấy), event gốc nằm ở `task-events.dlq`.
103
+ 4. Assign cho user thường → feed hiện bình thường (happy saga).
104
+ 5. spring: tạo team fail giữa chừng → DB không có team lẫn members (rollback test).
105
+ 6. REST `/api/activity/events` đã xóa (404), CI go-svc xanh với workflow sửa đổi.
106
+ 7. CI all green trên dest gồm convergence sửa đổi; ADR-0008 + conventions/09 tồn tại.
107
+
108
+ ## Boundary epic-level
109
+ - Nhánh đích `story-<epic-id>-kafka-outbox-saga`; PR human merge.
110
+ - CI-only verify (user máy yếu); Kafka không expose host; không đụng product code ngoài files trong touch map (bug thấy = report).
111
+ - Historical docs (plans/specs/contexts FI-62 nhắc /api/activity/events) KHÔNG sửa.
@@ -0,0 +1,173 @@
1
+ # Epic Spec — UI/UX Redesign (shell + remotes + fe-shared design system)
2
+
3
+ > Story: VU-53 (epic In Progress) · tạo 2026-10-13 · pipeline: story-workflow CREATE
4
+ > Rev 2 — sau spec-critic (GO): sửa 3 P1 (contract api-mở-rộng SF-3, assignee UUID rút gọn không resolve tên, cssFilename fact /assets/ sai) + 6 P2 (primitive props API trong hand-off, spike R2 exit criteria, quán từ SF-4/SF-2, aria-list exhaustive, env.d.ts defensive, phase-2 visual transient expected)
5
+ > Rev 3 — sau plan-critic (GO): P1 phân rã tasks SF-2 (7→9) + SF-4 (6→9); P2 spike R2 chạy sớm sau jsx-runtime config, tests primitives ở shell/tests (fe-shared không vitest — tránh đụng lockfile), phase-gate security owner rõ, SF-3/4 rebase note (packs)
6
+ > Repo: `__STACK_ORG__/architecture-overview` (đã chạy được: 10 services compose + e2e smoke 2 chiều PASS)
7
+ > Input user: "design lại UI/UX" · Creativity: BALANCED (spec = khung cứng; chi tiết chưa ghi agent tự quyết theo conventions, quyết định lớn flag trong notes)
8
+
9
+ ## IDEA-BRIEF (8 chiều)
10
+
11
+ - **Task**: Design lại toàn bộ UI/UX của micro-frontend demo: dựng design system (tokens + base + primitives dùng chung shell/remotes), restyle shell (layout/login/nav/fallback) + 2 remote (tasks/activity), đóng các khoảng trống UX nhìn thấy được **bằng API hiện có** (pagination, filter, edit, delete, assignee/createdAt, per-item busy, skeleton, nav active, responsive).
12
+ - **Output**: Cùng repo — `docker compose up` → mở `:8080` thấy UI có visual identity nhất quán xuyên shell + 2 remote (không còn "unstyled mặc định trình duyệt"), standalone debug `:4001/:4002` có style, 3 package FE test+typecheck xanh, walkthrough mục 4 (kể cả saga 4b) chạy được trên UI mới.
13
+ - **Users**: (a) dev nội bộ copy boilerplate — UI là "mặt tiền" phán xét khi fresh-clone walkthrough; (b) người demo e2e/saga (cần badge `assignment_failed` nhận diện được); (c) CI KHÔNG nhìn UI (e2e là curl API-level — story này không đụng CI).
14
+ - **Constraints**: MUST — giữ toàn bộ contracts ghim (mục "Contracts ghim"); a11y không thụt lùi (WCAG AA 4.5:1 text); 0 npm dependency mới, 0 external asset/CDN (CSP chưa set — không mở), giữ system-ui font stack; pin matrix (react 19.3.0 / rspack 1.7.12 / MF enhanced 0.21.6) bất biến. MUST-NOT — không đụng BE/gateway/contracts/OpenAPI, không đổi MF registry, không thêm dark mode/i18n framework.
15
+ - **Input**: Không Figma (story không có nguồn thiết kế 1:1) → hướng thiết kế sinh qua **designer 3-hướng mock-prototype, USER CHỌN (gate bắt buộc)**, hand-off doc là source of truth. Code hiện có: 4 package FE ~1.150 LOC src, CSS 68 dòng 1 file.
16
+ - **Context**: Repo là boilerplate demo đã hoàn thiện (epic trước: microservice + MFE + Kafka saga). A11y baseline tốt bất thường (skip link, focus management, role=alert/status) — giữ nguyên semantics. Coupling ngầm CSS shell→remotes là nợ lớn nhất: remotes ăn global CSS của shell, standalone mất style; 11 chỗ inline style; 0 media queries.
17
+ - **Success criteria** (binary): (1) Login `alice@demo.local` → nav → Tasks CRUD (tạo/sửa tiêu đề/xoá/đổi status/phân trang/filter) → Activity feed phản ánh — toàn bộ trên UI mới qua `:8080`. (2) Saga demo 4b: assign `fail@demo.local` → badge "Gán thất bại" nhận diện rõ. (3) Kill 1 remote → fallback đẹp + retry hoạt động. (4) Standalone `:4001`/`:4002` có style. (5) 3 package: `pnpm test` + `pnpm typecheck` xanh (38 case cũ update đồng bộ + tests mới primitives). (6) Responsive: dùng được ở 375px (không overflow ngang). (7) Không deps mới — `pnpm-lock.yaml` không đổi.
18
+ - **Out-of-scope**: dark mode (tokens CSS vars để sẵn điểm cắm); i18n framework (giữ hardcode vi); icon library/CDN font; backend/API thay đổi; e2e browser tự động (mở rộng CI); nâng cấp bất kỳ dependency nào; scaffold script (tự thừa hưởng — verify thôi).
19
+
20
+ ## Quyết định đã chốt (BALANCED — agent tự quyết theo conventions, flag cho user duyệt ở STORY-READY)
21
+
22
+ | # | Quyết định | Chọn | Flag |
23
+ |---|---|---|---|
24
+ | 1 | Phạm vi | Visual redesign + đóng UX gaps **bằng API hiện có** (limit≤100+offset, filter status, PATCH title/desc, DELETE, assignee/createdAt fields) — không tính năng ngoài contract | |
25
+ | 2 | Nguồn thiết kế | Không Figma → designer 3 hướng (mock-prototype) → **USER GATE chọn** → hand-off `docs/superpowers/designs/ui-redesign-direction.md` = source of truth mọi SF sau. **ĐÃ XỔI 2026-10-13 lúc CREATE (front-load design gate)**: user chọn **hướng B "Linear-referenced dark"** sau khi xem 3 bản draft (`designs/drafts/`) — gate record `designs/direction-approved.md`. SF-1 còn mỗi implement | ~~USER GATE~~ ĐÃ DUYỆT |
26
+ | 3 | Nơi đặt design system | `frontend/shared` thêm `src/styles/` (tokens.css + base.css) + `src/ui/` (React primitives) — mọi package import (giải luôn coupling standalone). **Ownership exception**: epic cấp cho SF-1 sở hữu 2 thư mục này; 4 file logic (api-client/token-storage/error-envelope/mf-bootstrap) vẫn READ-ONLY tuyệt đối | ⚠ ownership change |
27
+ | 4 | UI library ngoài | KHÔNG — CSS thuần + tokens + class utilities, SVG inline nếu cần icon. Lý do: 0 deps mới, boilerplate dễ copy | |
28
+ | 5 | Kiến trúc CSS | tokens.css (custom properties `:root`, idempotent — nhiều bản cùng giá trị vô hại) + base.css tối thiểu (`@layer reset,base` cùng thứ tự mọi bản) — shell import LÀM CHỦ global base; remote chỉ import tokens + scoped classes (tránh 2 bản base đè nhau) | |
29
+ | 6 | Dark mode / i18n | Out-of-scope (điểm cắm để sẵn trong tokens) | |
30
+ | 7 | Responsive | Include: breakpoints ≤768px / ≥1024px, nav wrap, list 1 cột mobile — verify thủ công 375px ở SF-5 (jsdom không assert media query) | |
31
+ | 8 | Chuỗi UI text Việt | Bộ aria-label/text nguyên văn hiện có là **contract có test** — giữ nguyên максимально; designer chỉ đề xuất đổi khi cần, đổi = cùng-commit với test | |
32
+ | 9 | Test đỏ phân mảnh | Quy tắc: SF đổi chuỗi nào thì update test chuỗi đó TRONG CÙNG SF — không để đỏ chờ SF khác | |
33
+
34
+ ## Contracts ghim (CHECKLIST — SF agents đối chiếu trước khi code)
35
+
36
+ 1. **MF registry** (conventions/08 + rspack exposes): name `tasks`/`activity`, file `remoteEntry.js`, expose `./TasksPage`/`./ActivityPage` (+ default export), URL prod `/remotes/<name>/remoteEntry.js`, env `REMOTE_TASKS_URL`/`REMOTE_ACTIVITY_URL`/`REMOTE_PUBLIC_PATH`. KHÔNG đổi.
37
+ 2. **Async boundary** `shell/src/index.tsx` = `import('./bootstrap')` — giữ nguyên (RUNTIME-006).
38
+ 3. **Singleton MF**: react/react-dom singleton; remotes `requiredVersion: false`. Pin matrix catalog bất biến.
39
+ 4. **API client interface** từ fe-shared — `ApiClient` + signature các call HIỆN CÓ không đổi; remote-local `src/api.ts` **ĐƯỢC MỞ RỘNG** (thêm query params limit/offset/status + hàm mới vd `deleteTask`) đúng contract `tasks.yaml`; không gọi endpoint ngoài `/api/auth/login`, `/api/tasks*`, `/api/activity/*` (KHÔNG resolve tên assignee qua `/api/users` — ngoài pin + sai base URL dev của remote).
40
+ 5. **A11y contracts** (có test, KHÔNG thụt lùi) — exhaustive: skip link `href="#main-content"` + text "Tới nội dung chính"; `main id="main-content" tabIndex={-1}` + focus khi đổi route; `role="alert"` mọi error banner; `role="status"` badge; aria-label nguyên văn: "Điều hướng chính", "Form đăng nhập", "Quản lý tasks", "Form tạo task", "Danh sách tasks", "Trạng thái task <title>", "Activity feed và thống kê", "Thống kê tasks", "Tổng số task", "Task Cần làm/Làm/Xong", "Sự kiện 24h qua", "Danh sách hoạt động"; `data-testid="nav-user"`.
41
+ 6. **Test harness**: vitest + Testing Library jsdom; mock tầng `../src/api`; stub `__API_BASE_URL__` trong vitest define.
42
+ 7. **Build/deploy**: Dockerfile multi-stage + nginx SPA fallback + security headers giữ cấu trúc; KHÔNG thêm asset ngoài (CSP chưa set); thêm `output.cssFilename: '[name].[contenthash].css'` prod để cache-busting khi re-deploy (CSS emit ở root path — KHÔNG nằm trong `/assets/` immutable; dời js+css vào `/assets/` = ngoài scope story này).
43
+ 8. **Read-only tuyệt đối**: `frontend/shared/src/{api-client,token-storage,error-envelope,mf-bootstrap}.ts`, `frontend/shared/package.json` trường `mfToolkit`, `contracts/**`, `platform/gateway/**`, `services/**`, `scripts/smoke/e2e.sh`, `platform/conventions/08`, `frontend/spike/**`, mọi Dockerfile/nginx.conf.
44
+ 9. **CI e2e API-level không đổi** — story này human gate = browser walkthrough mục 4 + 4b.
45
+
46
+ ## P0 impact — 10 chiều (tóm tắt, full trong context packs)
47
+
48
+ **Rủi ro đã phán** (P0 analyst, đọc code thật):
49
+
50
+ | # | Rủi ro | Sev | Mitigation (bắt buộc) | SF |
51
+ |---|---|---|---|---|
52
+ | R1 | Remotes rspack KHÔNG có css rule + experiments.css → import fe-shared CSS fail build ngay | **P0** | Copy y hệt rule của shell (`rspack.config.mjs:42-45,85-87`) vào 2 remote + `declare module '*.css'` vào env.d.ts ×3 | SF-1 |
53
+ | R2 | JSX trong fe-shared → `react/jsx-runtime` ngoài shared scope → duplicate react/hooks crash runtime lúc remote mount trong shell | **P0** | Thêm `'react/jsx-runtime': {singleton:true, requiredVersion:false}` vào shared CẢ 3 config + **spike build 3 package load thật soi console** trước khi restyle; fallback: primitives class-only (không JSX) | SF-1 |
54
+ | R3 | 2 bản base/tokens cùng load (shell + runtime remote CSS) — đè nhau / stale cache lệch version | P1 | tokens idempotent; base tối thiểu + `@layer` cùng thứ tự; shell làm chủ global base — remote chỉ tokens + scoped; cssFilename contenthash | SF-1 |
55
+ | R4 | Standalone :4001/:4002 mất style | P1 | remote `src/index.tsx` import base+tokens (sau R1) | SF-3/4 |
56
+ | R5 | Đổi chuỗi UI Việt → đỏ test phân mảnh | P1 | Quy tắc cùng-commit cùng-SF (quyết định #9) | mọi SF |
57
+ | R6 | A11y thụt lùi khi restyle | P1 | 3 test a11y là hard gate; palette hand-off phải đạt AA 4.5:1 (benchmark hiện tại `#742a2a`/`#fed7d7` đạt); animation mới → `prefers-reduced-motion` | mọi SF |
58
+ | R7 | fe-shared ownership (SF-1 cũ sở hữu) | P2 | Epic cấp ownership giới hạn `src/styles/`+`src/ui/` cho SF-1 mới; update comment pnpm-workspace.yaml + package.json description | SF-1 |
59
+ | R8 | Phình scope font/icon CDN → mở CSP | P2 | NO-GO by design: 0 external asset, system-ui stack | tất cả |
60
+ | R9 | Mất dấu badge `assignment_failed` (walkthrough 4b) | P2 | Badge = primitive bắt buộc trong hand-off; walkthrough chạy lại ở SF-5 | SF-5 |
61
+
62
+ **Facts SF agents phải mang theo**: (f1) css rule template shell:42-45,85-87; (f2) jsx-runtime sharing + spike trước restyle; (f3) cssFilename contenthash; (f4) kiến trúc CSS đích = fe-shared base.css nguồn element defaults, remote tokens + scoped; (f5) aria-label/text Việt = contract; (f6) CI không nhìn UI; (f7) 0 deps mới; (f8) ownership giới hạn; (f9) registry pin; (f10) thứ tự designer → nền móng → restyle song song → walkthrough.
63
+
64
+ ## Kiến trúc đích (design system)
65
+
66
+ ```
67
+ frontend/shared/src/
68
+ styles/tokens.css ← custom properties :root — màu (palette hand-off, AA), spacing scale,
69
+ │ type scale, radius, shadow, breakpoint vars, z-index. Idempotent.
70
+ styles/base.css ← @layer reset,base — reset tối thiểu + element defaults (body font,
71
+ │ form control, focus-visible, .error-banner, .skip-link…). Giống hệt
72
+ │ mọi bản — copy ×3 bundle vô hại khi cùng version.
73
+ ui/Badge.tsx ← status/action badge (role="status"), variant theo tokens — dùng cho
74
+ ui/EmptyState.tsx ← task status + assignment_failed + activity action
75
+ ui/Skeleton.tsx ← loading skeleton (thay "Đang tải…" text-only) + aria-busy
76
+ ui/Spinner.tsx ← busy indicator nhỏ (per-item, submitting)
77
+ Consumers: shell/bootstrap.tsx import base+tokens (LÀM CHỦ global); remotes import tokens
78
+ trong page entry + scoped classes riêng; remote standalone src/index.tsx tự import base+tokens.
79
+ ```
80
+
81
+ ## SF split (5 SF — rubric C1-C5/V1-V3 + anti-duplicate)
82
+
83
+ **Anti-duplicate check (liệt kê tasks mọi SF trước khi chốt):** primitives/tokens/rspack-css/jsx-runtime/spike = CHỈ SF-1 (SF-2/3/4 consume — không tái hiện); restyle mỗi package = touch map disjoint (shell / tasks / activity); test updates = per-SF khu mình (Zweck); browser walkthrough = chỉ SF-5. Pattern lặp ≥2 SF: KHÔNG có. SF-2/3/4 cùng "loại" (restyle) nhưng khác surface + <50% tasks trùng loại thực tế (login/nav/fallback vs form/list/pagination vs feed/stats). SF nào cũng ≥8 tasks.
84
+
85
+ ### Phase 1 — nền móng (checkpoint: 3 package build xanh + spike duplicate-react sạch + primitives có test)
86
+
87
+ **SF-1 · Design direction + design-system nền móng** (tier 0, ~14 tasks, design: mock-prototype — **USER GATE chọn hướng**)
88
+ - Designer (huashu-design): 3 hướng HTML prototype (login + tasks + activity 3 màn hình chính mỗi hướng) → user chọn → hand-off `docs/superpowers/designs/ui-redesign-direction.md` (palette AA contrast values, type/spacing scale, component spec, motion tối giản)
89
+ - `fe-shared/src/styles/tokens.css` + `base.css` (@layer reset,base) theo direction đã chọn
90
+ - Primitives `ui/`: Badge (role=status + variants), EmptyState, Skeleton (aria-busy), Spinner
91
+ - Barrel export + package.json exports map (chỉ đụng phần mới — 4 file logic READ-ONLY)
92
+ - Rspack: css rule + experiments.css cho 2 remotes (template shell), `declare module '*.css'` env.d.ts ×3 (defensive — tsc hiện PASS nhờ side-effect import, thêm phòng named import), `'react/jsx-runtime'` shared ×3
93
+ - **Spike R2 chạy SỚM** — ngay sau task config jsx-runtime ×3 với 1 JSX stub tối thiểu, TRƯỚC khi viết primitives (FAIL muộn = rewrite đắt nhất). Exit criteria: build 3 package → load shell + remote mount + 1 tương tác (đổi status) OK + console KHÔNG có "Invalid hook call"/"2 copies of React" → screenshot vào `docs/superpowers/evidence/`; FAIL → fallback primitives class-only (không JSX), hand-off ghi luôn API shape thay thế
94
+ - Primitives props API: document TS props từng primitive trong hand-off doc (Badge variant enum phủ 4 status extended tasks + 5 action labels activity) — SF-2/3/4 consume theo đúng shape này; tests primitives sống ở `frontend/shell/tests/` (fe-shared KHÔNG có vitest — thêm vào sẽ đụng lockfile)
95
+ - `output.cssFilename` contenthash ×3 (prod)
96
+ - Remotes standalone `src/index.tsx` import base+tokens (fix R4 một nửa — full fix visual ở SF-3/4)
97
+ - Tests: primitives (Badge role/status, EmptyState text, Skeleton aria-busy, Spinner label) + shell build smoke
98
+ - Ownership notes: pnpm-workspace.yaml comment + fe-shared README + description
99
+ - Demo: storybook-less — 1 trang demo HTML đơn giản trong hand-off hoặc standalone :4001 render primitives
100
+
101
+ ### Phase 2 — 3 surface song song (checkpoint mỗi SF: package đó test+typecheck xanh + dev-server xem được UI mới)
102
+
103
+ **SF-2 · Shell — layout, login, nav, remote fallback** (tier 1, ~10 tasks — design theo hand-off SF-1, KHÔNG gate mock riêng)
104
+ - Layout: container max-width + header/page structure theo direction (giữ skip link + #main-content + focus logic NGUYÊN VẸN)
105
+ - NavBar: active state (`aria-current="page"` + visual), responsive wrap ≤768px
106
+ - NavBar: user chip + logout/login styling (giữ `data-testid="nav-user"`)
107
+ - HomePage: từ "Trang chủ" trống → dashboard chào + quick links 2 remote + demo hints (alice/fail@demo.local)
108
+ - LoginPage: card giữa màn hình + error banner styling + demo hint format đẹp — behavior + tests giữ (redirect, deep-link, error messages nguyên văn)
109
+ - RemoteSlot: Suspense fallback = Skeleton (thay `<p>Đang tải {name}…</p>` — không test nào assert chuỗi này, thay an toàn), error fallback visual (giữ text "Không tải được phần tasks…" + nút "Thử lại" — test contract)
110
+ - `shell/src/styles.css` rewrite → scoped classes + consume tokens (xóa element selectors toàn cục đã chuyển vào base.css)
111
+ - Tests tách theo surface: a11y 3 case giữ nguyên vẹn / login / remote-slot / integration update chuỗi nếu đổi
112
+ - Diff-hygiene cuối SF (không secrets, không exec-bit mới — phase-gate security của coordinator)
113
+
114
+ **SF-3 · Remote tasks — TasksPage redesign + UX gaps** (tier 1, ~13 tasks)
115
+ - Tách component: TaskForm / TaskList / TaskItem / StatusSelect (giữ export default + named cho MF)
116
+ - TaskItem: card layout responsive, StatusBadge dùng primitive Badge (giữ "Gán thất bại" role=status + text), per-item busy (Spinner + disable select) khi PATCH đang bay
117
+ - Edit inline title/description (PATCH có sẵn — nút sửa → input inline → save/cancel)
118
+ - Delete task (DELETE có sẵn — nút xoá + confirm dialog; task.deleted vào feed tự nhiên qua Kafka)
119
+ - Hiển thị assignee (UUID rút gọn monospace + tooltip full — KHÔNG resolve tên qua `/api/users`) + createdAt
120
+ - Pagination "Tải thêm" (limit ≤100 + offset — API có sẵn) + hiển thị "x/total"
121
+ - Filter theo status (?status= — API có sẵn) — chip/toggle bộ 3 writable status
122
+ - Loading = Skeleton list (primitive), empty = EmptyState (primitive), error banner giữ role=alert + message 503 spring
123
+ - `src/index.tsx` standalone: banner debug đẹp + đã có CSS (kế thừa SF-1)
124
+ - Scoped css riêng theo kiến trúc CSS đích (mục "Kiến trúc đích" — tokens từ fe-shared, KHÔNG element selectors toàn cục; SF-3∥SF-4 chạy song song nên không copy code nhau)
125
+ - Tests: update chuỗi nếu đổi + THÊM case mới (edit inline gọi PATCH đúng, delete gọi DELETE + confirm, load-more gọi offset, filter gọi ?status=, per-item busy)
126
+
127
+ **SF-4 · Remote activity — ActivityPage redesign** (tier 1, ~9 tasks)
128
+ - Stats: grid layout responsive + StatTile cards dùng tokens (giữ nguyên bộ aria-label)
129
+ - Feed: timeline theo nhóm ngày + item card (action badge primitive + userName/taskTitle)
130
+ - Feed item: time vi-VN + unknown action fallback nguyên văn
131
+ - Nút "Làm mới" styling + busy state (Spinner)
132
+ - Loading = Skeleton (feed + stats riêng biệt — giữ Promise.allSettled independence)
133
+ - Empty = EmptyState hướng dẫn sang Tasks
134
+ - Scoped css riêng (theo kiến trúc CSS đích), standalone banner debug
135
+ - Tests: update + thêm (stats card grid aria-label giữ, skeleton xuất hiện lúc loading)
136
+ - Diff-hygiene cuối SF (phase-gate security)
137
+
138
+ ### Phase 3 — hội tụ (checkpoint: walkthrough người + full suite xanh)
139
+
140
+ **SF-5 · Convergence — browser walkthrough + docs + security** (tier 2, ~9 tasks)
141
+ - Rule 0 browser walkthrough trên compose `:8080`: login → nav active → Tasks CRUD (tạo/sửa/xoá/đổi status/filter/load-more) → Activity phản ánh (feed Kafka) → saga 4b (assign fail@demo.local → badge "Gán thất bại" nhận diện) → kill 1 remote dev → fallback + retry → standalone :4001/:4002 có style — screenshot evidence
142
+ - Responsive spot-check 375px (không overflow ngang) — 3 màn hình chính
143
+ - Full suite: `pnpm -r test` + `pnpm -r typecheck` 3 package + build prod 3 package
144
+ - Docs sync: walkthrough mục 4/4b đối chiếu UI mới (label đổi = update), README repo-map (fe-shared thêm design system), frontend READMEs
145
+ - Security pass: diff không chứa secrets, không exec-bit mới, không asset ngoài, CSP untouched, `.env` không commit
146
+ - Scaffold sanity: chạy scaffold copy → output có `frontend/shared/src/styles|ui` (design system theo project mới), build được
147
+ - Improvements-log: patterns story này
148
+ - Báo (không fix) bug product thấy được — SF owning xử lý
149
+
150
+ ## Phased-release
151
+
152
+ - **Phase 1** = SF-1 (shippable: design system đứng cạnh UI cũ — UI cũ vẫn chạy dùng CSS riêng; không phá gì).
153
+ - **Phase 2** = SF-2 ∥ SF-3 ∥ SF-4 (mỗi SF shippable độc lập: package đó đã restyle, package kia vẫn cũ nhưng tokens không phá — khác surface). Visual transient GIỮA các merge trong Phase 2 là expected (shell merge trước → remotes cũ mất element styles cũ đã chuyển vào base.css tối thiểu — chấp nhận cho repo demo, tự hết khi cả 3 merge).
154
+ - **Phase 3** = SF-5 (walkthrough + docs — chỉ有意义 khi cả 3 surface xong).
155
+ - Release checkpoint sau mỗi phase; phase checkpoint kèm security-audit pass (P0/P1 sạch mới qua) — Phase 1/2: diff-hygiene checklist do SF cuối mỗi phase chạy (task có trong SF) + coordinator duyệt; Phase 3: security pass đầy đủ trong SF-5.
156
+
157
+ ## Acceptance (epic-level, user-visible)
158
+
159
+ 1. Mở `:8080` → login → 3 trang (Trang chủ / Tasks / Activity) nhất quán một design direction đã user-chọn — không còn mặc định trình duyệt trơ trụi.
160
+ 2. Tasks: tạo → sửa tiêu đề inline → đổi status (per-item busy) → xoá (confirm) → filter status → "Tải thêm" — tất cả phản ánh BE thật; tổng số "x/total" đúng.
161
+ 3. Activity: stats cards + timeline feed phản ánh mọi thao tác trên Tasks (qua Kafka), time vi-VN.
162
+ 4. Saga 4b: assign `fail@demo.local` → task hiện badge "Gán thất bại" rõ ràng; re-assign bob + status todo → về luồng thường.
163
+ 5. Kill remote-tasks → shell còn nguyên, slot tasks hiện fallback đẹp + "Thử lại" hoạt động; activity vẫn chạy.
164
+ 6. Standalone `:4001` / `:4002` mở trực tiếp có style (không còn trơ).
165
+ 7. 375px: 3 màn hình chính dùng được, không overflow ngang.
166
+ 8. `pnpm -r test && pnpm -r typecheck` xanh; `pnpm-lock.yaml` không đổi; e2e smoke `scripts/smoke/e2e.sh` vẫn PASS (không đụng).
167
+
168
+ ## Boundary epic-level
169
+
170
+ - KHÔNG đụng: BE services, gateway, contracts OpenAPI/DDL, `scripts/smoke/e2e.sh`, CI workflows, `platform/conventions/08`, pin matrix, Dockerfile/nginx cấu trúc (trừ cssFilename là rspack config).
171
+ - KHÔNG: dark mode, i18n framework, icon/font CDN, dependency mới, nâng cấp version, e2e browser tự động, đổi MF registry/exposes, đổi API call shapes.
172
+ - fe-shared: CHỈ được thêm `src/styles/` + `src/ui/` (+ barrel/exports phần mới) — 4 file logic READ-LOCKED.
173
+ - Design direction: chỉ user chọn (gate SF-1) — agent không tự chốt hướng cuối.
@@ -0,0 +1,46 @@
1
+ # SF-3 Spec — Remote tasks: TasksPage redesign + UX gaps (VU-56)
2
+
3
+ > Story VU-53 · slice canonical: `docs/superpowers/contexts/ui-redesign/sf-3.md` (đọc THAY VÌ tổng hợp lại) · epic spec rev 3: `docs/superpowers/specs/2026-10-13-ui-redesign.md` · direction: `docs/superpowers/designs/ui-redesign-direction.md` (hướng B — user đã duyệt ở CREATE)
4
+ > File này = brainstorm self-run (autonomous): holistic re-examination + design decisions mức SF. Epic-level questions đã trả lời hết ở epic spec — KHÔNG hỏi lại.
5
+
6
+ ## Design decisions (self-answered theo conventions, BALANCED)
7
+
8
+ | # | Câu hỏi brainstorm | Quyết định | Lý do |
9
+ |---|---|---|---|
10
+ | 1 | State sống đâu? | `TasksPage` owns: `tasks[]`, `total`, `loading`, `loadingMore`, `error`, `statusFilter`. `TaskForm` owns inputs của mình; `TaskItem` owns `editing`/`confirming`/`busy` cục bộ | Decomposition spec slice #1; busy per-item là UI cục bộ (spec slice #3) |
11
+ | 2 | `fetchTasks` signature? | `fetchTasks(params?: { limit?; offset?; status? })` — query builder clamp limit 1..100 (mặc định `TASKS_PAGE_SIZE = 10`), offset ≥ 0, status chỉ khi có. Luôn gửi `limit` + `offset` | Contract `tasks.yaml` (limit max 100, offset ≥ 0); page size 10 để "Tải thêm" hiện sớm trong demo |
12
+ | 3 | aria-label "Tiêu đề" trùng giữa form tạo và form sửa? | Edit inputs dùng aria-label riêng: `Sửa tiêu đề task <title>` / `Sửa mô tả task <title>` | Tránh ambiguous getByLabelText trong test + accessible name rõ hơn cho màn đọc |
13
+ | 4 | Confirm xoá: `window.confirm` hay inline? | Inline 2 bước trong item: nút "Xoá" → text "Xoá task này?" + [Xác nhận xoá] [Huỷ] | jsdom/userEvent không mô phỏng native confirm tốt; inline confirm style được theo hand-off (no-shadow, surface ladder); buttons đặt tên distinct cho test |
14
+ | 5 | aria-label `Trạng thái task <title>` trên badge sao cho KHÔNG đụng fe-shared (đóng băng — `BadgeProps = {variant, children}`)? | Bọc `<span role="status" aria-label="Trạng thái task <title>">` quanh `<Badge>` — query role=status theo name vẫn khớp test cũ, text "Gán thất bại" nguyên văn qua children | Không sửa primitive; giữ đúng contract a11y (boundary: KHÔNG đổi aria-label bộ tasks) |
15
+ | 6 | Per-item busy hiển thị thế nào? | Khi busy: `Spinner` (label `Đang xử lý task <title>`) THAY badge (hand-off §4 "Spinner thay dot") + disable select + disable nút Sửa/Xoá | Hand-off §4 task row; chống double-submit |
16
+ | 7 | Skeleton lúc load-more? | KHÔNG — giữ list, nút "Tải thêm" → "Đang tải thêm…" + disabled. Skeleton chỉ cho load đầu/tiêu đổi filter | Tránh list nhảy layout; loading state rõ ràng hơn |
17
+ | 8 | Edit payload? | Chỉ gửi field THAY ĐỔI (minProperties 1 theo contract); cả hai không đổi → thoát edit không gọi PATCH; title rỗng → không gửi | `UpdateTaskRequest` minProperties 1; description rỗng gửi `''` (contract cho phép string) |
18
+ | 9 | Assignee hiển thị? | `null` → "Chưa gán"; có → `<code title={full}>` 8 ký tự đầu + "…" monospace; KHÔNG resolve tên (boundary) | Spec slice #6 |
19
+ | 10 | createdAt format? | `Intl.DateTimeFormat('vi-VN', {2-digit date + hour/minute})` render trong `<time dateTime={iso}>`; test không assert chuỗi locale (ICU variance) — assert `/2026/` + dateTime attr | Hand-off §4 "thời gian vi-VN"; test bền |
20
+ | 11 | Empty khi đang filter? | Vẫn `EmptyState` title "Chưa có task nào" (giữ semantics — boundary), description đổi theo ngữ cảnh (bỏ lọc / thử bỏ bộ lọc) | Spec slice #10 + boundary giữ text |
21
+ | 12 | CSS scope? | File `src/styles.css` import trong `TasksPage.tsx`, mọi selector prefix `.tsk-`, KHÔNG element selector toàn cục, chỉ ăn tokens `--c-* --ink* --line* --accent* --st-* --sp-* --fs-* --r-*`; media ≤768px stack card | Spec slice #11 + epic quyết định #5 (remote chỉ tokens + scoped) |
22
+ | 13 | `index.tsx` hay `standalone.tsx` chứa banner? | `standalone.tsx` (SF-1 đã tách render ra khỏi async boundary). `index.tsx` GIỮ NGUYÊN — boundary `import('./standalone')` là contract RUNTIME-006 | Touch map ghi "index.tsx SỬA banner debug" — thực chất banner nằm ở file render; surgical scope giữ boundary không đụng |
23
+ | 14 | MF contract? | Giữ nguyên: `TasksPage.tsx` export named `TasksPage` + `export default`; không đổi expose/name/publicPath | Boundary: registry pin |
24
+ | 15 | TDD? | Viết/trả test TRƯỚC theo API component mới (RED), implement tới XANH (GREEN); evidence ghi `tdd: RED→GREEN` | Gate story-verify TDD_MODE |
25
+
26
+ ## Component tree
27
+
28
+ ```
29
+ TasksPage (state owner, error banner, filter chips, skeleton/empty/load-more)
30
+ ├── TaskForm — tạo task (aria-label "Form tạo task" giữ nguyên)
31
+ ├── FilterChips — inline trong TasksPage: "Tất cả" + 3 writable (aria-pressed)
32
+ └── TaskList — h2 "Danh sách (x/total)" + ul aria-label "Danh sách tasks"
33
+ └── TaskItem — card: badge/spinner + title/desc + meta (uuid, createdAt) + actions
34
+ ├── StatusBadge — bọc Badge primitive (role=status + aria-label giữ nguyên)
35
+ ├── StatusSelect— 3 writable, aria-label "Trạng thái task <title>", disabled khi busy
36
+ └── edit/confirm inline UI
37
+ ```
38
+
39
+ ## Test kế hoạch (giữ 12 case cũ update + thêm ~10)
40
+
41
+ Component: render list + "x/total" · tạo task · 503 banner · empty · đổi status · assignment_failed badge KHÔNG select · select 3 option · **sửa inline PATCH đúng payload** · **huỷ sửa không gọi PATCH** · **xoá confirm gọi DELETE** · **huỷ xoá không gọi** · **Tải thêm gọi offset** · **filter gọi ?status=** · **per-item busy (select disabled + Spinner)** · **assignee UUID rút gọn + title full + createdAt** · **skeleton khi loading**.
42
+ API: fetchTasks default URL mới · fetchTasks đủ params + clamp · **deleteTask DELETE 204** · create/update/503/timeout giữ.
43
+
44
+ ## Boundary (nhắc lại — từ context pack, không đổi)
45
+
46
+ KHÔNG đụng shell/**, activity/**, shared/** (đóng băng), rspack.config, env.d.ts, contracts; KHÔNG deps mới; KHÔNG merge/PR; STATUS_LABELS + aria-label bộ tasks + role=alert/status giữ nguyên văn.
@@ -0,0 +1,30 @@
1
+ # SF-5 Spec — Convergence: browser walkthrough + docs + security (VU-58)
2
+
3
+ > Story VU-53 · slice canonical: `docs/superpowers/contexts/ui-redesign/sf-5.md` (đọc THAY VÌ tổng hợp lại) · epic spec rev 3: `docs/superpowers/specs/2026-10-13-ui-redesign.md` · direction: `docs/superpowers/designs/ui-redesign-direction.md` (hướng B — user đã duyệt ở CREATE, KHÔNG designer phase)
4
+ > File này = brainstorm self-run (autonomous): holistic re-examination + quyết định mức SF. Epic-level questions đã trả lời hết ở epic spec — KHÔNG hỏi lại.
5
+
6
+ ## Holistic re-examination (brainstorm)
7
+
8
+ SF-5 KHÔNG viết code sản phẩm — nó là vòng **hội tụ**: chứng minh 8/8 acceptance epic bằng browser walkthrough thật (Rule 0 — compose `:8080` là chuẩn duy nhất cho FLOW tier), đồng bộ docs để người MỚI đi lại được, security pass cuối story, và **chuẩn bị đủ điều kiện cho human gate**: stack sống + hướng dẫn 8 bước + screenshots + walkthrough.md mục 4/4b khớp UI mới. Phần "Người walkthrough xác nhận PASS 8/8" là gate của coordinator/user — SF-5 KHÔNG tự tick.
9
+
10
+ Khác biệt với walkthrough SF-2/3/4 (isolate dev stack :3100/:4101/:4102): SF-5 đi trên **compose prod-build** (10 container) — đúng điều kiện CI convergence + đúng cái người copy boilerplate sẽ chạy. Kill-remote ở chế độ này = stop container remote (nginx proxy 502 → RemoteSlot error fallback), không phải kill dev server.
11
+
12
+ ## Design decisions (self-answered theo conventions, BALANCED)
13
+
14
+ | # | Câu hỏi brainstorm | Quyết định | Lý do |
15
+ |---|---|---|---|
16
+ | 1 | "Kill 1 remote dev" trên compose :8080 nghĩa là gì? | `docker stop boilerplate-remote-tasks-1` → reload `:8080` → shell còn nguyên, slot tasks fallback lỗi + "Thử lại"; rồi `docker start` lại container → click "Thử lại" → remote mount lại OK. Cả 2 nửa (fallback + retry) đều chứng minh | Compose không có dev server — remote là container nginx static; URL remote của shell build prod = `/remotes/tasks/remoteEntry.js` qua nginx (`Dockerfile` ARG `REMOTE_TASKS_URL`, nginx `location /remotes/`). Stop container = đúng cách remote "chết" trong chế độ này |
17
+ | 2 | "BEFORE/AFTER từng màn" cho SF convergence không restyle gì? | BEFORE/AFTER theo **trạng thái động do hành động walkthrough tạo ra** (list trước/sau tạo task; badge thường → "Gán thất bại" sau assign fail@; shell loaded → fallback sau kill remote), màn tĩnh (login/home) chụp 1 shot + so direction B. SF-2/3/4 đã có evidence old→new của từng surface | SF-5 không đổi UI — cặp old/new UI không tồn tại trên nhánh này (SF-2/3/4 đã merge); giá trị evidence của convergence là chuỗi hành động thật trên 1 build |
18
+ | 3 | Evidence layout? | Screenshots walkthrough → `docs/superpowers/evidence/ui-redesign/` (đặt tên `conv-<n>-<bước>.png`); test-run/smoke evidence gate B1 → `docs/superpowers/evidence/sf-5-ui-redesign-conv/test-run.txt` (HEAD/HEAD~1 hash + dòng `tdd:`) | Checklist Rule 0 chỉ `evidence/ui-redesign/` cho screenshots; gate B1 story-verify neo `sf-5-*/test-run.txt` (FI-440) |
19
+ | 4 | TDD cho SF docs-only? | `tdd: skipped-tdd: SF-5 docs/verify-only — không có unit mới để viết RED; bằng chứng = full suite + e2e smoke + walkthrough screenshot (3 tầng Rule 0)` trong test-run.txt | Gate TDD story-verify chấp nhận skipped có lý do; verification của SF-5 là browser + suite, không phải test mới |
20
+ | 5 | Pagination "Tải thêm" cần >10 tasks — data nào? | Tạo task CRUD qua UI (bắt buộc — đó là acceptance); nếu DB chưa đủ 10 task cho load-more thì seed thêm qua `POST /api/tasks` (curl, API công khai contract) — UI vẫn phải tự phản ánh đúng | Walkthrough kiểm UI phản ánh BE thật; seed qua API không thay thế bước CRUD-trên-UI nào |
21
+ | 6 | Saga timing? | Sau assign `fail@demo.local`: poll badge "Gán thất bại" tối đa ~60s (go consumer retry ×3 với backoff); re-assign bob + PATCH `status=todo` qua UI (edit inline + select) — đúng chuỗi walkthrough 4b | walkthrough.md mục 4b step 2-4; `assignment_failed` là system-owned, PATCH tường minh mới về luồng thường |
22
+ | 7 | 375px responsive đo thế nào khi Orca browser không có device emulation? | Headless Chrome (`--headless --window-size=375,812`) trên **cùng build :8080** đang verify, script CDP (`--remote-debugging-port`) login + navigate + screenshot 3 màn. Đây là pixel thật của cùng bundle (fallback trung thực FI-464 — khai báo trong evidence); DOM tier kiểm `scrollWidth <= innerWidth` trên chính phiên đó | Orca tab không expose viewport override; 375px phải là ảnh pixel thật (tầng 2), không phải đo DOM thay thế |
23
+ | 8 | Docs sync phạm vi chính xác? | `docs/walkthrough.md` mục 4 (4 bước → mở rộng theo UI mới: login card → nav → Tasks CRUD chi tiết → Activity → kill remote compose) + 4b (badge "Gán thất bại" + re-assign bob + PATCH todo + DLQ command); `README.md` repo-map dòng `shared/` + đoạn FE; `frontend/shell/README.md`, `frontend/remotes/{tasks,activity}/README.md` — thêm cách import tokens/primitives. KHÔNG đụng README khác | Touch map context pack (SF-5 sole owner docs); nhãn/badge đổi so walkthrough cũ = update đúng những chỗ đó thôi |
24
+ | 9 | Scaffold sanity chạy thế nào cho sạch? | `bash scripts/scaffold/scaffold.sh sf5-sanity` (dir `/tmp/...` theo pack) → assert `frontend/shared/src/styles` + `src/ui` tồn tại → `pnpm install --no-frozen-lockfile` + build shell → PASS → xoá output | Context pack mục 6 — verify-only, KHÔNG sửa scaffold script |
25
+ | 10 | Security pass đo thế nào? | Scan diff TOÀN story (`git diff <merge-base với main>..HEAD`): secret-pattern (key/secret/password/token ngoài fixture `demo-password` đã có sẵn), `.env` không được track, exec-bit mới (diff --summary), asset ngoài/CDN trong FE, CSP/nginx untouched, pnpm-lock không đổi | Context pack mục 5; OWASP surface = none-new (0 code FE/BE mới trong SF-5) → checklist diff-hygiene là đúng mức |
26
+ | 11 | Bug thấy được trong walkthrough? | KHÔNG fix (boundary frontend/** services/** READ-ONLY) — ghi REPORT coordinator vào worktree comment + improvements-log nếu có | Context pack boundary + mục 8 |
27
+
28
+ ## Boundary (nhắc lại — từ context pack, không đổi)
29
+
30
+ KHÔNG fix code SF-2/3/4; KHÔNG đụng `frontend/** services/** scripts/** .github/** contracts/** platform/**` (trừ docs của mình); KHÔNG merge/PR (coordinator); KHÔNG tự tick human-confirm 8/8; KHÔNG thêm tính năng.