create-wakii-stack 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (998) hide show
  1. package/README.md +66 -2
  2. package/dist/chunk-7XGW4UJ5.js +75 -0
  3. package/dist/chunk-AKPWS7FJ.js +76 -0
  4. package/dist/chunk-ELM6GGC5.js +50 -0
  5. package/dist/chunk-ON2WTGZH.js +77 -0
  6. package/dist/index.js +385 -0
  7. package/dist/manifest-2JVLRMDB.js +10 -0
  8. package/dist/manifest-O35TPW73.js +10 -0
  9. package/dist/manifest-TXTY67BF.js +10 -0
  10. package/dist/manifest-XWHR7Y3F.js +10 -0
  11. package/package.json +23 -4
  12. package/stack-template/.changeset/config.json +15 -0
  13. package/stack-template/.changeset/vu53-ui-redesign.md +11 -0
  14. package/stack-template/.claude/agents/be-dev.md +56 -0
  15. package/stack-template/.claude/agents/contracts-keeper.md +51 -0
  16. package/stack-template/.claude/agents/e2e-runner.md +61 -0
  17. package/stack-template/.claude/agents/fe-dev.md +53 -0
  18. package/stack-template/.claude/settings.json +77 -0
  19. package/stack-template/.claude/settings.local.json +9 -0
  20. package/stack-template/.claude/skills/add-service/SKILL.md +81 -0
  21. package/stack-template/.claude/skills/sync-contracts/SKILL.md +74 -0
  22. package/stack-template/.editorconfig +21 -0
  23. package/stack-template/.gitattributes +10 -0
  24. package/stack-template/.github/pull_request_template.md +26 -0
  25. package/stack-template/.github/workflow-templates/services-ci.yml.example +69 -0
  26. package/stack-template/.github/workflows/contracts.yml +133 -0
  27. package/stack-template/.github/workflows/convergence.yml +209 -0
  28. package/stack-template/.github/workflows/git-guard.yml +44 -0
  29. package/stack-template/.github/workflows/publish-uikit.yml +96 -0
  30. package/stack-template/.github/workflows/remotes-activity.yml +82 -0
  31. package/stack-template/.github/workflows/remotes-tasks.yml +82 -0
  32. package/stack-template/.github/workflows/services-auth-svc.yml +153 -0
  33. package/stack-template/.github/workflows/services-go-svc.yml +281 -0
  34. package/stack-template/.github/workflows/services-node-svc.yml +173 -0
  35. package/stack-template/.github/workflows/services-spring-svc.yml +132 -0
  36. package/stack-template/.github/workflows/shell.yml +78 -0
  37. package/stack-template/.github/workflows/ui-kit.yml +51 -0
  38. package/stack-template/.husky/commit-msg +14 -0
  39. package/stack-template/.husky/pre-push +51 -0
  40. package/stack-template/.spectral.yaml +17 -0
  41. package/stack-template/AGENTS.md +197 -0
  42. package/stack-template/CLAUDE.md +114 -0
  43. package/stack-template/README.md +172 -0
  44. package/stack-template/app/admin/index.html +12 -0
  45. package/stack-template/app/admin/package.json +40 -0
  46. package/stack-template/app/admin/scripts/verify-chart.mjs +49 -0
  47. package/stack-template/app/admin/src/App.test.tsx +70 -0
  48. package/stack-template/app/admin/src/App.tsx +33 -0
  49. package/stack-template/app/admin/src/data/users.ts +47 -0
  50. package/stack-template/app/admin/src/layout/AdminLayout.tsx +212 -0
  51. package/stack-template/app/admin/src/main.tsx +17 -0
  52. package/stack-template/app/admin/src/pages/ComponentsDemo.tsx +138 -0
  53. package/stack-template/app/admin/src/pages/Dashboard.tsx +182 -0
  54. package/stack-template/app/admin/src/pages/HooksDemo.tsx +153 -0
  55. package/stack-template/app/admin/src/pages/Settings.tsx +156 -0
  56. package/stack-template/app/admin/src/pages/UploadPage.tsx +34 -0
  57. package/stack-template/app/admin/src/pages/Users.test.tsx +66 -0
  58. package/stack-template/app/admin/src/pages/Users.tsx +245 -0
  59. package/stack-template/app/admin/src/styles.css +9 -0
  60. package/stack-template/app/admin/src/tests/setup.ts +15 -0
  61. package/stack-template/app/admin/tsconfig.json +18 -0
  62. package/stack-template/app/admin/vite.config.ts +11 -0
  63. package/stack-template/app/admin/vitest.config.ts +14 -0
  64. package/stack-template/app/create-wakii-app/README.md +71 -0
  65. package/stack-template/app/create-wakii-app/package.json +27 -0
  66. package/stack-template/app/create-wakii-app/scripts/publish-npm.sh +38 -0
  67. package/stack-template/app/create-wakii-app/src/index.ts +127 -0
  68. package/stack-template/app/create-wakii-app/src/options.test.ts +80 -0
  69. package/stack-template/app/create-wakii-app/src/options.ts +117 -0
  70. package/stack-template/app/create-wakii-app/src/scaffold.test.ts +143 -0
  71. package/stack-template/app/create-wakii-app/src/scaffold.ts +194 -0
  72. package/stack-template/app/create-wakii-app/tsconfig.json +17 -0
  73. package/stack-template/app/create-wakii-app/vitest.config.ts +9 -0
  74. package/stack-template/app/create-wakii-stack/package.json +27 -0
  75. package/stack-template/app/create-wakii-stack/src/manifest.ts +101 -0
  76. package/stack-template/app/create-wakii-stack/src/options.ts +106 -0
  77. package/stack-template/app/create-wakii-stack/src/scaffold.ts +315 -0
  78. package/stack-template/app/create-wakii-stack/tsconfig.json +17 -0
  79. package/stack-template/app/create-wakii-stack/vitest.config.ts +9 -0
  80. package/stack-template/app/remotes/activity/Dockerfile +36 -0
  81. package/stack-template/app/remotes/activity/README.md +59 -0
  82. package/stack-template/app/remotes/activity/index.html +11 -0
  83. package/stack-template/app/remotes/activity/nginx.conf +35 -0
  84. package/stack-template/app/remotes/activity/package.json +40 -0
  85. package/stack-template/app/remotes/activity/rspack.config.mjs +152 -0
  86. package/stack-template/app/remotes/activity/src/ActivityPage.tsx +139 -0
  87. package/stack-template/app/remotes/activity/src/api.ts +63 -0
  88. package/stack-template/app/remotes/activity/src/app.css +7 -0
  89. package/stack-template/app/remotes/activity/src/components/FeedItem.tsx +39 -0
  90. package/stack-template/app/remotes/activity/src/components/StatTile.tsx +24 -0
  91. package/stack-template/app/remotes/activity/src/components/Timeline.tsx +53 -0
  92. package/stack-template/app/remotes/activity/src/components/time.ts +30 -0
  93. package/stack-template/app/remotes/activity/src/env.d.ts +5 -0
  94. package/stack-template/app/remotes/activity/src/index.tsx +12 -0
  95. package/stack-template/app/remotes/activity/src/standalone.tsx +36 -0
  96. package/stack-template/app/remotes/activity/tests/ActivityPage.test.tsx +260 -0
  97. package/stack-template/app/remotes/activity/tests/api.test.ts +61 -0
  98. package/stack-template/app/remotes/activity/tests/setup.ts +1 -0
  99. package/stack-template/app/remotes/activity/tests/test-utils.tsx +16 -0
  100. package/stack-template/app/remotes/activity/tsconfig.json +26 -0
  101. package/stack-template/app/remotes/activity/vitest.config.ts +38 -0
  102. package/stack-template/app/remotes/tasks/Dockerfile +36 -0
  103. package/stack-template/app/remotes/tasks/README.md +59 -0
  104. package/stack-template/app/remotes/tasks/index.html +11 -0
  105. package/stack-template/app/remotes/tasks/nginx.conf +35 -0
  106. package/stack-template/app/remotes/tasks/package.json +41 -0
  107. package/stack-template/app/remotes/tasks/rspack.config.mjs +153 -0
  108. package/stack-template/app/remotes/tasks/src/TasksPage.tsx +284 -0
  109. package/stack-template/app/remotes/tasks/src/api.ts +109 -0
  110. package/stack-template/app/remotes/tasks/src/app.css +7 -0
  111. package/stack-template/app/remotes/tasks/src/components/StatusBadge.tsx +20 -0
  112. package/stack-template/app/remotes/tasks/src/components/StatusSelect.tsx +27 -0
  113. package/stack-template/app/remotes/tasks/src/components/TaskForm.tsx +74 -0
  114. package/stack-template/app/remotes/tasks/src/components/TaskItem.tsx +199 -0
  115. package/stack-template/app/remotes/tasks/src/components/TaskList.tsx +60 -0
  116. package/stack-template/app/remotes/tasks/src/components/status.ts +23 -0
  117. package/stack-template/app/remotes/tasks/src/env.d.ts +5 -0
  118. package/stack-template/app/remotes/tasks/src/index.tsx +12 -0
  119. package/stack-template/app/remotes/tasks/src/standalone.tsx +38 -0
  120. package/stack-template/app/remotes/tasks/tests/TasksPage.test.tsx +445 -0
  121. package/stack-template/app/remotes/tasks/tests/api.test.ts +159 -0
  122. package/stack-template/app/remotes/tasks/tests/setup.ts +1 -0
  123. package/stack-template/app/remotes/tasks/tests/test-utils.tsx +16 -0
  124. package/stack-template/app/remotes/tasks/tsconfig.json +26 -0
  125. package/stack-template/app/remotes/tasks/vitest.config.ts +34 -0
  126. package/stack-template/app/shared/README.md +21 -0
  127. package/stack-template/app/shared/package.json +37 -0
  128. package/stack-template/app/shared/src/api-client.ts +66 -0
  129. package/stack-template/app/shared/src/error-envelope.ts +38 -0
  130. package/stack-template/app/shared/src/index.ts +21 -0
  131. package/stack-template/app/shared/src/mf-bootstrap.ts +89 -0
  132. package/stack-template/app/shared/src/refresh-client.ts +170 -0
  133. package/stack-template/app/shared/src/token-storage.ts +57 -0
  134. package/stack-template/app/shell/Dockerfile +37 -0
  135. package/stack-template/app/shell/README.md +79 -0
  136. package/stack-template/app/shell/index.html +11 -0
  137. package/stack-template/app/shell/nginx.conf +23 -0
  138. package/stack-template/app/shell/package.json +43 -0
  139. package/stack-template/app/shell/rspack.config.mjs +147 -0
  140. package/stack-template/app/shell/src/App.tsx +57 -0
  141. package/stack-template/app/shell/src/api.ts +36 -0
  142. package/stack-template/app/shell/src/app.css +11 -0
  143. package/stack-template/app/shell/src/bootstrap.tsx +24 -0
  144. package/stack-template/app/shell/src/components/Layout.tsx +35 -0
  145. package/stack-template/app/shell/src/components/NavBar.tsx +118 -0
  146. package/stack-template/app/shell/src/components/RemoteSlot.tsx +82 -0
  147. package/stack-template/app/shell/src/components/RequireAuth.tsx +14 -0
  148. package/stack-template/app/shell/src/env.d.ts +7 -0
  149. package/stack-template/app/shell/src/index.tsx +3 -0
  150. package/stack-template/app/shell/src/pages/HomePage.tsx +70 -0
  151. package/stack-template/app/shell/src/pages/LoginPage.tsx +217 -0
  152. package/stack-template/app/shell/src/remote-urls.ts +18 -0
  153. package/stack-template/app/shell/tests/a11y.test.tsx +53 -0
  154. package/stack-template/app/shell/tests/api-timeout.test.ts +43 -0
  155. package/stack-template/app/shell/tests/integration.test.tsx +93 -0
  156. package/stack-template/app/shell/tests/login.test.tsx +227 -0
  157. package/stack-template/app/shell/tests/mf-retry.test.ts +76 -0
  158. package/stack-template/app/shell/tests/refresh-client.test.ts +301 -0
  159. package/stack-template/app/shell/tests/remote-slot.test.tsx +109 -0
  160. package/stack-template/app/shell/tests/remote-urls.test.ts +26 -0
  161. package/stack-template/app/shell/tests/setup.ts +15 -0
  162. package/stack-template/app/shell/tests/shell-chrome.test.tsx +126 -0
  163. package/stack-template/app/shell/tsconfig.json +26 -0
  164. package/stack-template/app/shell/vitest.config.ts +42 -0
  165. package/stack-template/app/spike/README.md +35 -0
  166. package/stack-template/app/spike/host/index.html +11 -0
  167. package/stack-template/app/spike/host/package.json +17 -0
  168. package/stack-template/app/spike/host/rspack.config.mjs +34 -0
  169. package/stack-template/app/spike/host/src/bootstrap.jsx +26 -0
  170. package/stack-template/app/spike/host/src/index.jsx +3 -0
  171. package/stack-template/app/spike/remote/package.json +17 -0
  172. package/stack-template/app/spike/remote/rspack.config.mjs +36 -0
  173. package/stack-template/app/spike/remote/src/Hello.jsx +7 -0
  174. package/stack-template/app/spike/remote/src/index.js +2 -0
  175. package/stack-template/app/spike/serve.mjs +31 -0
  176. package/stack-template/app/starter-templates/template-feats/extras/carousel/src/DemoCarousel.tsx +99 -0
  177. package/stack-template/app/starter-templates/template-feats/extras/chart/src/DemoChart.tsx +84 -0
  178. package/stack-template/app/starter-templates/template-feats/extras/editor/src/DemoEditor.tsx +110 -0
  179. package/stack-template/app/starter-templates/template-feats/extras/schedule/src/DemoSchedule.tsx +81 -0
  180. package/stack-template/app/starter-templates/template-feats/router/src/App.tsx +332 -0
  181. package/stack-template/app/starter-templates/template-feats/router/src/main.tsx +14 -0
  182. package/stack-template/app/starter-templates/vite-js/README.md +72 -0
  183. package/stack-template/app/starter-templates/vite-js/index.html +12 -0
  184. package/stack-template/app/starter-templates/vite-js/jsconfig.json +10 -0
  185. package/stack-template/app/starter-templates/vite-js/package.json +22 -0
  186. package/stack-template/app/starter-templates/vite-js/src/App.jsx +158 -0
  187. package/stack-template/app/starter-templates/vite-js/src/main.jsx +10 -0
  188. package/stack-template/app/starter-templates/vite-js/src/styles.css +15 -0
  189. package/stack-template/app/starter-templates/vite-js/src/theme.js +21 -0
  190. package/stack-template/app/starter-templates/vite-js/vite.config.mjs +8 -0
  191. package/stack-template/app/starter-templates/vite-ts/README.md +53 -0
  192. package/stack-template/app/starter-templates/vite-ts/index.html +12 -0
  193. package/stack-template/app/starter-templates/vite-ts/package.json +29 -0
  194. package/stack-template/app/starter-templates/vite-ts/src/App.tsx +181 -0
  195. package/stack-template/app/starter-templates/vite-ts/src/main.tsx +12 -0
  196. package/stack-template/app/starter-templates/vite-ts/src/styles.css +21 -0
  197. package/stack-template/app/starter-templates/vite-ts/src/theme.ts +16 -0
  198. package/stack-template/app/starter-templates/vite-ts/tsconfig.json +25 -0
  199. package/stack-template/app/starter-templates/vite-ts/tsconfig.node.json +11 -0
  200. package/stack-template/app/starter-templates/vite-ts/vite.config.ts +10 -0
  201. package/stack-template/app/ui-kit/.storybook/main.ts +29 -0
  202. package/stack-template/app/ui-kit/.storybook/manager-head.html +97 -0
  203. package/stack-template/app/ui-kit/.storybook/manager.ts +138 -0
  204. package/stack-template/app/ui-kit/.storybook/preview-head.html +57 -0
  205. package/stack-template/app/ui-kit/.storybook/preview.ts +62 -0
  206. package/stack-template/app/ui-kit/.storybook/tailwind-preview.css +3 -0
  207. package/stack-template/app/ui-kit/.storybook/test-runner.config.ts +20 -0
  208. package/stack-template/app/ui-kit/CHANGELOG.md +137 -0
  209. package/stack-template/app/ui-kit/LICENSE +21 -0
  210. package/stack-template/app/ui-kit/MIGRATION.md +84 -0
  211. package/stack-template/app/ui-kit/README.md +173 -0
  212. package/stack-template/app/ui-kit/RELEASE.md +77 -0
  213. package/stack-template/app/ui-kit/USAGE.md +380 -0
  214. package/stack-template/app/ui-kit/eslint.config.js +47 -0
  215. package/stack-template/app/ui-kit/package.json +166 -0
  216. package/stack-template/app/ui-kit/scripts/publish-github.sh +39 -0
  217. package/stack-template/app/ui-kit/scripts/publish-npm.sh +76 -0
  218. package/stack-template/app/ui-kit/scripts/stamp-build.cjs +13 -0
  219. package/stack-template/app/ui-kit/src/KitchenSink.stories.tsx +576 -0
  220. package/stack-template/app/ui-kit/src/Tokens.stories.tsx +193 -0
  221. package/stack-template/app/ui-kit/src/entries/carousel.ts +7 -0
  222. package/stack-template/app/ui-kit/src/entries/chart.ts +4 -0
  223. package/stack-template/app/ui-kit/src/entries/editor.ts +4 -0
  224. package/stack-template/app/ui-kit/src/entries/experience3d.ts +5 -0
  225. package/stack-template/app/ui-kit/src/entries/schedule.ts +5 -0
  226. package/stack-template/app/ui-kit/src/env.d.ts +3 -0
  227. package/stack-template/app/ui-kit/src/hooks/form.stories.tsx +80 -0
  228. package/stack-template/app/ui-kit/src/hooks/hooks-new.stories.tsx +392 -0
  229. package/stack-template/app/ui-kit/src/hooks/hooks.stories.tsx +167 -0
  230. package/stack-template/app/ui-kit/src/hooks/useClickAway.test.tsx +63 -0
  231. package/stack-template/app/ui-kit/src/hooks/useClickAway.ts +30 -0
  232. package/stack-template/app/ui-kit/src/hooks/useControllableState.test.ts +36 -0
  233. package/stack-template/app/ui-kit/src/hooks/useControllableState.ts +41 -0
  234. package/stack-template/app/ui-kit/src/hooks/useCopyToClipboard.test.ts +89 -0
  235. package/stack-template/app/ui-kit/src/hooks/useCopyToClipboard.ts +20 -0
  236. package/stack-template/app/ui-kit/src/hooks/useCountdown.test.ts +88 -0
  237. package/stack-template/app/ui-kit/src/hooks/useCountdown.ts +38 -0
  238. package/stack-template/app/ui-kit/src/hooks/useDebounce.test.ts +71 -0
  239. package/stack-template/app/ui-kit/src/hooks/useDebounce.ts +14 -0
  240. package/stack-template/app/ui-kit/src/hooks/useDefault.test.ts +37 -0
  241. package/stack-template/app/ui-kit/src/hooks/useDefault.ts +15 -0
  242. package/stack-template/app/ui-kit/src/hooks/useEventListener.test.ts +47 -0
  243. package/stack-template/app/ui-kit/src/hooks/useEventListener.ts +28 -0
  244. package/stack-template/app/ui-kit/src/hooks/useFieldArray.test.tsx +160 -0
  245. package/stack-template/app/ui-kit/src/hooks/useFieldArray.ts +85 -0
  246. package/stack-template/app/ui-kit/src/hooks/useFocusTrap.ts +67 -0
  247. package/stack-template/app/ui-kit/src/hooks/useForm.test.tsx +192 -0
  248. package/stack-template/app/ui-kit/src/hooks/useForm.ts +119 -0
  249. package/stack-template/app/ui-kit/src/hooks/useFullscreen.test.tsx +71 -0
  250. package/stack-template/app/ui-kit/src/hooks/useFullscreen.ts +68 -0
  251. package/stack-template/app/ui-kit/src/hooks/useHover.test.tsx +30 -0
  252. package/stack-template/app/ui-kit/src/hooks/useHover.ts +23 -0
  253. package/stack-template/app/ui-kit/src/hooks/useInView.test.tsx +70 -0
  254. package/stack-template/app/ui-kit/src/hooks/useInView.ts +55 -0
  255. package/stack-template/app/ui-kit/src/hooks/useInfiniteScroll.test.tsx +72 -0
  256. package/stack-template/app/ui-kit/src/hooks/useInfiniteScroll.ts +45 -0
  257. package/stack-template/app/ui-kit/src/hooks/useIsFirstRender.test.ts +30 -0
  258. package/stack-template/app/ui-kit/src/hooks/useIsFirstRender.ts +14 -0
  259. package/stack-template/app/ui-kit/src/hooks/useKeyPress.test.ts +45 -0
  260. package/stack-template/app/ui-kit/src/hooks/useKeyPress.ts +31 -0
  261. package/stack-template/app/ui-kit/src/hooks/useLocalStorage.test.ts +102 -0
  262. package/stack-template/app/ui-kit/src/hooks/useLocalStorage.ts +34 -0
  263. package/stack-template/app/ui-kit/src/hooks/useLockBodyScroll.test.ts +42 -0
  264. package/stack-template/app/ui-kit/src/hooks/useLockBodyScroll.ts +13 -0
  265. package/stack-template/app/ui-kit/src/hooks/useMeasure.test.tsx +57 -0
  266. package/stack-template/app/ui-kit/src/hooks/useMeasure.ts +32 -0
  267. package/stack-template/app/ui-kit/src/hooks/useMediaQuery.test.ts +73 -0
  268. package/stack-template/app/ui-kit/src/hooks/useMediaQuery.ts +20 -0
  269. package/stack-template/app/ui-kit/src/hooks/useMountEffect.test.ts +22 -0
  270. package/stack-template/app/ui-kit/src/hooks/useMountEffect.ts +10 -0
  271. package/stack-template/app/ui-kit/src/hooks/useOnlineStatus.test.ts +36 -0
  272. package/stack-template/app/ui-kit/src/hooks/useOnlineStatus.ts +21 -0
  273. package/stack-template/app/ui-kit/src/hooks/usePrevious.test.ts +35 -0
  274. package/stack-template/app/ui-kit/src/hooks/usePrevious.ts +13 -0
  275. package/stack-template/app/ui-kit/src/hooks/useScrollProgress.test.ts +59 -0
  276. package/stack-template/app/ui-kit/src/hooks/useScrollProgress.ts +31 -0
  277. package/stack-template/app/ui-kit/src/hooks/useSessionStorage.test.ts +80 -0
  278. package/stack-template/app/ui-kit/src/hooks/useSessionStorage.ts +34 -0
  279. package/stack-template/app/ui-kit/src/hooks/useThrottle.test.ts +61 -0
  280. package/stack-template/app/ui-kit/src/hooks/useThrottle.ts +30 -0
  281. package/stack-template/app/ui-kit/src/hooks/useTimeout.test.ts +95 -0
  282. package/stack-template/app/ui-kit/src/hooks/useTimeout.ts +38 -0
  283. package/stack-template/app/ui-kit/src/hooks/useTitle.test.ts +34 -0
  284. package/stack-template/app/ui-kit/src/hooks/useTitle.ts +24 -0
  285. package/stack-template/app/ui-kit/src/hooks/useToggle.test.ts +46 -0
  286. package/stack-template/app/ui-kit/src/hooks/useToggle.ts +16 -0
  287. package/stack-template/app/ui-kit/src/hooks/useUpdateEffect.test.ts +25 -0
  288. package/stack-template/app/ui-kit/src/hooks/useUpdateEffect.ts +18 -0
  289. package/stack-template/app/ui-kit/src/hooks/useWindowSize.test.ts +33 -0
  290. package/stack-template/app/ui-kit/src/hooks/useWindowSize.ts +23 -0
  291. package/stack-template/app/ui-kit/src/index.ts +218 -0
  292. package/stack-template/app/ui-kit/src/intro-showcase.stories.tsx +272 -0
  293. package/stack-template/app/ui-kit/src/intro.docs.mdx +247 -0
  294. package/stack-template/app/ui-kit/src/motion/motion-showcase.stories.tsx +234 -0
  295. package/stack-template/app/ui-kit/src/motion/motion.md +38 -0
  296. package/stack-template/app/ui-kit/src/provider/index.tsx +77 -0
  297. package/stack-template/app/ui-kit/src/provider/provider.stories.tsx +87 -0
  298. package/stack-template/app/ui-kit/src/provider/provider.test.tsx +121 -0
  299. package/stack-template/app/ui-kit/src/styles/base.css +171 -0
  300. package/stack-template/app/ui-kit/src/styles/dark-theme.test.ts +21 -0
  301. package/stack-template/app/ui-kit/src/styles/tailwind.css +220 -0
  302. package/stack-template/app/ui-kit/src/styles/themes/dark.css +71 -0
  303. package/stack-template/app/ui-kit/src/styles/tokens.css +133 -0
  304. package/stack-template/app/ui-kit/src/styles/ui-kit.css +10 -0
  305. package/stack-template/app/ui-kit/src/templates/auth.stories.tsx +425 -0
  306. package/stack-template/app/ui-kit/src/templates/crud.stories.tsx +416 -0
  307. package/stack-template/app/ui-kit/src/templates/dashboard.stories.tsx +504 -0
  308. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch1-deep-focus.tsx +96 -0
  309. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch2-living-docs.tsx +134 -0
  310. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch3-team-velocity.tsx +148 -0
  311. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch4-ship-your-app.tsx +100 -0
  312. package/stack-template/app/ui-kit/src/templates/experience/chapters/ch5-future.tsx +67 -0
  313. package/stack-template/app/ui-kit/src/templates/experience/chapters/hero.tsx +434 -0
  314. package/stack-template/app/ui-kit/src/templates/experience/chapters/nav-footer.tsx +85 -0
  315. package/stack-template/app/ui-kit/src/templates/experience/hero.stories.tsx +27 -0
  316. package/stack-template/app/ui-kit/src/templates/experience/hero.test.tsx +108 -0
  317. package/stack-template/app/ui-kit/src/templates/experience/index.stories.tsx +51 -0
  318. package/stack-template/app/ui-kit/src/templates/experience/lib/ChapterShell.tsx +84 -0
  319. package/stack-template/app/ui-kit/src/templates/experience/lib/SideNav.tsx +173 -0
  320. package/stack-template/app/ui-kit/src/templates/experience/lib/chapter-shell.test.tsx +266 -0
  321. package/stack-template/app/ui-kit/src/templates/experience/lib/scroll-mood.tsx +143 -0
  322. package/stack-template/app/ui-kit/src/templates/experience/lib/starfield.test.tsx +31 -0
  323. package/stack-template/app/ui-kit/src/templates/experience/lib/starfield.tsx +190 -0
  324. package/stack-template/app/ui-kit/src/templates/experience/mood-engine.stories.tsx +114 -0
  325. package/stack-template/app/ui-kit/src/templates/experience/shell-nav.stories.tsx +113 -0
  326. package/stack-template/app/ui-kit/src/templates/kanban-project.stories.tsx +352 -0
  327. package/stack-template/app/ui-kit/src/templates/landing.stories.tsx +380 -0
  328. package/stack-template/app/ui-kit/src/templates/parallax-landing.stories.tsx +633 -0
  329. package/stack-template/app/ui-kit/src/templates/settings.stories.tsx +474 -0
  330. package/stack-template/app/ui-kit/src/ui/accordion/accordion.stories.tsx +91 -0
  331. package/stack-template/app/ui-kit/src/ui/accordion/accordion.test.tsx +99 -0
  332. package/stack-template/app/ui-kit/src/ui/accordion/index.tsx +107 -0
  333. package/stack-template/app/ui-kit/src/ui/affix/affix.stories.tsx +104 -0
  334. package/stack-template/app/ui-kit/src/ui/affix/affix.test.tsx +138 -0
  335. package/stack-template/app/ui-kit/src/ui/affix/index.tsx +89 -0
  336. package/stack-template/app/ui-kit/src/ui/alert/alert.stories.tsx +149 -0
  337. package/stack-template/app/ui-kit/src/ui/alert/alert.test.tsx +85 -0
  338. package/stack-template/app/ui-kit/src/ui/alert/index.tsx +118 -0
  339. package/stack-template/app/ui-kit/src/ui/anchor/anchor.stories.tsx +96 -0
  340. package/stack-template/app/ui-kit/src/ui/anchor/anchor.test.tsx +191 -0
  341. package/stack-template/app/ui-kit/src/ui/anchor/index.tsx +144 -0
  342. package/stack-template/app/ui-kit/src/ui/auto-complete/auto-complete.stories.tsx +67 -0
  343. package/stack-template/app/ui-kit/src/ui/auto-complete/auto-complete.test.tsx +94 -0
  344. package/stack-template/app/ui-kit/src/ui/auto-complete/index.tsx +54 -0
  345. package/stack-template/app/ui-kit/src/ui/avatar/avatar.stories.tsx +132 -0
  346. package/stack-template/app/ui-kit/src/ui/avatar/avatar.test.tsx +65 -0
  347. package/stack-template/app/ui-kit/src/ui/avatar/index.tsx +48 -0
  348. package/stack-template/app/ui-kit/src/ui/avatar-group/avatar-group.stories.tsx +113 -0
  349. package/stack-template/app/ui-kit/src/ui/avatar-group/avatar-group.test.tsx +71 -0
  350. package/stack-template/app/ui-kit/src/ui/avatar-group/index.tsx +66 -0
  351. package/stack-template/app/ui-kit/src/ui/backdrop/backdrop.stories.tsx +66 -0
  352. package/stack-template/app/ui-kit/src/ui/backdrop/backdrop.test.tsx +37 -0
  353. package/stack-template/app/ui-kit/src/ui/backdrop/index.tsx +29 -0
  354. package/stack-template/app/ui-kit/src/ui/badge/badge.stories.tsx +105 -0
  355. package/stack-template/app/ui-kit/src/ui/badge/badge.test.tsx +115 -0
  356. package/stack-template/app/ui-kit/src/ui/badge/index.tsx +154 -0
  357. package/stack-template/app/ui-kit/src/ui/blockui/blockui.stories.tsx +34 -0
  358. package/stack-template/app/ui-kit/src/ui/blockui/blockui.test.tsx +29 -0
  359. package/stack-template/app/ui-kit/src/ui/blockui/index.tsx +25 -0
  360. package/stack-template/app/ui-kit/src/ui/bottom-navigation/bottom-navigation.stories.tsx +70 -0
  361. package/stack-template/app/ui-kit/src/ui/bottom-navigation/bottom-navigation.test.tsx +68 -0
  362. package/stack-template/app/ui-kit/src/ui/bottom-navigation/index.tsx +82 -0
  363. package/stack-template/app/ui-kit/src/ui/branch-fill.test.tsx +245 -0
  364. package/stack-template/app/ui-kit/src/ui/breadcrumb/breadcrumb.stories.tsx +103 -0
  365. package/stack-template/app/ui-kit/src/ui/breadcrumb/breadcrumb.test.tsx +49 -0
  366. package/stack-template/app/ui-kit/src/ui/breadcrumb/index.tsx +37 -0
  367. package/stack-template/app/ui-kit/src/ui/busy-box/busy-box.stories.tsx +30 -0
  368. package/stack-template/app/ui-kit/src/ui/busy-box/busy-box.test.tsx +29 -0
  369. package/stack-template/app/ui-kit/src/ui/busy-box/index.tsx +25 -0
  370. package/stack-template/app/ui-kit/src/ui/button/button.stories.tsx +121 -0
  371. package/stack-template/app/ui-kit/src/ui/button/button.test.tsx +207 -0
  372. package/stack-template/app/ui-kit/src/ui/button/index.tsx +128 -0
  373. package/stack-template/app/ui-kit/src/ui/calendar/calendar.stories.tsx +100 -0
  374. package/stack-template/app/ui-kit/src/ui/calendar/calendar.test.tsx +92 -0
  375. package/stack-template/app/ui-kit/src/ui/calendar/index.tsx +163 -0
  376. package/stack-template/app/ui-kit/src/ui/card/card.stories.tsx +203 -0
  377. package/stack-template/app/ui-kit/src/ui/card/card.test.tsx +135 -0
  378. package/stack-template/app/ui-kit/src/ui/card/index.tsx +84 -0
  379. package/stack-template/app/ui-kit/src/ui/carousel/carousel.stories.tsx +533 -0
  380. package/stack-template/app/ui-kit/src/ui/carousel/carousel.test.tsx +148 -0
  381. package/stack-template/app/ui-kit/src/ui/carousel/index.tsx +195 -0
  382. package/stack-template/app/ui-kit/src/ui/cascade-select/cascade-select.stories.tsx +126 -0
  383. package/stack-template/app/ui-kit/src/ui/cascade-select/cascade-select.test.tsx +132 -0
  384. package/stack-template/app/ui-kit/src/ui/cascade-select/index.tsx +87 -0
  385. package/stack-template/app/ui-kit/src/ui/chart/chart-theme.test.tsx +79 -0
  386. package/stack-template/app/ui-kit/src/ui/chart/chart.stories.tsx +278 -0
  387. package/stack-template/app/ui-kit/src/ui/chart/chart.test.tsx +103 -0
  388. package/stack-template/app/ui-kit/src/ui/chart/index.tsx +172 -0
  389. package/stack-template/app/ui-kit/src/ui/checkbox/checkbox.stories.tsx +67 -0
  390. package/stack-template/app/ui-kit/src/ui/checkbox/checkbox.test.tsx +99 -0
  391. package/stack-template/app/ui-kit/src/ui/checkbox/index.tsx +52 -0
  392. package/stack-template/app/ui-kit/src/ui/chips/chips.stories.tsx +53 -0
  393. package/stack-template/app/ui-kit/src/ui/chips/chips.test.tsx +86 -0
  394. package/stack-template/app/ui-kit/src/ui/chips/index.tsx +44 -0
  395. package/stack-template/app/ui-kit/src/ui/collapse/collapse.stories.tsx +93 -0
  396. package/stack-template/app/ui-kit/src/ui/collapse/collapse.test.tsx +128 -0
  397. package/stack-template/app/ui-kit/src/ui/collapse/index.tsx +75 -0
  398. package/stack-template/app/ui-kit/src/ui/color-picker/color-picker.stories.tsx +48 -0
  399. package/stack-template/app/ui-kit/src/ui/color-picker/color-picker.test.tsx +68 -0
  400. package/stack-template/app/ui-kit/src/ui/color-picker/index.tsx +38 -0
  401. package/stack-template/app/ui-kit/src/ui/context-menu/context-menu.stories.tsx +73 -0
  402. package/stack-template/app/ui-kit/src/ui/context-menu/context-menu.test.tsx +93 -0
  403. package/stack-template/app/ui-kit/src/ui/context-menu/index.tsx +79 -0
  404. package/stack-template/app/ui-kit/src/ui/count-up/count-up.stories.tsx +80 -0
  405. package/stack-template/app/ui-kit/src/ui/count-up/count-up.test.tsx +121 -0
  406. package/stack-template/app/ui-kit/src/ui/count-up/index.tsx +70 -0
  407. package/stack-template/app/ui-kit/src/ui/date-picker/date-picker.stories.tsx +154 -0
  408. package/stack-template/app/ui-kit/src/ui/date-picker/date-picker.test.tsx +221 -0
  409. package/stack-template/app/ui-kit/src/ui/date-picker/index.tsx +287 -0
  410. package/stack-template/app/ui-kit/src/ui/date-picker/locale-constants.ts +90 -0
  411. package/stack-template/app/ui-kit/src/ui/date-picker/locale.tsx +15 -0
  412. package/stack-template/app/ui-kit/src/ui/deferred-content/deferred-content.stories.tsx +62 -0
  413. package/stack-template/app/ui-kit/src/ui/deferred-content/deferred-content.test.tsx +94 -0
  414. package/stack-template/app/ui-kit/src/ui/deferred-content/index.tsx +61 -0
  415. package/stack-template/app/ui-kit/src/ui/descriptions/descriptions.stories.tsx +114 -0
  416. package/stack-template/app/ui-kit/src/ui/descriptions/descriptions.test.tsx +75 -0
  417. package/stack-template/app/ui-kit/src/ui/descriptions/index.tsx +48 -0
  418. package/stack-template/app/ui-kit/src/ui/divider/divider.stories.tsx +66 -0
  419. package/stack-template/app/ui-kit/src/ui/divider/divider.test.tsx +83 -0
  420. package/stack-template/app/ui-kit/src/ui/divider/index.tsx +65 -0
  421. package/stack-template/app/ui-kit/src/ui/drag-drop/drag-drop.stories.tsx +145 -0
  422. package/stack-template/app/ui-kit/src/ui/drag-drop/drag-drop.test.tsx +352 -0
  423. package/stack-template/app/ui-kit/src/ui/drag-drop/index.tsx +456 -0
  424. package/stack-template/app/ui-kit/src/ui/drawer/drawer.stories.tsx +108 -0
  425. package/stack-template/app/ui-kit/src/ui/drawer/drawer.test.tsx +132 -0
  426. package/stack-template/app/ui-kit/src/ui/drawer/index.tsx +113 -0
  427. package/stack-template/app/ui-kit/src/ui/dropdown/dropdown.stories.tsx +61 -0
  428. package/stack-template/app/ui-kit/src/ui/dropdown/dropdown.test.tsx +101 -0
  429. package/stack-template/app/ui-kit/src/ui/dropdown/index.tsx +162 -0
  430. package/stack-template/app/ui-kit/src/ui/editor/EditorInner.tsx +93 -0
  431. package/stack-template/app/ui-kit/src/ui/editor/editor.stories.tsx +37 -0
  432. package/stack-template/app/ui-kit/src/ui/editor/editor.test.tsx +84 -0
  433. package/stack-template/app/ui-kit/src/ui/editor/index.tsx +58 -0
  434. package/stack-template/app/ui-kit/src/ui/empty-state/empty-state.stories.tsx +24 -0
  435. package/stack-template/app/ui-kit/src/ui/empty-state/empty-state.test.tsx +48 -0
  436. package/stack-template/app/ui-kit/src/ui/empty-state/index.tsx +22 -0
  437. package/stack-template/app/ui-kit/src/ui/experience3d/experience3d.stories.tsx +66 -0
  438. package/stack-template/app/ui-kit/src/ui/experience3d/experience3d.test.tsx +50 -0
  439. package/stack-template/app/ui-kit/src/ui/experience3d/index.tsx +457 -0
  440. package/stack-template/app/ui-kit/src/ui/field/field-array.stories.tsx +214 -0
  441. package/stack-template/app/ui-kit/src/ui/field/field.stories.tsx +158 -0
  442. package/stack-template/app/ui-kit/src/ui/field/field.test.tsx +68 -0
  443. package/stack-template/app/ui-kit/src/ui/field/index.tsx +48 -0
  444. package/stack-template/app/ui-kit/src/ui/fieldset/fieldset.stories.tsx +49 -0
  445. package/stack-template/app/ui-kit/src/ui/fieldset/fieldset.test.tsx +88 -0
  446. package/stack-template/app/ui-kit/src/ui/fieldset/index.tsx +62 -0
  447. package/stack-template/app/ui-kit/src/ui/flex/flex.stories.tsx +96 -0
  448. package/stack-template/app/ui-kit/src/ui/flex/flex.test.tsx +79 -0
  449. package/stack-template/app/ui-kit/src/ui/flex/index.tsx +45 -0
  450. package/stack-template/app/ui-kit/src/ui/float-button/float-button.stories.tsx +82 -0
  451. package/stack-template/app/ui-kit/src/ui/float-button/float-button.test.tsx +107 -0
  452. package/stack-template/app/ui-kit/src/ui/float-button/index.tsx +124 -0
  453. package/stack-template/app/ui-kit/src/ui/galleria/galleria.stories.tsx +78 -0
  454. package/stack-template/app/ui-kit/src/ui/galleria/galleria.test.tsx +67 -0
  455. package/stack-template/app/ui-kit/src/ui/galleria/index.tsx +47 -0
  456. package/stack-template/app/ui-kit/src/ui/grid/grid.stories.tsx +179 -0
  457. package/stack-template/app/ui-kit/src/ui/grid/grid.test.tsx +286 -0
  458. package/stack-template/app/ui-kit/src/ui/grid/index.tsx +104 -0
  459. package/stack-template/app/ui-kit/src/ui/icons/icons.stories.tsx +52 -0
  460. package/stack-template/app/ui-kit/src/ui/icons/icons.test.tsx +60 -0
  461. package/stack-template/app/ui-kit/src/ui/icons/index.tsx +294 -0
  462. package/stack-template/app/ui-kit/src/ui/image/image.stories.tsx +231 -0
  463. package/stack-template/app/ui-kit/src/ui/image/image.test.tsx +79 -0
  464. package/stack-template/app/ui-kit/src/ui/image/index.tsx +76 -0
  465. package/stack-template/app/ui-kit/src/ui/inplace/index.tsx +33 -0
  466. package/stack-template/app/ui-kit/src/ui/inplace/inplace.stories.tsx +75 -0
  467. package/stack-template/app/ui-kit/src/ui/inplace/inplace.test.tsx +58 -0
  468. package/stack-template/app/ui-kit/src/ui/input/index.tsx +133 -0
  469. package/stack-template/app/ui-kit/src/ui/input/input-search.stories.tsx +112 -0
  470. package/stack-template/app/ui-kit/src/ui/input/input-search.test.tsx +116 -0
  471. package/stack-template/app/ui-kit/src/ui/input/input-search.tsx +116 -0
  472. package/stack-template/app/ui-kit/src/ui/input/input.stories.tsx +176 -0
  473. package/stack-template/app/ui-kit/src/ui/input/input.test.tsx +106 -0
  474. package/stack-template/app/ui-kit/src/ui/input-mask/index.tsx +39 -0
  475. package/stack-template/app/ui-kit/src/ui/input-mask/input-mask.stories.tsx +46 -0
  476. package/stack-template/app/ui-kit/src/ui/input-mask/input-mask.test.tsx +57 -0
  477. package/stack-template/app/ui-kit/src/ui/input-number/index.tsx +125 -0
  478. package/stack-template/app/ui-kit/src/ui/input-number/input-number.stories.tsx +190 -0
  479. package/stack-template/app/ui-kit/src/ui/input-number/input-number.test.tsx +157 -0
  480. package/stack-template/app/ui-kit/src/ui/input-otp/index.tsx +57 -0
  481. package/stack-template/app/ui-kit/src/ui/input-otp/input-otp.stories.tsx +90 -0
  482. package/stack-template/app/ui-kit/src/ui/input-otp/input-otp.test.tsx +66 -0
  483. package/stack-template/app/ui-kit/src/ui/kanban/index.tsx +277 -0
  484. package/stack-template/app/ui-kit/src/ui/kanban/kanban.stories.tsx +219 -0
  485. package/stack-template/app/ui-kit/src/ui/kanban/kanban.test.tsx +234 -0
  486. package/stack-template/app/ui-kit/src/ui/knob/index.tsx +58 -0
  487. package/stack-template/app/ui-kit/src/ui/knob/knob.stories.tsx +49 -0
  488. package/stack-template/app/ui-kit/src/ui/knob/knob.test.tsx +42 -0
  489. package/stack-template/app/ui-kit/src/ui/layout/index.tsx +145 -0
  490. package/stack-template/app/ui-kit/src/ui/layout/layout.stories.tsx +158 -0
  491. package/stack-template/app/ui-kit/src/ui/layout/layout.test.tsx +154 -0
  492. package/stack-template/app/ui-kit/src/ui/link/index.tsx +61 -0
  493. package/stack-template/app/ui-kit/src/ui/link/link.stories.tsx +68 -0
  494. package/stack-template/app/ui-kit/src/ui/link/link.test.tsx +69 -0
  495. package/stack-template/app/ui-kit/src/ui/list/index.tsx +135 -0
  496. package/stack-template/app/ui-kit/src/ui/list/list.stories.tsx +194 -0
  497. package/stack-template/app/ui-kit/src/ui/list/list.test.tsx +164 -0
  498. package/stack-template/app/ui-kit/src/ui/listbox/index.tsx +27 -0
  499. package/stack-template/app/ui-kit/src/ui/listbox/listbox.stories.tsx +57 -0
  500. package/stack-template/app/ui-kit/src/ui/listbox/listbox.test.tsx +49 -0
  501. package/stack-template/app/ui-kit/src/ui/mega-menu/index.tsx +142 -0
  502. package/stack-template/app/ui-kit/src/ui/mega-menu/mega-menu.stories.tsx +137 -0
  503. package/stack-template/app/ui-kit/src/ui/mega-menu/mega-menu.test.tsx +130 -0
  504. package/stack-template/app/ui-kit/src/ui/mention/index.tsx +76 -0
  505. package/stack-template/app/ui-kit/src/ui/mention/mention.stories.tsx +44 -0
  506. package/stack-template/app/ui-kit/src/ui/mention/mention.test.tsx +87 -0
  507. package/stack-template/app/ui-kit/src/ui/menu/index.tsx +256 -0
  508. package/stack-template/app/ui-kit/src/ui/menu/menu.stories.tsx +124 -0
  509. package/stack-template/app/ui-kit/src/ui/menu/menu.test.tsx +251 -0
  510. package/stack-template/app/ui-kit/src/ui/menubar/index.tsx +42 -0
  511. package/stack-template/app/ui-kit/src/ui/menubar/menubar.stories.tsx +66 -0
  512. package/stack-template/app/ui-kit/src/ui/menubar/menubar.test.tsx +65 -0
  513. package/stack-template/app/ui-kit/src/ui/message/index.tsx +123 -0
  514. package/stack-template/app/ui-kit/src/ui/message/message.stories.tsx +104 -0
  515. package/stack-template/app/ui-kit/src/ui/message/message.test.tsx +109 -0
  516. package/stack-template/app/ui-kit/src/ui/modal/index.tsx +142 -0
  517. package/stack-template/app/ui-kit/src/ui/modal/modal.stories.tsx +128 -0
  518. package/stack-template/app/ui-kit/src/ui/modal/modal.test.tsx +166 -0
  519. package/stack-template/app/ui-kit/src/ui/notification/index.tsx +142 -0
  520. package/stack-template/app/ui-kit/src/ui/notification/notification.stories.tsx +155 -0
  521. package/stack-template/app/ui-kit/src/ui/notification/notification.test.tsx +83 -0
  522. package/stack-template/app/ui-kit/src/ui/order-list/index.tsx +38 -0
  523. package/stack-template/app/ui-kit/src/ui/order-list/order-list.stories.tsx +38 -0
  524. package/stack-template/app/ui-kit/src/ui/order-list/order-list.test.tsx +54 -0
  525. package/stack-template/app/ui-kit/src/ui/org-chart/index.tsx +138 -0
  526. package/stack-template/app/ui-kit/src/ui/org-chart/org-chart.stories.tsx +76 -0
  527. package/stack-template/app/ui-kit/src/ui/org-chart/org-chart.test.tsx +98 -0
  528. package/stack-template/app/ui-kit/src/ui/pagination/index.tsx +102 -0
  529. package/stack-template/app/ui-kit/src/ui/pagination/pagination.stories.tsx +103 -0
  530. package/stack-template/app/ui-kit/src/ui/pagination/pagination.test.tsx +112 -0
  531. package/stack-template/app/ui-kit/src/ui/panel-menu/index.tsx +59 -0
  532. package/stack-template/app/ui-kit/src/ui/panel-menu/panel-menu.stories.tsx +96 -0
  533. package/stack-template/app/ui-kit/src/ui/panel-menu/panel-menu.test.tsx +64 -0
  534. package/stack-template/app/ui-kit/src/ui/parallax/index.tsx +62 -0
  535. package/stack-template/app/ui-kit/src/ui/parallax/parallax.stories.tsx +115 -0
  536. package/stack-template/app/ui-kit/src/ui/parallax/parallax.test.tsx +148 -0
  537. package/stack-template/app/ui-kit/src/ui/password/index.tsx +67 -0
  538. package/stack-template/app/ui-kit/src/ui/password/password.stories.tsx +43 -0
  539. package/stack-template/app/ui-kit/src/ui/password/password.test.tsx +45 -0
  540. package/stack-template/app/ui-kit/src/ui/pick-list/index.tsx +103 -0
  541. package/stack-template/app/ui-kit/src/ui/pick-list/pick-list.stories.tsx +59 -0
  542. package/stack-template/app/ui-kit/src/ui/pick-list/pick-list.test.tsx +94 -0
  543. package/stack-template/app/ui-kit/src/ui/popconfirm/index.tsx +102 -0
  544. package/stack-template/app/ui-kit/src/ui/popconfirm/popconfirm.stories.tsx +73 -0
  545. package/stack-template/app/ui-kit/src/ui/popconfirm/popconfirm.test.tsx +127 -0
  546. package/stack-template/app/ui-kit/src/ui/popover/index.tsx +136 -0
  547. package/stack-template/app/ui-kit/src/ui/popover/popover.stories.tsx +114 -0
  548. package/stack-template/app/ui-kit/src/ui/popover/popover.test.tsx +172 -0
  549. package/stack-template/app/ui-kit/src/ui/progress/index.tsx +46 -0
  550. package/stack-template/app/ui-kit/src/ui/progress/progress.stories.tsx +57 -0
  551. package/stack-template/app/ui-kit/src/ui/progress/progress.test.tsx +90 -0
  552. package/stack-template/app/ui-kit/src/ui/qr-code/index.tsx +88 -0
  553. package/stack-template/app/ui-kit/src/ui/qr-code/qr-code.stories.tsx +109 -0
  554. package/stack-template/app/ui-kit/src/ui/qr-code/qr-code.test.tsx +155 -0
  555. package/stack-template/app/ui-kit/src/ui/qr-code/qrcode-core.ts +56 -0
  556. package/stack-template/app/ui-kit/src/ui/qr-code/qrcode-generator.vendor.ts +2300 -0
  557. package/stack-template/app/ui-kit/src/ui/radio/index.tsx +62 -0
  558. package/stack-template/app/ui-kit/src/ui/radio/radio.stories.tsx +94 -0
  559. package/stack-template/app/ui-kit/src/ui/radio/radio.test.tsx +83 -0
  560. package/stack-template/app/ui-kit/src/ui/rating/index.tsx +36 -0
  561. package/stack-template/app/ui-kit/src/ui/rating/rating.stories.tsx +42 -0
  562. package/stack-template/app/ui-kit/src/ui/rating/rating.test.tsx +45 -0
  563. package/stack-template/app/ui-kit/src/ui/result/index.tsx +72 -0
  564. package/stack-template/app/ui-kit/src/ui/result/result.stories.tsx +82 -0
  565. package/stack-template/app/ui-kit/src/ui/result/result.test.tsx +57 -0
  566. package/stack-template/app/ui-kit/src/ui/reveal/index.tsx +83 -0
  567. package/stack-template/app/ui-kit/src/ui/reveal/reveal.stories.tsx +91 -0
  568. package/stack-template/app/ui-kit/src/ui/reveal/reveal.test.tsx +148 -0
  569. package/stack-template/app/ui-kit/src/ui/schedule/index.tsx +104 -0
  570. package/stack-template/app/ui-kit/src/ui/schedule/schedule.fc.test.tsx +95 -0
  571. package/stack-template/app/ui-kit/src/ui/schedule/schedule.stories.tsx +61 -0
  572. package/stack-template/app/ui-kit/src/ui/schedule/schedule.test.tsx +41 -0
  573. package/stack-template/app/ui-kit/src/ui/scroll-page/index.tsx +46 -0
  574. package/stack-template/app/ui-kit/src/ui/scroll-page/scroll-page.stories.tsx +92 -0
  575. package/stack-template/app/ui-kit/src/ui/scroll-page/scroll-page.test.tsx +51 -0
  576. package/stack-template/app/ui-kit/src/ui/scroll-panel/index.tsx +16 -0
  577. package/stack-template/app/ui-kit/src/ui/scroll-panel/scroll-panel.stories.tsx +37 -0
  578. package/stack-template/app/ui-kit/src/ui/scroll-panel/scroll-panel.test.tsx +41 -0
  579. package/stack-template/app/ui-kit/src/ui/scrolltop/index.tsx +27 -0
  580. package/stack-template/app/ui-kit/src/ui/scrolltop/scrolltop.stories.tsx +41 -0
  581. package/stack-template/app/ui-kit/src/ui/scrolltop/scrolltop.test.tsx +37 -0
  582. package/stack-template/app/ui-kit/src/ui/segmented/index.tsx +47 -0
  583. package/stack-template/app/ui-kit/src/ui/segmented/segmented.stories.tsx +126 -0
  584. package/stack-template/app/ui-kit/src/ui/segmented/segmented.test.tsx +77 -0
  585. package/stack-template/app/ui-kit/src/ui/select/index.tsx +302 -0
  586. package/stack-template/app/ui-kit/src/ui/select/select.stories.tsx +268 -0
  587. package/stack-template/app/ui-kit/src/ui/select/select.test.tsx +226 -0
  588. package/stack-template/app/ui-kit/src/ui/sidebar/index.tsx +83 -0
  589. package/stack-template/app/ui-kit/src/ui/sidebar/sidebar.stories.tsx +71 -0
  590. package/stack-template/app/ui-kit/src/ui/sidebar/sidebar.test.tsx +101 -0
  591. package/stack-template/app/ui-kit/src/ui/skeleton/index.tsx +55 -0
  592. package/stack-template/app/ui-kit/src/ui/skeleton/skeleton.stories.tsx +110 -0
  593. package/stack-template/app/ui-kit/src/ui/skeleton/skeleton.test.tsx +74 -0
  594. package/stack-template/app/ui-kit/src/ui/slide-menu/index.tsx +103 -0
  595. package/stack-template/app/ui-kit/src/ui/slide-menu/slide-menu.stories.tsx +92 -0
  596. package/stack-template/app/ui-kit/src/ui/slide-menu/slide-menu.test.tsx +120 -0
  597. package/stack-template/app/ui-kit/src/ui/slider/index.tsx +90 -0
  598. package/stack-template/app/ui-kit/src/ui/slider/slider.stories.tsx +60 -0
  599. package/stack-template/app/ui-kit/src/ui/slider/slider.test.tsx +66 -0
  600. package/stack-template/app/ui-kit/src/ui/space/index.tsx +32 -0
  601. package/stack-template/app/ui-kit/src/ui/space/space.stories.tsx +66 -0
  602. package/stack-template/app/ui-kit/src/ui/space/space.test.tsx +56 -0
  603. package/stack-template/app/ui-kit/src/ui/speed-dial/index.tsx +32 -0
  604. package/stack-template/app/ui-kit/src/ui/speed-dial/speed-dial.stories.tsx +34 -0
  605. package/stack-template/app/ui-kit/src/ui/speed-dial/speed-dial.test.tsx +34 -0
  606. package/stack-template/app/ui-kit/src/ui/spinner/index.tsx +74 -0
  607. package/stack-template/app/ui-kit/src/ui/spinner/spinner.stories.tsx +64 -0
  608. package/stack-template/app/ui-kit/src/ui/spinner/spinner.test.tsx +66 -0
  609. package/stack-template/app/ui-kit/src/ui/split-button/index.tsx +155 -0
  610. package/stack-template/app/ui-kit/src/ui/split-button/split-button.stories.tsx +137 -0
  611. package/stack-template/app/ui-kit/src/ui/split-button/split-button.test.tsx +152 -0
  612. package/stack-template/app/ui-kit/src/ui/splitter/index.tsx +49 -0
  613. package/stack-template/app/ui-kit/src/ui/splitter/splitter.stories.tsx +24 -0
  614. package/stack-template/app/ui-kit/src/ui/splitter/splitter.test.tsx +21 -0
  615. package/stack-template/app/ui-kit/src/ui/statistic/index.tsx +28 -0
  616. package/stack-template/app/ui-kit/src/ui/statistic/statistic.stories.tsx +112 -0
  617. package/stack-template/app/ui-kit/src/ui/statistic/statistic.test.tsx +39 -0
  618. package/stack-template/app/ui-kit/src/ui/steps/index.tsx +50 -0
  619. package/stack-template/app/ui-kit/src/ui/steps/steps.stories.tsx +57 -0
  620. package/stack-template/app/ui-kit/src/ui/steps/steps.test.tsx +55 -0
  621. package/stack-template/app/ui-kit/src/ui/switch/index.tsx +87 -0
  622. package/stack-template/app/ui-kit/src/ui/switch/switch.stories.tsx +123 -0
  623. package/stack-template/app/ui-kit/src/ui/switch/switch.test.tsx +98 -0
  624. package/stack-template/app/ui-kit/src/ui/tab-menu/index.tsx +33 -0
  625. package/stack-template/app/ui-kit/src/ui/tab-menu/tab-menu.stories.tsx +49 -0
  626. package/stack-template/app/ui-kit/src/ui/tab-menu/tab-menu.test.tsx +50 -0
  627. package/stack-template/app/ui-kit/src/ui/table/index.tsx +690 -0
  628. package/stack-template/app/ui-kit/src/ui/table/table-advanced.stories.tsx +91 -0
  629. package/stack-template/app/ui-kit/src/ui/table/table-advanced.test.tsx +188 -0
  630. package/stack-template/app/ui-kit/src/ui/table/table-expandable.stories.tsx +91 -0
  631. package/stack-template/app/ui-kit/src/ui/table/table-expandable.test.tsx +143 -0
  632. package/stack-template/app/ui-kit/src/ui/table/table.stories.tsx +342 -0
  633. package/stack-template/app/ui-kit/src/ui/table/table.test.tsx +465 -0
  634. package/stack-template/app/ui-kit/src/ui/table/types.ts +173 -0
  635. package/stack-template/app/ui-kit/src/ui/tabs/index.tsx +118 -0
  636. package/stack-template/app/ui-kit/src/ui/tabs/tabs.stories.tsx +113 -0
  637. package/stack-template/app/ui-kit/src/ui/tabs/tabs.test.tsx +77 -0
  638. package/stack-template/app/ui-kit/src/ui/tag/index.tsx +68 -0
  639. package/stack-template/app/ui-kit/src/ui/tag/tag.stories.tsx +88 -0
  640. package/stack-template/app/ui-kit/src/ui/tag/tag.test.tsx +126 -0
  641. package/stack-template/app/ui-kit/src/ui/team/debt-board/debt-board.stories.tsx +52 -0
  642. package/stack-template/app/ui-kit/src/ui/team/debt-board/debt-board.test.tsx +72 -0
  643. package/stack-template/app/ui-kit/src/ui/team/debt-board/index.tsx +125 -0
  644. package/stack-template/app/ui-kit/src/ui/team/inbox-thread/inbox-thread.stories.tsx +70 -0
  645. package/stack-template/app/ui-kit/src/ui/team/inbox-thread/inbox-thread.test.tsx +56 -0
  646. package/stack-template/app/ui-kit/src/ui/team/inbox-thread/index.tsx +107 -0
  647. package/stack-template/app/ui-kit/src/ui/team/ping-feed/index.tsx +102 -0
  648. package/stack-template/app/ui-kit/src/ui/team/ping-feed/ping-feed.stories.tsx +57 -0
  649. package/stack-template/app/ui-kit/src/ui/team/ping-feed/ping-feed.test.tsx +60 -0
  650. package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/index.tsx +60 -0
  651. package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/stage-pipeline.stories.tsx +68 -0
  652. package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/stage-pipeline.test.tsx +50 -0
  653. package/stack-template/app/ui-kit/src/ui/team/team-dashboard/index.tsx +103 -0
  654. package/stack-template/app/ui-kit/src/ui/team/team-dashboard/team-dashboard.stories.tsx +72 -0
  655. package/stack-template/app/ui-kit/src/ui/team/team-dashboard/team-dashboard.test.tsx +72 -0
  656. package/stack-template/app/ui-kit/src/ui/time-picker/index.tsx +143 -0
  657. package/stack-template/app/ui-kit/src/ui/time-picker/time-picker.stories.tsx +90 -0
  658. package/stack-template/app/ui-kit/src/ui/time-picker/time-picker.test.tsx +64 -0
  659. package/stack-template/app/ui-kit/src/ui/timeline/index.tsx +91 -0
  660. package/stack-template/app/ui-kit/src/ui/timeline/timeline.stories.tsx +209 -0
  661. package/stack-template/app/ui-kit/src/ui/timeline/timeline.test.tsx +116 -0
  662. package/stack-template/app/ui-kit/src/ui/timesheet/index.tsx +277 -0
  663. package/stack-template/app/ui-kit/src/ui/timesheet/timesheet.stories.tsx +97 -0
  664. package/stack-template/app/ui-kit/src/ui/timesheet/timesheet.test.tsx +103 -0
  665. package/stack-template/app/ui-kit/src/ui/toggle-button/index.tsx +28 -0
  666. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.stories.tsx +85 -0
  667. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.test.tsx +97 -0
  668. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.tsx +81 -0
  669. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button.stories.tsx +46 -0
  670. package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button.test.tsx +38 -0
  671. package/stack-template/app/ui-kit/src/ui/toolbar/index.tsx +18 -0
  672. package/stack-template/app/ui-kit/src/ui/toolbar/toolbar.stories.tsx +35 -0
  673. package/stack-template/app/ui-kit/src/ui/toolbar/toolbar.test.tsx +11 -0
  674. package/stack-template/app/ui-kit/src/ui/tooltip/index.tsx +61 -0
  675. package/stack-template/app/ui-kit/src/ui/tooltip/tooltip.stories.tsx +81 -0
  676. package/stack-template/app/ui-kit/src/ui/tooltip/tooltip.test.tsx +120 -0
  677. package/stack-template/app/ui-kit/src/ui/tour/index.tsx +210 -0
  678. package/stack-template/app/ui-kit/src/ui/tour/tour.stories.tsx +153 -0
  679. package/stack-template/app/ui-kit/src/ui/tour/tour.test.tsx +131 -0
  680. package/stack-template/app/ui-kit/src/ui/transition/index.tsx +377 -0
  681. package/stack-template/app/ui-kit/src/ui/transition/transition.stories.tsx +254 -0
  682. package/stack-template/app/ui-kit/src/ui/transition/transition.test.tsx +285 -0
  683. package/stack-template/app/ui-kit/src/ui/tree/index.tsx +68 -0
  684. package/stack-template/app/ui-kit/src/ui/tree/tree.stories.tsx +139 -0
  685. package/stack-template/app/ui-kit/src/ui/tree/tree.test.tsx +77 -0
  686. package/stack-template/app/ui-kit/src/ui/tree-select/index.tsx +251 -0
  687. package/stack-template/app/ui-kit/src/ui/tree-select/tree-select.stories.tsx +105 -0
  688. package/stack-template/app/ui-kit/src/ui/tree-select/tree-select.test.tsx +174 -0
  689. package/stack-template/app/ui-kit/src/ui/tree-table/index.tsx +229 -0
  690. package/stack-template/app/ui-kit/src/ui/tree-table/tree-table.stories.tsx +111 -0
  691. package/stack-template/app/ui-kit/src/ui/tree-table/tree-table.test.tsx +137 -0
  692. package/stack-template/app/ui-kit/src/ui/typography/index.tsx +124 -0
  693. package/stack-template/app/ui-kit/src/ui/typography/typography.stories.tsx +65 -0
  694. package/stack-template/app/ui-kit/src/ui/typography/typography.test.tsx +117 -0
  695. package/stack-template/app/ui-kit/src/ui/upload/index.tsx +39 -0
  696. package/stack-template/app/ui-kit/src/ui/upload/upload-core.tsx +204 -0
  697. package/stack-template/app/ui-kit/src/ui/upload/upload-dropzone.tsx +79 -0
  698. package/stack-template/app/ui-kit/src/ui/upload/upload.stories.tsx +67 -0
  699. package/stack-template/app/ui-kit/src/ui/upload/upload.test.tsx +204 -0
  700. package/stack-template/app/ui-kit/src/ui/virtual-scroll/index.tsx +86 -0
  701. package/stack-template/app/ui-kit/src/ui/virtual-scroll/virtual-scroll.stories.tsx +111 -0
  702. package/stack-template/app/ui-kit/src/ui/virtual-scroll/virtual-scroll.test.tsx +125 -0
  703. package/stack-template/app/ui-kit/src/ui/watermark/index.tsx +182 -0
  704. package/stack-template/app/ui-kit/src/ui/watermark/watermark.stories.tsx +96 -0
  705. package/stack-template/app/ui-kit/src/ui/watermark/watermark.test.tsx +120 -0
  706. package/stack-template/app/ui-kit/src/utils/array.test.ts +88 -0
  707. package/stack-template/app/ui-kit/src/utils/array.ts +51 -0
  708. package/stack-template/app/ui-kit/src/utils/dom.test.tsx +69 -0
  709. package/stack-template/app/ui-kit/src/utils/dom.ts +38 -0
  710. package/stack-template/app/ui-kit/src/utils/format.test.ts +63 -0
  711. package/stack-template/app/ui-kit/src/utils/format.ts +81 -0
  712. package/stack-template/app/ui-kit/tests/setup.ts +15 -0
  713. package/stack-template/app/ui-kit/tsconfig.json +18 -0
  714. package/stack-template/app/ui-kit/tsup.config.ts +37 -0
  715. package/stack-template/app/ui-kit/vercel.json +6 -0
  716. package/stack-template/app/ui-kit/vitest.config.ts +22 -0
  717. package/stack-template/contracts/auth/token-contract.md +119 -0
  718. package/stack-template/contracts/auth/users.json +35 -0
  719. package/stack-template/contracts/db/tasks-schema.sql +62 -0
  720. package/stack-template/contracts/events/fixtures/task.assigned.json +11 -0
  721. package/stack-template/contracts/events/fixtures/task.assignment_failed.json +11 -0
  722. package/stack-template/contracts/events/fixtures/task.created.json +12 -0
  723. package/stack-template/contracts/events/fixtures/task.deleted.json +10 -0
  724. package/stack-template/contracts/events/fixtures/task.updated.json +12 -0
  725. package/stack-template/contracts/events/task-events.md +80 -0
  726. package/stack-template/contracts/openapi/activity.yaml +196 -0
  727. package/stack-template/contracts/openapi/auth.yaml +310 -0
  728. package/stack-template/contracts/openapi/tasks.yaml +316 -0
  729. package/stack-template/contracts/openapi/users.yaml +345 -0
  730. package/stack-template/docs/adr/0001-mixed-stack.md +14 -0
  731. package/stack-template/docs/adr/0002-mf-rspack.md +14 -0
  732. package/stack-template/docs/adr/0003-contract-first.md +14 -0
  733. package/stack-template/docs/adr/0004-readonly-schema-tradeoff.md +14 -0
  734. package/stack-template/docs/adr/0005-fail-closed.md +14 -0
  735. package/stack-template/docs/adr/0006-fire-and-forget-events.md +14 -0
  736. package/stack-template/docs/adr/0007-fork-not-upgrade.md +14 -0
  737. package/stack-template/docs/adr/0008-kafka-outbox-saga.md +24 -0
  738. package/stack-template/docs/adr/0009-ui-kit-split.md +39 -0
  739. package/stack-template/docs/adr/README.md +15 -0
  740. package/stack-template/docs/ai/recipes.md +956 -0
  741. package/stack-template/docs/ai/table-Theming.md +25 -0
  742. package/stack-template/docs/ai/table-datadisplay-mz.md +20 -0
  743. package/stack-template/docs/ai/table-feedback.md +20 -0
  744. package/stack-template/docs/ai/table-forms.md +26 -0
  745. package/stack-template/docs/git-flow.md +70 -0
  746. package/stack-template/docs/parity-matrix.md +102 -0
  747. package/stack-template/docs/superpowers/contexts/auth-real/gap-answer.md +195 -0
  748. package/stack-template/docs/superpowers/contexts/auth-real/sf-1.md +21 -0
  749. package/stack-template/docs/superpowers/contexts/auth-real/sf-2.md +21 -0
  750. package/stack-template/docs/superpowers/contexts/auth-real/sf-3.md +17 -0
  751. package/stack-template/docs/superpowers/contexts/auth-real/sf-4.md +20 -0
  752. package/stack-template/docs/superpowers/contexts/auth-real/sf-5.md +21 -0
  753. package/stack-template/docs/superpowers/contexts/experience-design.md +85 -0
  754. package/stack-template/docs/superpowers/contexts/sf-1.md +39 -0
  755. package/stack-template/docs/superpowers/contexts/sf-2.md +42 -0
  756. package/stack-template/docs/superpowers/contexts/sf-3.md +42 -0
  757. package/stack-template/docs/superpowers/contexts/sf-4.md +26 -0
  758. package/stack-template/docs/superpowers/contexts/sf-5.md +36 -0
  759. package/stack-template/docs/superpowers/contexts/sf-6.md +36 -0
  760. package/stack-template/docs/superpowers/contexts/sf-7.md +35 -0
  761. package/stack-template/docs/superpowers/contexts/sf-cin-overview.md +21 -0
  762. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-1.md +46 -0
  763. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-2.md +44 -0
  764. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-3.md +47 -0
  765. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-4.md +44 -0
  766. package/stack-template/docs/superpowers/contexts/ui-redesign/sf-5.md +36 -0
  767. package/stack-template/docs/superpowers/designs/direction-approved.md +11 -0
  768. package/stack-template/docs/superpowers/designs/ui-redesign/drafts/a-roulette-soundviz.html +353 -0
  769. package/stack-template/docs/superpowers/designs/ui-redesign/drafts/b-reference.html +347 -0
  770. package/stack-template/docs/superpowers/designs/ui-redesign/drafts/c-designer.html +375 -0
  771. package/stack-template/docs/superpowers/designs/ui-redesign/ds-demo.html +140 -0
  772. package/stack-template/docs/superpowers/designs/ui-redesign-direction.md +93 -0
  773. package/stack-template/docs/superpowers/improvements-log.md +158 -0
  774. package/stack-template/docs/superpowers/mindmaps/auth-real.wakii +115 -0
  775. package/stack-template/docs/superpowers/mindmaps/kafka-outbox-saga.wakii +110 -0
  776. package/stack-template/docs/superpowers/mindmaps/micro-boilerplate.wakii +171 -0
  777. package/stack-template/docs/superpowers/mindmaps/ui-redesign.wakii +116 -0
  778. package/stack-template/docs/superpowers/mindmaps/vu53-cinematic-experience.wakii +32 -0
  779. package/stack-template/docs/superpowers/plans/2026-10-12-sf-1-contracts-platform-plan.md +44 -0
  780. package/stack-template/docs/superpowers/plans/2026-10-12-sf-3-spring-svc-impact.md +69 -0
  781. package/stack-template/docs/superpowers/plans/2026-10-12-sf-3-spring-svc-plan.md +27 -0
  782. package/stack-template/docs/superpowers/plans/2026-10-12-sf-4-go-svc-plan.md +99 -0
  783. package/stack-template/docs/superpowers/plans/2026-10-12-sf-5-fe-shell-plan.md +64 -0
  784. package/stack-template/docs/superpowers/plans/2026-10-12-sf-6-fe-remotes-plan.md +83 -0
  785. package/stack-template/docs/superpowers/plans/2026-10-12-sf-7-convergence-plan.md +59 -0
  786. package/stack-template/docs/superpowers/plans/2026-10-12-sf2-node-svc-plan.md +19 -0
  787. package/stack-template/docs/superpowers/plans/2026-10-13-sf-1-kafka-foundation-plan.md +30 -0
  788. package/stack-template/docs/superpowers/plans/2026-10-13-sf-1-ui-redesign-plan.md +28 -0
  789. package/stack-template/docs/superpowers/plans/2026-10-13-sf-2-node-outbox-plan.md +46 -0
  790. package/stack-template/docs/superpowers/plans/2026-10-13-sf-3-go-consumer-plan.md +31 -0
  791. package/stack-template/docs/superpowers/plans/2026-10-13-sf-4-spring-tx-plan.md +96 -0
  792. package/stack-template/docs/superpowers/plans/2026-10-13-sf-5-convergence-plan.md +21 -0
  793. package/stack-template/docs/superpowers/plans/2026-10-14-sf-2-ui-redesign-plan.md +32 -0
  794. package/stack-template/docs/superpowers/plans/2026-10-14-sf-3-ui-redesign-plan.md +34 -0
  795. package/stack-template/docs/superpowers/plans/2026-10-14-sf-5-ui-redesign-plan.md +35 -0
  796. package/stack-template/docs/superpowers/plans/2026-10-17-auth-real-plan.md +112 -0
  797. package/stack-template/docs/superpowers/plans/2026-10-17-ui-kit-split-plan.md +18 -0
  798. package/stack-template/docs/superpowers/reviews/2026-10-18-data-display-coverage.md +52 -0
  799. package/stack-template/docs/superpowers/reviews/code-reviewer-sf-5-r1.md +65 -0
  800. package/stack-template/docs/superpowers/reviews/security-audit-sf-5-auth-real.md +39 -0
  801. package/stack-template/docs/superpowers/specs/2026-10-12-boilerplate-microservice-mfe.md +110 -0
  802. package/stack-template/docs/superpowers/specs/2026-10-12-sf-3-spring-svc-design.md +160 -0
  803. package/stack-template/docs/superpowers/specs/2026-10-12-sf-7-convergence-spec.md +114 -0
  804. package/stack-template/docs/superpowers/specs/2026-10-12-sf2-node-svc-spec.md +42 -0
  805. package/stack-template/docs/superpowers/specs/2026-10-13-kafka-outbox-saga.md +111 -0
  806. package/stack-template/docs/superpowers/specs/2026-10-13-ui-redesign.md +173 -0
  807. package/stack-template/docs/superpowers/specs/2026-10-14-sf-3-ui-redesign.md +46 -0
  808. package/stack-template/docs/superpowers/specs/2026-10-14-sf-5-ui-redesign.md +30 -0
  809. package/stack-template/docs/superpowers/specs/2026-10-17-antd-look-tokens.md +28 -0
  810. package/stack-template/docs/superpowers/specs/2026-10-17-auth-real-design.md +124 -0
  811. package/stack-template/docs/superpowers/specs/2026-10-17-tailwind-migration.md +32 -0
  812. package/stack-template/docs/superpowers/specs/2026-10-17-ui-kit-split.md +44 -0
  813. package/stack-template/docs/superpowers/specs/2026-10-18-0.3.0-release-notes.md +77 -0
  814. package/stack-template/docs/toolchain.md +28 -0
  815. package/stack-template/docs/wakii-playbook.md +172 -0
  816. package/stack-template/docs/walkthrough.md +204 -0
  817. package/stack-template/orca.yaml +146 -0
  818. package/stack-template/package.json +19 -0
  819. package/stack-template/platform/.env.example +72 -0
  820. package/stack-template/platform/conventions/01-dockerfile-pattern.md +78 -0
  821. package/stack-template/platform/conventions/02-healthcheck.md +26 -0
  822. package/stack-template/platform/conventions/03-logging.md +41 -0
  823. package/stack-template/platform/conventions/04-error-envelope.md +41 -0
  824. package/stack-template/platform/conventions/05-ports.md +38 -0
  825. package/stack-template/platform/conventions/06-configuration.md +25 -0
  826. package/stack-template/platform/conventions/07-cors.md +23 -0
  827. package/stack-template/platform/conventions/08-gateway-and-remotes.md +33 -0
  828. package/stack-template/platform/conventions/09-async-messaging.md +42 -0
  829. package/stack-template/platform/conventions/README.md +15 -0
  830. package/stack-template/platform/docker-compose.yml +255 -0
  831. package/stack-template/platform/gateway/nginx/nginx.conf +137 -0
  832. package/stack-template/platform/postgres/init/01-init.sh +55 -0
  833. package/stack-template/pnpm-lock.yaml +15992 -0
  834. package/stack-template/pnpm-workspace.yaml +24 -0
  835. package/stack-template/scripts/scaffold/scaffold.sh +110 -0
  836. package/stack-template/scripts/smoke/e2e.sh +305 -0
  837. package/stack-template/scripts/snapshot-stack-template.sh +84 -0
  838. package/stack-template/services/auth-svc/.dockerignore +5 -0
  839. package/stack-template/services/auth-svc/Dockerfile +32 -0
  840. package/stack-template/services/auth-svc/README.md +101 -0
  841. package/stack-template/services/auth-svc/drizzle/0000_init.sql +25 -0
  842. package/stack-template/services/auth-svc/drizzle/meta/0000_snapshot.json +190 -0
  843. package/stack-template/services/auth-svc/drizzle/meta/_journal.json +13 -0
  844. package/stack-template/services/auth-svc/drizzle.config.ts +10 -0
  845. package/stack-template/services/auth-svc/package.json +35 -0
  846. package/stack-template/services/auth-svc/pnpm-lock.yaml +2425 -0
  847. package/stack-template/services/auth-svc/src/app.test.ts +403 -0
  848. package/stack-template/services/auth-svc/src/app.ts +103 -0
  849. package/stack-template/services/auth-svc/src/auth-crypto.test.ts +32 -0
  850. package/stack-template/services/auth-svc/src/auth-crypto.ts +25 -0
  851. package/stack-template/services/auth-svc/src/db/client.ts +24 -0
  852. package/stack-template/services/auth-svc/src/db/migrate.ts +72 -0
  853. package/stack-template/services/auth-svc/src/db/schema.ts +39 -0
  854. package/stack-template/services/auth-svc/src/db/seed.ts +60 -0
  855. package/stack-template/services/auth-svc/src/env.test.ts +55 -0
  856. package/stack-template/services/auth-svc/src/env.ts +57 -0
  857. package/stack-template/services/auth-svc/src/logger.ts +31 -0
  858. package/stack-template/services/auth-svc/src/plugins/auth.ts +70 -0
  859. package/stack-template/services/auth-svc/src/repo.drizzle.integration.test.ts +182 -0
  860. package/stack-template/services/auth-svc/src/repo.drizzle.ts +144 -0
  861. package/stack-template/services/auth-svc/src/repo.test-support.ts +168 -0
  862. package/stack-template/services/auth-svc/src/repo.ts +60 -0
  863. package/stack-template/services/auth-svc/src/routes/auth.ts +193 -0
  864. package/stack-template/services/auth-svc/src/routes/health.ts +40 -0
  865. package/stack-template/services/auth-svc/src/server.ts +54 -0
  866. package/stack-template/services/auth-svc/tsconfig.json +20 -0
  867. package/stack-template/services/go-svc/.dockerignore +5 -0
  868. package/stack-template/services/go-svc/Dockerfile +19 -0
  869. package/stack-template/services/go-svc/README.md +93 -0
  870. package/stack-template/services/go-svc/cmd/server/main.go +105 -0
  871. package/stack-template/services/go-svc/go.mod +12 -0
  872. package/stack-template/services/go-svc/internal/api/auth.go +83 -0
  873. package/stack-template/services/go-svc/internal/api/auth_test.go +92 -0
  874. package/stack-template/services/go-svc/internal/api/envelope.go +61 -0
  875. package/stack-template/services/go-svc/internal/api/envelope_test.go +51 -0
  876. package/stack-template/services/go-svc/internal/api/fakes_test.go +105 -0
  877. package/stack-template/services/go-svc/internal/api/feed.go +98 -0
  878. package/stack-template/services/go-svc/internal/api/feed_test.go +118 -0
  879. package/stack-template/services/go-svc/internal/api/health.go +34 -0
  880. package/stack-template/services/go-svc/internal/api/health_test.go +46 -0
  881. package/stack-template/services/go-svc/internal/api/json.go +13 -0
  882. package/stack-template/services/go-svc/internal/api/middleware.go +82 -0
  883. package/stack-template/services/go-svc/internal/api/middleware_test.go +48 -0
  884. package/stack-template/services/go-svc/internal/api/openapi/activity.yaml +196 -0
  885. package/stack-template/services/go-svc/internal/api/openapi.go +29 -0
  886. package/stack-template/services/go-svc/internal/api/openapi_test.go +38 -0
  887. package/stack-template/services/go-svc/internal/api/router.go +86 -0
  888. package/stack-template/services/go-svc/internal/api/stats.go +63 -0
  889. package/stack-template/services/go-svc/internal/api/stats_test.go +83 -0
  890. package/stack-template/services/go-svc/internal/api/types.go +32 -0
  891. package/stack-template/services/go-svc/internal/apperr/apperr.go +9 -0
  892. package/stack-template/services/go-svc/internal/config/config.go +115 -0
  893. package/stack-template/services/go-svc/internal/config/config_test.go +92 -0
  894. package/stack-template/services/go-svc/internal/consumer/envelope.go +78 -0
  895. package/stack-template/services/go-svc/internal/consumer/envelope_test.go +154 -0
  896. package/stack-template/services/go-svc/internal/consumer/handler.go +91 -0
  897. package/stack-template/services/go-svc/internal/consumer/handler_test.go +136 -0
  898. package/stack-template/services/go-svc/internal/consumer/producer.go +117 -0
  899. package/stack-template/services/go-svc/internal/consumer/runner.go +194 -0
  900. package/stack-template/services/go-svc/internal/consumer/runner_test.go +351 -0
  901. package/stack-template/services/go-svc/internal/logging/logging.go +49 -0
  902. package/stack-template/services/go-svc/internal/model/model.go +37 -0
  903. package/stack-template/services/go-svc/internal/resolve/resolver.go +134 -0
  904. package/stack-template/services/go-svc/internal/resolve/resolver_test.go +82 -0
  905. package/stack-template/services/go-svc/internal/resolve/token.go +130 -0
  906. package/stack-template/services/go-svc/internal/resolve/token_test.go +151 -0
  907. package/stack-template/services/go-svc/internal/store/events.go +71 -0
  908. package/stack-template/services/go-svc/internal/store/migrate.go +90 -0
  909. package/stack-template/services/go-svc/internal/store/migrate_test.go +34 -0
  910. package/stack-template/services/go-svc/internal/store/migrations/0001_create_events.sql +20 -0
  911. package/stack-template/services/go-svc/internal/store/migrations/0002_widen_action_cascade.sql +14 -0
  912. package/stack-template/services/go-svc/internal/store/store.go +65 -0
  913. package/stack-template/services/go-svc/internal/store/tasks.go +109 -0
  914. package/stack-template/services/go-svc/internal/swagger/assets/LICENSE +202 -0
  915. package/stack-template/services/go-svc/internal/swagger/assets/NOTICE +2 -0
  916. package/stack-template/services/go-svc/internal/swagger/assets/favicon-16x16.png +0 -0
  917. package/stack-template/services/go-svc/internal/swagger/assets/favicon-32x32.png +0 -0
  918. package/stack-template/services/go-svc/internal/swagger/assets/swagger-ui-bundle.js +2 -0
  919. package/stack-template/services/go-svc/internal/swagger/assets/swagger-ui.css +3 -0
  920. package/stack-template/services/go-svc/internal/swagger/index.html +28 -0
  921. package/stack-template/services/go-svc/internal/swagger/swagger.go +38 -0
  922. package/stack-template/services/go-svc/test/integration/integration_test.go +523 -0
  923. package/stack-template/services/node-svc/.dockerignore +5 -0
  924. package/stack-template/services/node-svc/Dockerfile +27 -0
  925. package/stack-template/services/node-svc/README.md +155 -0
  926. package/stack-template/services/node-svc/drizzle/0000_init.sql +17 -0
  927. package/stack-template/services/node-svc/drizzle/0001_status-assignment-failed.sql +2 -0
  928. package/stack-template/services/node-svc/drizzle/0002_outbox-table.sql +7 -0
  929. package/stack-template/services/node-svc/drizzle/meta/0000_snapshot.json +136 -0
  930. package/stack-template/services/node-svc/drizzle/meta/0001_snapshot.json +136 -0
  931. package/stack-template/services/node-svc/drizzle/meta/0002_snapshot.json +180 -0
  932. package/stack-template/services/node-svc/drizzle/meta/_journal.json +27 -0
  933. package/stack-template/services/node-svc/drizzle.config.ts +10 -0
  934. package/stack-template/services/node-svc/package.json +39 -0
  935. package/stack-template/services/node-svc/pnpm-lock.yaml +2706 -0
  936. package/stack-template/services/node-svc/src/app.test.ts +611 -0
  937. package/stack-template/services/node-svc/src/app.ts +126 -0
  938. package/stack-template/services/node-svc/src/clients/spring.ts +53 -0
  939. package/stack-template/services/node-svc/src/compensation-consumer.test.ts +157 -0
  940. package/stack-template/services/node-svc/src/compensation-consumer.ts +170 -0
  941. package/stack-template/services/node-svc/src/db/client.ts +23 -0
  942. package/stack-template/services/node-svc/src/db/migrate.ts +63 -0
  943. package/stack-template/services/node-svc/src/db/schema-diff.test.ts +252 -0
  944. package/stack-template/services/node-svc/src/db/schema.ts +64 -0
  945. package/stack-template/services/node-svc/src/env.ts +52 -0
  946. package/stack-template/services/node-svc/src/logger.ts +18 -0
  947. package/stack-template/services/node-svc/src/outbox-relay.test.ts +141 -0
  948. package/stack-template/services/node-svc/src/outbox-relay.ts +182 -0
  949. package/stack-template/services/node-svc/src/plugins/auth.ts +76 -0
  950. package/stack-template/services/node-svc/src/repo.drizzle.test.ts +182 -0
  951. package/stack-template/services/node-svc/src/repo.drizzle.ts +158 -0
  952. package/stack-template/services/node-svc/src/repo.ts +73 -0
  953. package/stack-template/services/node-svc/src/routes/health.ts +42 -0
  954. package/stack-template/services/node-svc/src/routes/tasks.ts +287 -0
  955. package/stack-template/services/node-svc/src/server.ts +91 -0
  956. package/stack-template/services/node-svc/src/types/api.d.ts +391 -0
  957. package/stack-template/services/node-svc/src/types/log.ts +3 -0
  958. package/stack-template/services/node-svc/tsconfig.json +20 -0
  959. package/stack-template/services/spring-svc/.dockerignore +5 -0
  960. package/stack-template/services/spring-svc/.mvn/wrapper/maven-wrapper.properties +20 -0
  961. package/stack-template/services/spring-svc/Dockerfile +22 -0
  962. package/stack-template/services/spring-svc/README.md +121 -0
  963. package/stack-template/services/spring-svc/mvnw +332 -0
  964. package/stack-template/services/spring-svc/mvnw.cmd +206 -0
  965. package/stack-template/services/spring-svc/pom.xml +144 -0
  966. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/SpringSvcApplication.java +12 -0
  967. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/Team.java +64 -0
  968. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/TeamRepository.java +34 -0
  969. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/User.java +72 -0
  970. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/UserRepository.java +10 -0
  971. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/logging/LowercaseLevelJsonProvider.java +24 -0
  972. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/security/JwtAuthFilter.java +89 -0
  973. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/security/JwtVerifier.java +48 -0
  974. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/service/TeamService.java +84 -0
  975. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ApiError.java +15 -0
  976. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ApiException.java +37 -0
  977. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/DevCorsConfig.java +41 -0
  978. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ErrorEnvelope.java +27 -0
  979. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/GlobalExceptionHandler.java +90 -0
  980. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/HealthController.java +46 -0
  981. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ReadinessService.java +40 -0
  982. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/TeamController.java +79 -0
  983. package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/UserController.java +187 -0
  984. package/stack-template/services/spring-svc/src/main/java/db/migration/V2__SeedUsers.java +66 -0
  985. package/stack-template/services/spring-svc/src/main/resources/application.yml +42 -0
  986. package/stack-template/services/spring-svc/src/main/resources/db/migration/V1__init.sql +24 -0
  987. package/stack-template/services/spring-svc/src/main/resources/logback-spring.xml +34 -0
  988. package/stack-template/services/spring-svc/src/main/resources/openapi/users.yaml +345 -0
  989. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/logging/LogShapeTest.java +39 -0
  990. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/security/JwtAuthFilterTest.java +106 -0
  991. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/seed/SeedMatchIntegrationTest.java +68 -0
  992. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/service/TeamServiceRollbackTest.java +122 -0
  993. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/DevCorsTest.java +45 -0
  994. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/HealthCheckTest.java +56 -0
  995. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/TeamApiTest.java +139 -0
  996. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/TestPingController.java +21 -0
  997. package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/UserApiTest.java +182 -0
  998. package/stack-template/stack-manifest.json +285 -0
@@ -0,0 +1,24 @@
1
+ packages:
2
+ # FE workspace — từ story VU-53 SF-1: app/shared/src/{styles,ui} do design-system
3
+ # SF sở hữu (SF-2/3/4 consume); 4 file logic fe-shared + mfToolkit READ-LOCKED
4
+ - "app/*"
5
+ # Spike MF/Rspack (SF-1) — xoá được sau khi pin versions chốt
6
+ - "app/spike/*"
7
+ # [FLAG coordinator duyệt] SF-6 (FI-74) thêm — remotes phải vào workspace để dùng
8
+ # workspace:* (fe-shared) + catalog: (singletons); REQUIREMENT-GAP đã comment epic FI-62
9
+ - "app/remotes/*"
10
+ # node-svc (SF-2 điền impl) — spring-svc/go-svc không thuộc pnpm workspace
11
+ - "services/node-svc"
12
+ # auth-svc (VU-59 SF-2 / VU-61) — standalone lockfile như node-svc
13
+ - "services/auth-svc"
14
+
15
+ # Catalog — single source versions cho MF singletons (SF-5/6 import cùng pin).
16
+ # Nguồn: SF-1 spike + SF-5 re-validation (GAP epic FI-62 2026-10-12). Coordinator sở hữu.
17
+ catalog:
18
+ react: 19.3.0
19
+ react-dom: 19.3.0
20
+ react-router: ^7.9.0
21
+ "@module-federation/enhanced": 0.21.6
22
+ "@rspack/core": 1.7.12
23
+ # react-query singleton (libs adopt 2026-10-17) — share cache tasks↔activity qua MF
24
+ "@tanstack/react-query": ^5.0.0
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # scaffold.sh — sinh project MỚI từ boilerplate (SF-7, FI-75).
4
+ #
5
+ # Copy + rename + prune thuần (tar-based — KHÔNG rsync, KHÔNG generator framework,
6
+ # đúng spec epic: "copy + rename + prune"). Project mới cùng flow chạy được.
7
+ #
8
+ # Usage:
9
+ # bash scripts/scaffold/scaffold.sh <new-name> [--out <dir>]
10
+ # <new-name> tên project mới (lowercase, chữ/số/dấu gạch — dùng làm scope)
11
+ # --out <dir> thư mục output (default: <cwd>/<new-name>)
12
+ #
13
+ # Prune (không copy): .git · node_modules · target/ · dist/ · docs/superpowers ·
14
+ # app/spike · .github/workflow-templates · .github/workflows/convergence.yml
15
+ # (pin story branch — chết trong repo mới) · .story-brief.md · .env
16
+ #
17
+ # Rename: @wakii/* → @<new-name>/* (toàn bộ package.json + pnpm-lock.yaml) ·
18
+ # root package name → <new-name> · compose `name:` → <new-name> · README title.
19
+ #
20
+ # Lưu ý pnpm-lock: importers của thư mục bị prune (vd app/spike) còn sót
21
+ # trong lockfile — pnpm tự reconcile ở lần `pnpm install --no-frozen-lockfile`
22
+ # ĐẦU TIÊN (bắt buộc — đã ghi trong SCAFFOLD.md output). Không tự strip tay
23
+ # bằng sed/awk — rủi ro corrupt lockfile lớn hơn lợi ích.
24
+ # ============================================================================
25
+ set -euo pipefail
26
+
27
+ usage() { echo "usage: $0 <new-name> [--out <dir>]" >&2; exit 1; }
28
+ [ $# -ge 1 ] || usage
29
+ NAME="$1"; shift
30
+ [ "${1:-}" = "--out" ] && { OUT="$2"; shift 2; } || OUT=""
31
+ [ $# -eq 0 ] || usage
32
+
33
+ echo "$NAME" | grep -qE '^[a-z0-9][a-z0-9-]*$' || { echo "LỖI: new-name phải lowercase [a-z0-9-]: '$NAME'" >&2; exit 1; }
34
+
35
+ SRC="$(cd "$(dirname "$0")/../.." && pwd)" # repo root (script ở scripts/scaffold/)
36
+ [ -f "$SRC/pnpm-workspace.yaml" ] || { echo "LỖI: không tìm thấy repo root tại $SRC" >&2; exit 1; }
37
+ OUT="${OUT:-$PWD/$NAME}"
38
+ [ ! -e "$OUT" ] || { echo "LỖI: output đã tồn tại: $OUT" >&2; exit 1; }
39
+ # chặn OUT nằm TRONG source (tar copy-into-self ô nhiễm output — P0 code-review SF-7)
40
+ # python3 thay realpath -m: BSD realpath (macOS) không có -m — fix portability 2026-10-17
41
+ OUT_REAL="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$OUT")"
42
+ case "$OUT_REAL" in "$SRC"/*) echo "LỖI: --out không được nằm trong repo nguồn: $OUT" >&2; exit 1;; esac
43
+
44
+ # sed -i BSD (macOS) bắt buộc tham số backup ('') — GNU không. Detect 1 lần (fix portability 2026-10-17)
45
+ if sed --version >/dev/null 2>&1; then SED_I=(sed -i); else SED_I=(sed -i ''); fi
46
+
47
+ echo "[scaffold] copy $SRC → $OUT (prune boilerplate-infra)"
48
+ mkdir -p "$OUT"
49
+ tar -C "$SRC" -cf - \
50
+ --exclude='./.git' \
51
+ --exclude='./node_modules' \
52
+ --exclude='*/node_modules' \
53
+ --exclude='*/node_modules/*' \
54
+ --exclude='./*/node_modules' \
55
+ --exclude='*/target' \
56
+ --exclude='*/dist' \
57
+ --exclude='./docs/superpowers' \
58
+ --exclude='./app/spike' \
59
+ --exclude='./.github/workflow-templates' \
60
+ --exclude='./.github/workflows/convergence.yml' \
61
+ --exclude='./.story-brief.md' \
62
+ --exclude='.env' \
63
+ . | tar -C "$OUT" -xf -
64
+
65
+ echo "[scaffold] rename @wakii/* → @$NAME/* (package.json + source imports + Dockerfile + yml + md + lockfile)"
66
+ find "$OUT" \( -name package.json -o -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.css' -o -name '*.mjs' \
67
+ -o -name 'Dockerfile*' -o -name '*.yml' -o -name '*.yaml' -o -name '*.md' \) \
68
+ -not -path '*/node_modules/*' -not -path '*/target/*' -not -path '*/dist/*' \
69
+ -exec "${SED_I[@]}" "s/@wakii\//@$NAME\//g" {} +
70
+ "${SED_I[@]}" "s/@wakii\//@$NAME\//g" "$OUT/pnpm-lock.yaml"
71
+
72
+ echo "[scaffold] rename root package name + compose name + README title + orca.yaml"
73
+ "${SED_I[@]}" "s/\"name\": \"[^\"]*\"/\"name\": \"$NAME\"/" "$OUT/package.json"
74
+ "${SED_I[@]}" "s/^name: boilerplate/name: $NAME/" "$OUT/platform/docker-compose.yml"
75
+ "${SED_I[@]}" "1s/^# Boilerplate Microservice + Micro-frontend/# $NAME (scaffolded từ boilerplate microservice + micro-frontend)/" "$OUT/README.md"
76
+ "${SED_I[@]}" "s/^name: architecture-overview/name: $NAME/" "$OUT/orca.yaml"
77
+
78
+ cat > "$OUT/SCAFFOLD.md" <<EOF
79
+ # Scaffold: $NAME
80
+
81
+ Sinh từ boilerplate epic FI-62 bởi \`scripts/scaffold/scaffold.sh\` ngày $(date +%F).
82
+
83
+ ## Đổi tên đã áp dụng
84
+ - pnpm scope \`@wakii/*\` → \`@$NAME/*\` (package.json + pnpm-lock.yaml)
85
+ - root package name → \`$NAME\`; compose project name → \`$NAME\`; README title
86
+
87
+ ## Bước tiếp theo (bắt buộc theo thứ tự)
88
+ 1. \`git init\` + commit đầu tiên.
89
+ 2. \`pnpm install --no-frozen-lockfile\` — LẦN ĐẦU PHẢI non-frozen: lockfile còn
90
+ giữ importers của thư mục đã prune (app/spike); pnpm tự reconcile.
91
+ Từ lần sau dùng \`--frozen-lockfile\` như thường.
92
+ 3. \`cp platform/.env.example platform/.env\` rồi điền JWT_SECRET + passwords.
93
+ 4. Compose (máy có Docker): \`docker compose -f platform/docker-compose.yml --env-file platform/.env up -d --build\`
94
+ → \`bash scripts/smoke/e2e.sh\` (login → tạo task → đọc feed qua gateway :8080).
95
+ 5. Native (không Docker): theo \`docs/walkthrough.md\`.
96
+
97
+ ## Boundary
98
+ - Full e2e trên project scaffolded là **human gate** (cần Docker) — CI chỉ
99
+ chứng minh build + compose-config được (narrowing đã duyệt ở epic FI-62).
100
+ - Đọc \`README.md\` + \`docs/walkthrough.md\` + \`docs/adr/\` để hiểu kiến trúc.
101
+
102
+ ## AI onboarding
103
+ - \`CLAUDE.md\` — onboarding AI (nguyên tắc vàng + lệnh + gotchas).
104
+ - \`orca.yaml\` — descriptor máy đọc cho agent (services/ports/commands/gotchas).
105
+ - \`.claude/agents/\` — 4 agent miền: fe-dev · be-dev · e2e-runner · contracts-keeper.
106
+ - \`.claude/skills/\` — thủ tục dự án: add-service (thêm service mới) · sync-contracts (sửa API/contract).
107
+ EOF
108
+
109
+ echo "[scaffold] DONE — project mới tại: $OUT"
110
+ echo "[scaffold] tiếp theo: cd '$OUT' && pnpm install --no-frozen-lockfile (xem SCAFFOLD.md)"
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # e2e smoke — SF-5 (FI-81, story FI-76) + mở rộng auth-real (SF-5 VU-64):
4
+ # chứng minh chuỗi Kafka + Outbox + Saga + auth thật LIỀN MẠCH qua gateway
5
+ # trên compose stack.
6
+ #
7
+ # 2 chiều (context pack sf-5):
8
+ # HAPPY: login (auth-svc) → tạo task (node-svc; event qua outbox → Kafka →
9
+ # go-svc consume) → đọc feed + stats (go-svc).
10
+ # AUTH-REAL (VU-64): register user mới → refresh rotation → reuse token cũ
11
+ # → 401 (revoke-all) → logout idempotent → RBAC: user roles ["user"]
12
+ # DELETE task → 403 FORBIDDEN, alice (admin) DELETE → 204 (tasks.yaml).
13
+ # SAGA : tạo task → PATCH assigneeId = svc-fail fixture → go consumer fail
14
+ # ×3 → compensating event `task.assignment_failed` → node compensation
15
+ # consumer → GET task status = `assignment_failed` → assert DLQ:
16
+ # kafka-console-consumer đọc `task-events.dlq` thấy event gốc.
17
+ #
18
+ # API-level thuần curl — chạy được mọi nơi có bash + curl (GitHub CI, Git Bash
19
+ # Windows, Linux). Bước DLQ cần docker (exec trong container kafka) — tắt cả
20
+ # khối saga bằng SMOKE_SAGA=0 (đường B native không Kafka). Browser walkthrough
21
+ # KHÔNG nằm ở đây (human gate tại checkpoint — xem docs/walkthrough.md).
22
+ #
23
+ # Env:
24
+ # GATEWAY_URL (default http://localhost:8080)
25
+ # SMOKE_EMAIL (default alice@demo.local)
26
+ # SMOKE_PASSWORD (default demo-password)
27
+ # SMOKE_SAGA (default 1 — chạy saga path + DLQ assert; 0 = happy + auth
28
+ # only, dùng cho môi trường không Kafka/docker — đường B)
29
+ # SMOKE_FAIL_USER_ID (default svc-fail fixture UUID — contracts/auth/users.json;
30
+ # go consumer simulate fail khi assigneeId trùng user này)
31
+ # SMOKE_FEED_RETRIES (default 30 — outbox relay 500ms + Kafka latency; nới từ
32
+ # 10 của SF-7 vì chuỗi giờ qua Kafka thật, CI 10 services
33
+ # cạnh tranh CPU)
34
+ # SMOKE_SAGA_RETRIES (default 60 — saga: relay + go retry ×3 backoff 500ms +
35
+ # compensating publish + node compensation UPDATE)
36
+ #
37
+ # Exit 0 = PASS; exit N = fail ở bước N (in rõ bước fail).
38
+ # Lịch sử đánh số (bảo toàn contract exit N = fail bước N): FI-81 8 bước nhãn
39
+ # /8 (exit tới 10); VU-64 +6 bước auth-real → nhãn /15, exit = label+1 (tới 16,
40
+ # unique từng bước) — marker
41
+ # `SAGA_TASK_ID=` + `SMOKE_SAGA=0` exit 0 giữ nguyên (CI convergence.yml parse).
42
+ # ============================================================================
43
+ set -u
44
+
45
+ GW="${GATEWAY_URL:-http://localhost:8080}"
46
+ EMAIL="${SMOKE_EMAIL:-alice@demo.local}"
47
+ PASSWORD="${SMOKE_PASSWORD:-demo-password}"
48
+ SAGA="${SMOKE_SAGA:-1}"
49
+ FAIL_USER="${SMOKE_FAIL_USER_ID:-55555555-5555-4555-8555-555555555555}"
50
+ PREFIX="${SMOKE_TITLE_PREFIX:-smoke}"
51
+ RETRIES="${SMOKE_FEED_RETRIES:-30}"
52
+ SAGA_RETRIES="${SMOKE_SAGA_RETRIES:-60}"
53
+ TITLE="$PREFIX-$(date +%s)-$$"
54
+ SAGA_TITLE="$PREFIX-saga-$(date +%s)-$$"
55
+ # user register mỗi run — email unique theo ts+pid (tránh 409 trên stack sống lâu)
56
+ REGISTER_EMAIL="$PREFIX-auth-$(date +%s)-$$@demo.local"
57
+
58
+ say() { echo "[smoke] $*"; }
59
+ fail() { echo "[smoke] FAIL bước $1: $*" >&2; exit "$1"; }
60
+ extract() { # extract <json-field> <body-file> — grep thuần, không jq
61
+ # -n + /p (POSIX) thay cho GNU-only "s/.../\1/;t;d" — BSD sed (macOS) đọc
62
+ # ";d" sau t thành label undefined → fail bước 3 trên máy dev macOS
63
+ sed -E -n "s/.*\"$1\"[: ]*\"?([^\",}]+)\"?.*/\1/p" "$2" | head -1
64
+ }
65
+ CURL="curl -s --max-time 5" # timeout cụ thể — hung curl = treo CI tới 6h (P1 code-review SF-7)
66
+
67
+ command -v curl >/dev/null || fail 1 "curl không có trong PATH"
68
+
69
+ # dọn temp files (chứa token/body) kể cả khi fail giữa chừng (P2 security-audit SF-7)
70
+ # init rỗng TRƯỚC trap — set -u sẽ lỗi unbound khi trap fire trước khi mktemp chạy
71
+ LOGIN_BODY=""; STATS_BEFORE=""; TASK_BODY=""; FEED_BODY=""; STATS_AFTER=""
72
+ REGISTER_BODY=""; REFRESH_BODY=""; RBAC_403_BODY=""
73
+ SAGA_TASK_BODY=""; SAGA_GET_BODY=""; DLQ_OUT=""; DLQ_ERR=""
74
+ trap 'rm -f "$LOGIN_BODY" "$STATS_BEFORE" "$TASK_BODY" "$FEED_BODY" "$STATS_AFTER" "$REGISTER_BODY" "$REFRESH_BODY" "$RBAC_403_BODY" "$SAGA_TASK_BODY" "$SAGA_GET_BODY" "$DLQ_OUT" "$DLQ_ERR"' EXIT 2>/dev/null || true
75
+
76
+ # compose file resolve từ vị trí script — e2e.sh chạy được từ repo root lẫn platform/
77
+ # (script nằm ở scripts/smoke/ → lên 2 cấp mới tới platform/ — bug `../platform`
78
+ # = scripts/platform từng làm mọi docker exec trong script fail âm thầm run 1-4)
79
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
80
+ COMPOSE_FILE="$SCRIPT_DIR/../../platform/docker-compose.yml"
81
+ COMPOSE_ENV="$SCRIPT_DIR/../../platform/.env.example"
82
+
83
+ # --- Bước 1: gateway + auth-svc ready (poll — gateway không có /readyz riêng,
84
+ # conventions/02 rule 3; /api/auth/readyz = auth-svc qua gateway) ---
85
+ READY=0
86
+ for _ in $(seq 1 30); do
87
+ if curl -sf --max-time 3 "$GW/api/auth/readyz" 2>/dev/null | grep -q '"status":"ok"'; then READY=1; break; fi
88
+ sleep 1
89
+ done
90
+ [ "$READY" = "1" ] || fail 2 "gateway/auth-svc chưa ready sau 30s ($GW/api/auth/readyz)"
91
+ say "1/15 gateway + auth-svc ready (readyz = migration + seed xong)"
92
+
93
+ # --- Bước 2: login → accessToken ---
94
+ LOGIN_BODY="$(mktemp)"
95
+ HTTP=$($CURL -o "$LOGIN_BODY" -w '%{http_code}' -X POST "$GW/api/auth/login" \
96
+ -H 'Content-Type: application/json' \
97
+ -d "{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}")
98
+ [ "$HTTP" = "200" ] || fail 3 "login HTTP $HTTP (expect 200): $(cat "$LOGIN_BODY")"
99
+ TOKEN="$(extract accessToken "$LOGIN_BODY")"
100
+ # không in body login (chứa token) — chỉ báo shape field (P2 security-audit SF-7)
101
+ [ -n "$TOKEN" ] && [ "${#TOKEN}" -gt 40 ] || fail 3 "login 200 nhưng thiếu accessToken hợp lệ (field accessToken không parse được — kiểm shape LoginResponse contract)"
102
+ say "2/15 login OK (token ${#TOKEN} chars)"
103
+
104
+ # --- Bước 3: baseline stats (go-svc) TRƯỚC khi tạo task — poll: gateway route
105
+ # go-svc service_started → 502 đầu là bình thường, retry KHÔNG abort ---
106
+ STATS_BEFORE="$(mktemp)"
107
+ GOT=0
108
+ for _ in $(seq 1 30); do
109
+ HTTP=$($CURL -o "$STATS_BEFORE" -w '%{http_code}' "$GW/api/activity/stats" \
110
+ -H "Authorization: Bearer $TOKEN" 2>/dev/null) || { sleep 1; continue; }
111
+ [ "$HTTP" = "200" ] && { GOT=1; break; }
112
+ sleep 1
113
+ done
114
+ [ "$GOT" = "1" ] || fail 4 "stats baseline không 200 sau 30 lần retry (go-svc chưa sẵn sàng?) — HTTP cuối $HTTP"
115
+ BASELINE="$(extract totalTasks "$STATS_BEFORE")"
116
+ case "$BASELINE" in ''|*[!0-9]*) fail 4 "totalTasks baseline không parse được: $(cat "$STATS_BEFORE")";; esac
117
+ say "3/15 stats baseline totalTasks=$BASELINE"
118
+
119
+ # --- Bước 4: tạo task (node-svc; event task.created ghi outbox cùng tx) ---
120
+ TASK_BODY="$(mktemp)"
121
+ PAYLOAD="{\"title\":\"$TITLE\",\"description\":\"SF-5 e2e happy\"}"
122
+ HTTP=$($CURL -o "$TASK_BODY" -w '%{http_code}' -X POST "$GW/api/tasks" \
123
+ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
124
+ -d "$PAYLOAD")
125
+ [ "$HTTP" = "201" ] || fail 5 "tạo task HTTP $HTTP (expect 201): $(cat "$TASK_BODY")"
126
+ TASK_ID="$(extract id "$TASK_BODY")"
127
+ [ -n "$TASK_ID" ] || fail 5 "task id không parse được: $(cat "$TASK_BODY")"
128
+ say "4/15 task tạo OK id=$TASK_ID title=$TITLE"
129
+
130
+ # --- Bước 5: feed phản ánh QUA KAFKA (outbox relay 500ms → topic task-events →
131
+ # go consumer → persist; poll RETRIES×1s — nới từ SF-7 vì chuỗi giờ
132
+ # qua Kafka thật: relay 500ms + Kafka latency + consumer lag) ---
133
+ FEED_BODY="$(mktemp)"
134
+ FOUND=0
135
+ for _ in $(seq 1 "$RETRIES"); do
136
+ HTTP=$($CURL -o "$FEED_BODY" -w '%{http_code}' "$GW/api/activity/feed?limit=20" \
137
+ -H "Authorization: Bearer $TOKEN" 2>/dev/null) || { sleep 1; continue; }
138
+ # non-200 (vd 502 go-svc chưa bind) → retry, KHÔNG abort (readiness poll)
139
+ if [ "$HTTP" = "200" ] && grep -q '"action":"task.created"' "$FEED_BODY" \
140
+ && grep -q "\"taskTitle\":\"$TITLE\"" "$FEED_BODY"; then
141
+ FOUND=1; break
142
+ fi
143
+ sleep 1
144
+ done
145
+ [ "$FOUND" = "1" ] || fail 6 "feed không thấy action=task.created + taskTitle=$TITLE sau ${RETRIES}s retry (kiểm: outbox relay chạy? go consumer group go-svc-activity consume?)"
146
+ say "5/15 feed có task.created + taskTitle=$TITLE (qua outbox → Kafka → go-svc)"
147
+
148
+ # --- Bước 6: stats tăng (go-svc đọc readonly schema tasks — exit criterion readonly) ---
149
+ STATS_AFTER="$(mktemp)"
150
+ GOT=0
151
+ for _ in $(seq 1 30); do
152
+ HTTP=$($CURL -o "$STATS_AFTER" -w '%{http_code}' "$GW/api/activity/stats" \
153
+ -H "Authorization: Bearer $TOKEN" 2>/dev/null) || { sleep 1; continue; }
154
+ [ "$HTTP" = "200" ] && { GOT=1; break; }
155
+ sleep 1
156
+ done
157
+ [ "$GOT" = "1" ] || fail 7 "stats sau không 200 sau 30 lần retry — HTTP cuối $HTTP"
158
+ AFTER="$(extract totalTasks "$STATS_AFTER")"
159
+ case "$AFTER" in ''|*[!0-9]*) fail 7 "totalTasks sau không parse được: $(cat "$STATS_AFTER")";; esac
160
+ [ "$AFTER" -ge $((BASELINE + 1)) ] || fail 7 "stats không tăng: before=$BASELINE after=$AFTER"
161
+ say "6/15 stats totalTasks: $BASELINE → $AFTER"
162
+
163
+ # ============================================================================
164
+ # AUTH-REAL PATH (SF-5 VU-64): register → refresh rotation → reuse-detect →
165
+ # logout idempotent → RBAC DELETE (user 403 / admin 200). Chạy CẢ khi
166
+ # SMOKE_SAGA=0 — auth thật là luồng độc lập với saga (acceptance epic #2/#4).
167
+ # ============================================================================
168
+ # --- Bước 7: register user mới → 201 AuthSession (roles gán ["user"] — spec §Register) ---
169
+ REGISTER_BODY="$(mktemp)"
170
+ HTTP=$($CURL -o "$REGISTER_BODY" -w '%{http_code}' -X POST "$GW/api/auth/register" \
171
+ -H 'Content-Type: application/json' \
172
+ -d "{\"email\":\"$REGISTER_EMAIL\",\"password\":\"smoke-password-1\",\"displayName\":\"Smoke E2E\"}")
173
+ # P2 security-audit SF-5: nhánh fail KHÔNG in body (body có thể chứa AuthSession nếu
174
+ # service buggy trả success-code-sai) — chỉ in tên field, nhất quán policy bước login
175
+ [ "$HTTP" = "201" ] || fail 8 "register HTTP $HTTP (expect 201) — fields: $(grep -o '"[a-zA-Z]\+":' "$REGISTER_BODY" | tr '\n' ' ')"
176
+ grep -q '"roles":\["user"\]' "$REGISTER_BODY" || fail 8 "register response thiếu roles [\"user\"] (shape v2 — kiểm auth.yaml)"
177
+ USER_TOKEN="$(extract accessToken "$REGISTER_BODY")"
178
+ RT1="$(extract refreshToken "$REGISTER_BODY")"
179
+ [ -n "$USER_TOKEN" ] && [ -n "$RT1" ] || fail 8 "register 201 nhưng thiếu cặp token (shape AuthSession — kiểm contracts/openapi/auth.yaml)"
180
+ say "7/15 register OK $REGISTER_EMAIL (roles user — không in token)"
181
+
182
+ # --- Bước 8: refresh rotation CAS → 200 cặp mới, token cũ bị revoke trong cùng tx ---
183
+ REFRESH_BODY="$(mktemp)"
184
+ HTTP=$($CURL -o "$REFRESH_BODY" -w '%{http_code}' -X POST "$GW/api/auth/refresh" \
185
+ -H 'Content-Type: application/json' -d "{\"refreshToken\":\"$RT1\"}")
186
+ [ "$HTTP" = "200" ] || fail 9 "refresh HTTP $HTTP (expect 200) — fields: $(grep -o '"[a-zA-Z]\+":' "$REFRESH_BODY" | tr '\n' ' ')"
187
+ RT2="$(extract refreshToken "$REFRESH_BODY")"
188
+ [ -n "$RT2" ] && [ "$RT2" != "$RT1" ] || fail 9 "refresh 200 nhưng refreshToken không rotate (giống token cũ?)"
189
+ say "8/15 refresh rotation OK (token mới khác token cũ)"
190
+
191
+ # --- Bước 9: REUSE token đã rotate → 401 + revoke TẤT CẢ refresh của user (strict) ---
192
+ HTTP=$($CURL -o /dev/null -w '%{http_code}' -X POST "$GW/api/auth/refresh" \
193
+ -H 'Content-Type: application/json' -d "{\"refreshToken\":\"$RT1\"}")
194
+ [ "$HTTP" = "401" ] || fail 10 "reuse refresh cũ HTTP $HTTP (expect 401 — reuse-detect strict token-contract §3)"
195
+ say "9/15 reuse-detect OK (token cũ → 401 + revoke-all)"
196
+
197
+ # --- Bước 10: logout idempotent → 204 (RT2 đã bị revoke-all ở bước 9 — vẫn 204,
198
+ # đúng contract "token lạ/đã revoke vẫn 204, không leak") ---
199
+ HTTP=$($CURL -o /dev/null -w '%{http_code}' -X POST "$GW/api/auth/logout" \
200
+ -H 'Content-Type: application/json' -d "{\"refreshToken\":\"$RT2\"}")
201
+ [ "$HTTP" = "204" ] || fail 11 "logout HTTP $HTTP (expect 204 idempotent)"
202
+ say "10/15 logout OK (204 — idempotent trên token đã revoke)"
203
+
204
+ # --- Bước 11: RBAC — user roles ["user"] DELETE task của alice → 403 FORBIDDEN
205
+ # (envelope conventions/04; enforcement ở node-svc, gateway chỉ presence) ---
206
+ RBAC_403_BODY="$(mktemp)"
207
+ HTTP=$($CURL -o "$RBAC_403_BODY" -w '%{http_code}' -X DELETE "$GW/api/tasks/$TASK_ID" \
208
+ -H "Authorization: Bearer $USER_TOKEN")
209
+ [ "$HTTP" = "403" ] || fail 12 "DELETE task bởi user thường HTTP $HTTP (expect 403 — RBAC admin-only SF-3): $(cat "$RBAC_403_BODY")"
210
+ grep -q '"code":"FORBIDDEN"' "$RBAC_403_BODY" || fail 12 "403 nhưng thiếu envelope FORBIDDEN (conventions/04): $(cat "$RBAC_403_BODY")"
211
+ say "11/15 RBAC OK — user thường DELETE → 403 FORBIDDEN"
212
+
213
+ # --- Bước 12: alice (admin) DELETE cùng task → 204 (contract tasks.yaml —
214
+ # DELETE trả 204 No Content; prose plan ghi "200" là sơ sài) ---
215
+ HTTP=$($CURL -o /dev/null -w '%{http_code}' -X DELETE "$GW/api/tasks/$TASK_ID" \
216
+ -H "Authorization: Bearer $TOKEN")
217
+ [ "$HTTP" = "204" ] || fail 13 "DELETE task bởi alice HTTP $HTTP (expect 204 — tasks.yaml §delete)"
218
+ say "12/15 RBAC OK — alice DELETE → 204 (task xoá thật)"
219
+
220
+ # ============================================================================
221
+ # SAGA PATH (2 chiều — context pack sf-5): assign svc-fail → assignment_failed
222
+ # + DLQ assert. SMOKE_SAGA=0 để tắt (môi trường không Kafka/docker — đường B).
223
+ # ============================================================================
224
+ if [ "$SAGA" = "1" ]; then
225
+ # --- Bước 13: tạo task riêng cho saga + PATCH assigneeId = svc-fail ---
226
+ # (task riêng — taskId unique để assert DLQ không lẫn message khác)
227
+ SAGA_TASK_BODY="$(mktemp)"
228
+ HTTP=$($CURL -o "$SAGA_TASK_BODY" -w '%{http_code}' -X POST "$GW/api/tasks" \
229
+ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
230
+ -d "{\"title\":\"$SAGA_TITLE\",\"description\":\"SF-5 e2e saga\"}")
231
+ [ "$HTTP" = "201" ] || fail 14 "tạo task saga HTTP $HTTP (expect 201): $(cat "$SAGA_TASK_BODY")"
232
+ SAGA_TASK_ID="$(extract id "$SAGA_TASK_BODY")"
233
+ [ -n "$SAGA_TASK_ID" ] || fail 14 "task saga id không parse được: $(cat "$SAGA_TASK_BODY")"
234
+ HTTP=$($CURL -o /dev/null -w '%{http_code}' -X PATCH "$GW/api/tasks/$SAGA_TASK_ID" \
235
+ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
236
+ -d "{\"assigneeId\":\"$FAIL_USER\"}")
237
+ [ "$HTTP" = "200" ] || fail 14 "PATCH assigneeId=$FAIL_USER HTTP $HTTP (expect 200): task $SAGA_TASK_ID"
238
+ say "13/15 saga: PATCH task $SAGA_TASK_ID assigneeId=svc-fail OK — chờ go retry ×3 → compensating"
239
+
240
+ # --- Bước 14: poll GET task → status assignment_failed (node compensation
241
+ # consumer conditional UPDATE; chuỗi: relay 500ms → go consume →
242
+ # fail ×3 backoff 500ms → publish task.assignment_failed → node
243
+ # consume → UPDATE — tổng có thể >10s trên CI load) ---
244
+ SAGA_GET_BODY="$(mktemp)"
245
+ GOT=0
246
+ for _ in $(seq 1 "$SAGA_RETRIES"); do
247
+ HTTP=$($CURL -o "$SAGA_GET_BODY" -w '%{http_code}' "$GW/api/tasks/$SAGA_TASK_ID" \
248
+ -H "Authorization: Bearer $TOKEN" 2>/dev/null) || { sleep 1; continue; }
249
+ if [ "$HTTP" = "200" ] && grep -q '"status":"assignment_failed"' "$SAGA_GET_BODY"; then
250
+ GOT=1; break
251
+ fi
252
+ sleep 1
253
+ done
254
+ [ "$GOT" = "1" ] || fail 15 "task $SAGA_TASK_ID không thành assignment_failed sau ${SAGA_RETRIES}s (kiểm: go consumer retry/DLQ? node-svc-compensation group consume? conditional UPDATE guard?) — body cuối: $(cat "$SAGA_GET_BODY")"
255
+ say "14/15 saga: task status = assignment_failed (compensation đã chạy)"
256
+
257
+ # --- Bước 15: assert DLQ — event gốc (task.assigned cho task saga) phải nằm
258
+ # ở task-events.dlq. DLQ message shape (producer.go):
259
+ # {"schemaVersion":1,"originalEvent":"{...\"taskId\":\"<uuid>\"...}",
260
+ # "error":{...}} — grep taskId đủ chứng minh event gốc present.
261
+ # Run 3/4 lesson: docker compose exec TỪ TRONG script này fail âm
262
+ # thầm trong CI (stderr nuốt) trong khi CÙNG lệnh từ workflow
263
+ # run: block đọc được DLQ message 3/3 run (dump step). → assert ở
264
+ # đây là best-effort (surface stderr, đoán nguyên nhân); assert
265
+ # CHÍNH THỨC nằm ở CI step "Assert DLQ" sau step này (parse marker
266
+ # SAGA_TASK_ID= bên dưới). Chạy standalone (máy có compose) thì
267
+ # assert ở đây vẫn là assert thật. ---
268
+ command -v docker >/dev/null || fail 16 "docker không có trong PATH — không assert DLQ được (set SMOKE_SAGA=0 nếu môi trường không có Kafka)"
269
+ DLQ_OUT="$(mktemp)"
270
+ DLQ_ERR="$(mktemp)"
271
+ DLQ_ARRIVED=0
272
+ for attempt in 1 2 3 4 5 6; do
273
+ DLQ_END="$(docker compose -f "$COMPOSE_FILE" --env-file "$COMPOSE_ENV" exec -T kafka \
274
+ /opt/kafka/bin/kafka-get-offsets.sh --bootstrap-server localhost:9092 \
275
+ --topic task-events.dlq 2>"$DLQ_ERR" | sed -E 's/.*:([0-9]+)$/\1/')"
276
+ case "$DLQ_END" in ''|*[!0-9]*) DLQ_END=0;; esac
277
+ if [ "$DLQ_END" -ge 1 ]; then DLQ_ARRIVED=1; break; fi
278
+ [ "$attempt" -lt 6 ] && sleep 5
279
+ done
280
+ if [ "$DLQ_ARRIVED" = "1" ]; then
281
+ docker compose -f "$COMPOSE_FILE" --env-file "$COMPOSE_ENV" exec -T kafka \
282
+ /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 \
283
+ --topic task-events.dlq --from-beginning --timeout-ms 10000 > "$DLQ_OUT" 2>/dev/null
284
+ if [ ! -s "$DLQ_OUT" ]; then
285
+ # offset > 0 nhưng console-consumer trả output RỖNG = KHÔNG đọc được
286
+ # (exec/tool fail), khác với "đọc được mà không có taskId" (P2 reviewer)
287
+ fail 16 "DLQ có message (offset $DLQ_END) nhưng console-consumer trả output RỖNG — không đọc được (kiểm exec/tool)"
288
+ fi
289
+ if grep -q "$SAGA_TASK_ID" "$DLQ_OUT"; then
290
+ say "15/15 DLQ: event gốc của task $SAGA_TASK_ID có mặt ở task-events.dlq (end offset $DLQ_END) — acceptance saga đủ 2 nửa (status + DLQ)"
291
+ else
292
+ fail 16 "DLQ có message (offset $DLQ_END) nhưng không thấy taskId=$SAGA_TASK_ID — dlq output: $(head -c 400 "$DLQ_OUT")"
293
+ fi
294
+ else
295
+ # tool exec không trả output từ trong script (CI quirk — stderr giữ lại để
296
+ # chẩn đoán) → KHÔNG fail ở đây: marker dưới cho CI step assert chính thức
297
+ say "15/15 DLQ assert best-effort không chạy được từ trong script (stderr: $(head -c 200 "$DLQ_ERR" | tr '\n' ' ')) — ủy quyền CI step 'Assert DLQ'"
298
+ fi
299
+ # Marker cho CI step assert DLQ chính thức (convergence.yml) — LUÔN in khi saga chạy
300
+ say "SAGA_TASK_ID=$SAGA_TASK_ID"
301
+ else
302
+ say "SMOKE_SAGA=0 — bỏ qua saga path + DLQ assert (chạy happy only)"
303
+ fi
304
+
305
+ say "PASS — chuỗi auth-svc → node-svc (outbox → Kafka) → go-svc liền mạch qua gateway $GW$( [ "$SAGA" = "1" ] && echo ' + saga compensation → assignment_failed → DLQ' )"
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # snapshot-stack-template.sh — sinh app/stack-template/ từ repo hiện tại.
4
+ # Nguồn template cho create-wakii-stack; engine prune theo stack-manifest.json.
5
+ #
6
+ # Thiết kế tầng 1 (brief Mission #8):
7
+ # - rsync FULL repo trừ build-artifacts + nội bộ team — template chạy được ngay.
8
+ # - Placeholder hoá CHỈ chỗ an toàn: root package.json "name" + README H1 +
9
+ # compose `name:` → __STACK_NAME__; wakii-dev trong README + docs hướng dẫn
10
+ # → __STACK_ORG__. KHÔNG sed trong services/ — tên compose service giữ
11
+ # nguyên để `docker compose up` chạy được ngay sau scaffold.
12
+ # - Idempotent: khi template đã tồn tại phải chạy --force (xoá cũ, sinh mới).
13
+ # stack-manifest.json được GIỮ qua các lần regen (backup trước xoá, restore
14
+ # sau rsync) — nguồn chân lý prune không bao giờ mất khi refresh template.
15
+ # ============================================================================
16
+ set -euo pipefail
17
+ cd "$(dirname "$0")/.."
18
+
19
+ DEST="app/stack-template"
20
+ MANIFEST="$DEST/stack-manifest.json"
21
+
22
+ if [ "${1:-}" != "--force" ] && [ -e "$DEST" ]; then
23
+ echo "✗ $DEST đã tồn tại — chạy lại với --force để xoá và sinh mới"; exit 1
24
+ fi
25
+
26
+ # Giữ manifest qua regen
27
+ KEPT=""
28
+ if [ -f "$MANIFEST" ]; then
29
+ KEPT="$(mktemp)"
30
+ cp "$MANIFEST" "$KEPT"
31
+ fi
32
+
33
+ [ -e "$DEST" ] && rm -rf "$DEST"
34
+ mkdir -p "$DEST"
35
+
36
+ rsync -a \
37
+ --exclude='/app/stack-template/' \
38
+ --exclude='.git/' \
39
+ --exclude='node_modules/' \
40
+ --exclude='dist/' \
41
+ --exclude='storybook-static/' \
42
+ --exclude='coverage/' \
43
+ --exclude='.vercel/' \
44
+ --exclude='.env' \
45
+ --exclude='*.log' \
46
+ --exclude='docs/team/' \
47
+ --exclude='docs/superpowers/evidence/' \
48
+ ./ "$DEST/"
49
+
50
+ # Restore manifest giữ từ lần sinh trước
51
+ if [ -n "$KEPT" ]; then cp "$KEPT" "$MANIFEST"; rm -f "$KEPT"; fi
52
+
53
+ # Placeholder hoá — python chính xác từng chỗ (không sed lan), KHÔNG vào services/
54
+ python3 - "$DEST" <<'PY'
55
+ import json, pathlib, sys
56
+
57
+ dest = pathlib.Path(sys.argv[1])
58
+
59
+ # 1) root package.json "name" → __STACK_NAME__
60
+ pkg = dest / 'package.json'
61
+ data = json.loads(pkg.read_text())
62
+ data['name'] = '__STACK_NAME__'
63
+ pkg.write_text(json.dumps(data, indent=2, ensure_ascii=False) + '\n')
64
+
65
+ # 2) README.md H1 → __STACK_NAME__ (+ wakii-dev → __STACK_ORG__)
66
+ readme = dest / 'README.md'
67
+ lines = readme.read_text().split('\n')
68
+ if lines and lines[0].startswith('# '):
69
+ lines[0] = '# __STACK_NAME__'
70
+ readme.write_text('\n'.join(lines).replace('wakii-dev', '__STACK_ORG__'))
71
+
72
+ # 3) compose name: → __STACK_NAME__ (chỉ dòng name: — không đụng service blocks)
73
+ compose = dest / 'platform' / 'docker-compose.yml'
74
+ compose.write_text(compose.read_text().replace('name: boilerplate', 'name: __STACK_NAME__'))
75
+
76
+ # 4) wakii-dev → __STACK_ORG__ trong docs hướng dẫn (*.md dưới docs/ — hiện chỉ
77
+ # git-flow.md chứa; ADR/spec history không chứa nên nguyên vẹn)
78
+ for md in (dest / 'docs').rglob('*.md'):
79
+ text = md.read_text()
80
+ if 'wakii-dev' in text:
81
+ md.write_text(text.replace('wakii-dev', '__STACK_ORG__'))
82
+ PY
83
+
84
+ echo "✓ $DEST sinh xong — $(find "$DEST" -type f | wc -l | tr -d ' ') files"
@@ -0,0 +1,5 @@
1
+ node_modules
2
+ dist
3
+ coverage
4
+ .vitest
5
+ README.md
@@ -0,0 +1,32 @@
1
+ # auth-svc — multi-stage theo platform/conventions/01-dockerfile-pattern.md
2
+ # Lockfile: LOCAL pnpm-lock.yaml (thư mục này, pnpm install --ignore-workspace)
3
+ # vì build context = services/auth-svc — root workspace lockfile ngoài context.
4
+ # Build trong image (CI checkout không có dist/) — tsconfig excludes *.test.ts
5
+ # và *.test-support.ts.
6
+ # argon2: @node-rs/argon2 = napi prebuilt (kể cả linux-x64-musl) — KHÔNG cần
7
+ # python/make/g++ trong image (lý do chọn thay node-argon2 native-gyp).
8
+ # users.json KHÔNG nằm trong image — mount runtime từ contracts/auth/users.json
9
+ # (USERS_FIXTURE_PATH, compose SF-5 + CI boot-smoke mount — sửa fixture không
10
+ # cần rebuild, giống auth-mock).
11
+
12
+ FROM node:22-alpine AS deps
13
+ WORKDIR /app
14
+ COPY package.json pnpm-lock.yaml ./
15
+ RUN corepack enable && pnpm install --frozen-lockfile
16
+
17
+ FROM deps AS build
18
+ COPY tsconfig.json ./
19
+ COPY src ./src
20
+ RUN pnpm exec tsc -p tsconfig.json
21
+
22
+ FROM node:22-alpine AS runtime
23
+ WORKDIR /app
24
+ ENV NODE_ENV=production
25
+ COPY --from=deps /app/node_modules ./node_modules
26
+ COPY --from=build /app/dist ./dist
27
+ # migration chạy lúc boot (server.ts) — folder phải nằm cạnh dist/../drizzle
28
+ COPY drizzle ./drizzle
29
+ COPY package.json ./
30
+ USER node
31
+ EXPOSE 8090
32
+ CMD ["node", "dist/server.js"]