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.
- package/README.md +66 -2
- package/dist/chunk-7XGW4UJ5.js +75 -0
- package/dist/chunk-AKPWS7FJ.js +76 -0
- package/dist/chunk-ELM6GGC5.js +50 -0
- package/dist/chunk-ON2WTGZH.js +77 -0
- package/dist/index.js +385 -0
- package/dist/manifest-2JVLRMDB.js +10 -0
- package/dist/manifest-O35TPW73.js +10 -0
- package/dist/manifest-TXTY67BF.js +10 -0
- package/dist/manifest-XWHR7Y3F.js +10 -0
- package/package.json +23 -4
- package/stack-template/.changeset/config.json +15 -0
- package/stack-template/.changeset/vu53-ui-redesign.md +11 -0
- package/stack-template/.claude/agents/be-dev.md +56 -0
- package/stack-template/.claude/agents/contracts-keeper.md +51 -0
- package/stack-template/.claude/agents/e2e-runner.md +61 -0
- package/stack-template/.claude/agents/fe-dev.md +53 -0
- package/stack-template/.claude/settings.json +77 -0
- package/stack-template/.claude/settings.local.json +9 -0
- package/stack-template/.claude/skills/add-service/SKILL.md +81 -0
- package/stack-template/.claude/skills/sync-contracts/SKILL.md +74 -0
- package/stack-template/.editorconfig +21 -0
- package/stack-template/.gitattributes +10 -0
- package/stack-template/.github/pull_request_template.md +26 -0
- package/stack-template/.github/workflow-templates/services-ci.yml.example +69 -0
- package/stack-template/.github/workflows/contracts.yml +133 -0
- package/stack-template/.github/workflows/convergence.yml +209 -0
- package/stack-template/.github/workflows/git-guard.yml +44 -0
- package/stack-template/.github/workflows/publish-uikit.yml +96 -0
- package/stack-template/.github/workflows/remotes-activity.yml +82 -0
- package/stack-template/.github/workflows/remotes-tasks.yml +82 -0
- package/stack-template/.github/workflows/services-auth-svc.yml +153 -0
- package/stack-template/.github/workflows/services-go-svc.yml +281 -0
- package/stack-template/.github/workflows/services-node-svc.yml +173 -0
- package/stack-template/.github/workflows/services-spring-svc.yml +132 -0
- package/stack-template/.github/workflows/shell.yml +78 -0
- package/stack-template/.github/workflows/ui-kit.yml +51 -0
- package/stack-template/.husky/commit-msg +14 -0
- package/stack-template/.husky/pre-push +51 -0
- package/stack-template/.spectral.yaml +17 -0
- package/stack-template/AGENTS.md +197 -0
- package/stack-template/CLAUDE.md +114 -0
- package/stack-template/README.md +172 -0
- package/stack-template/app/admin/index.html +12 -0
- package/stack-template/app/admin/package.json +40 -0
- package/stack-template/app/admin/scripts/verify-chart.mjs +49 -0
- package/stack-template/app/admin/src/App.test.tsx +70 -0
- package/stack-template/app/admin/src/App.tsx +33 -0
- package/stack-template/app/admin/src/data/users.ts +47 -0
- package/stack-template/app/admin/src/layout/AdminLayout.tsx +212 -0
- package/stack-template/app/admin/src/main.tsx +17 -0
- package/stack-template/app/admin/src/pages/ComponentsDemo.tsx +138 -0
- package/stack-template/app/admin/src/pages/Dashboard.tsx +182 -0
- package/stack-template/app/admin/src/pages/HooksDemo.tsx +153 -0
- package/stack-template/app/admin/src/pages/Settings.tsx +156 -0
- package/stack-template/app/admin/src/pages/UploadPage.tsx +34 -0
- package/stack-template/app/admin/src/pages/Users.test.tsx +66 -0
- package/stack-template/app/admin/src/pages/Users.tsx +245 -0
- package/stack-template/app/admin/src/styles.css +9 -0
- package/stack-template/app/admin/src/tests/setup.ts +15 -0
- package/stack-template/app/admin/tsconfig.json +18 -0
- package/stack-template/app/admin/vite.config.ts +11 -0
- package/stack-template/app/admin/vitest.config.ts +14 -0
- package/stack-template/app/create-wakii-app/README.md +71 -0
- package/stack-template/app/create-wakii-app/package.json +27 -0
- package/stack-template/app/create-wakii-app/scripts/publish-npm.sh +38 -0
- package/stack-template/app/create-wakii-app/src/index.ts +127 -0
- package/stack-template/app/create-wakii-app/src/options.test.ts +80 -0
- package/stack-template/app/create-wakii-app/src/options.ts +117 -0
- package/stack-template/app/create-wakii-app/src/scaffold.test.ts +143 -0
- package/stack-template/app/create-wakii-app/src/scaffold.ts +194 -0
- package/stack-template/app/create-wakii-app/tsconfig.json +17 -0
- package/stack-template/app/create-wakii-app/vitest.config.ts +9 -0
- package/stack-template/app/create-wakii-stack/package.json +27 -0
- package/stack-template/app/create-wakii-stack/src/manifest.ts +101 -0
- package/stack-template/app/create-wakii-stack/src/options.ts +106 -0
- package/stack-template/app/create-wakii-stack/src/scaffold.ts +315 -0
- package/stack-template/app/create-wakii-stack/tsconfig.json +17 -0
- package/stack-template/app/create-wakii-stack/vitest.config.ts +9 -0
- package/stack-template/app/remotes/activity/Dockerfile +36 -0
- package/stack-template/app/remotes/activity/README.md +59 -0
- package/stack-template/app/remotes/activity/index.html +11 -0
- package/stack-template/app/remotes/activity/nginx.conf +35 -0
- package/stack-template/app/remotes/activity/package.json +40 -0
- package/stack-template/app/remotes/activity/rspack.config.mjs +152 -0
- package/stack-template/app/remotes/activity/src/ActivityPage.tsx +139 -0
- package/stack-template/app/remotes/activity/src/api.ts +63 -0
- package/stack-template/app/remotes/activity/src/app.css +7 -0
- package/stack-template/app/remotes/activity/src/components/FeedItem.tsx +39 -0
- package/stack-template/app/remotes/activity/src/components/StatTile.tsx +24 -0
- package/stack-template/app/remotes/activity/src/components/Timeline.tsx +53 -0
- package/stack-template/app/remotes/activity/src/components/time.ts +30 -0
- package/stack-template/app/remotes/activity/src/env.d.ts +5 -0
- package/stack-template/app/remotes/activity/src/index.tsx +12 -0
- package/stack-template/app/remotes/activity/src/standalone.tsx +36 -0
- package/stack-template/app/remotes/activity/tests/ActivityPage.test.tsx +260 -0
- package/stack-template/app/remotes/activity/tests/api.test.ts +61 -0
- package/stack-template/app/remotes/activity/tests/setup.ts +1 -0
- package/stack-template/app/remotes/activity/tests/test-utils.tsx +16 -0
- package/stack-template/app/remotes/activity/tsconfig.json +26 -0
- package/stack-template/app/remotes/activity/vitest.config.ts +38 -0
- package/stack-template/app/remotes/tasks/Dockerfile +36 -0
- package/stack-template/app/remotes/tasks/README.md +59 -0
- package/stack-template/app/remotes/tasks/index.html +11 -0
- package/stack-template/app/remotes/tasks/nginx.conf +35 -0
- package/stack-template/app/remotes/tasks/package.json +41 -0
- package/stack-template/app/remotes/tasks/rspack.config.mjs +153 -0
- package/stack-template/app/remotes/tasks/src/TasksPage.tsx +284 -0
- package/stack-template/app/remotes/tasks/src/api.ts +109 -0
- package/stack-template/app/remotes/tasks/src/app.css +7 -0
- package/stack-template/app/remotes/tasks/src/components/StatusBadge.tsx +20 -0
- package/stack-template/app/remotes/tasks/src/components/StatusSelect.tsx +27 -0
- package/stack-template/app/remotes/tasks/src/components/TaskForm.tsx +74 -0
- package/stack-template/app/remotes/tasks/src/components/TaskItem.tsx +199 -0
- package/stack-template/app/remotes/tasks/src/components/TaskList.tsx +60 -0
- package/stack-template/app/remotes/tasks/src/components/status.ts +23 -0
- package/stack-template/app/remotes/tasks/src/env.d.ts +5 -0
- package/stack-template/app/remotes/tasks/src/index.tsx +12 -0
- package/stack-template/app/remotes/tasks/src/standalone.tsx +38 -0
- package/stack-template/app/remotes/tasks/tests/TasksPage.test.tsx +445 -0
- package/stack-template/app/remotes/tasks/tests/api.test.ts +159 -0
- package/stack-template/app/remotes/tasks/tests/setup.ts +1 -0
- package/stack-template/app/remotes/tasks/tests/test-utils.tsx +16 -0
- package/stack-template/app/remotes/tasks/tsconfig.json +26 -0
- package/stack-template/app/remotes/tasks/vitest.config.ts +34 -0
- package/stack-template/app/shared/README.md +21 -0
- package/stack-template/app/shared/package.json +37 -0
- package/stack-template/app/shared/src/api-client.ts +66 -0
- package/stack-template/app/shared/src/error-envelope.ts +38 -0
- package/stack-template/app/shared/src/index.ts +21 -0
- package/stack-template/app/shared/src/mf-bootstrap.ts +89 -0
- package/stack-template/app/shared/src/refresh-client.ts +170 -0
- package/stack-template/app/shared/src/token-storage.ts +57 -0
- package/stack-template/app/shell/Dockerfile +37 -0
- package/stack-template/app/shell/README.md +79 -0
- package/stack-template/app/shell/index.html +11 -0
- package/stack-template/app/shell/nginx.conf +23 -0
- package/stack-template/app/shell/package.json +43 -0
- package/stack-template/app/shell/rspack.config.mjs +147 -0
- package/stack-template/app/shell/src/App.tsx +57 -0
- package/stack-template/app/shell/src/api.ts +36 -0
- package/stack-template/app/shell/src/app.css +11 -0
- package/stack-template/app/shell/src/bootstrap.tsx +24 -0
- package/stack-template/app/shell/src/components/Layout.tsx +35 -0
- package/stack-template/app/shell/src/components/NavBar.tsx +118 -0
- package/stack-template/app/shell/src/components/RemoteSlot.tsx +82 -0
- package/stack-template/app/shell/src/components/RequireAuth.tsx +14 -0
- package/stack-template/app/shell/src/env.d.ts +7 -0
- package/stack-template/app/shell/src/index.tsx +3 -0
- package/stack-template/app/shell/src/pages/HomePage.tsx +70 -0
- package/stack-template/app/shell/src/pages/LoginPage.tsx +217 -0
- package/stack-template/app/shell/src/remote-urls.ts +18 -0
- package/stack-template/app/shell/tests/a11y.test.tsx +53 -0
- package/stack-template/app/shell/tests/api-timeout.test.ts +43 -0
- package/stack-template/app/shell/tests/integration.test.tsx +93 -0
- package/stack-template/app/shell/tests/login.test.tsx +227 -0
- package/stack-template/app/shell/tests/mf-retry.test.ts +76 -0
- package/stack-template/app/shell/tests/refresh-client.test.ts +301 -0
- package/stack-template/app/shell/tests/remote-slot.test.tsx +109 -0
- package/stack-template/app/shell/tests/remote-urls.test.ts +26 -0
- package/stack-template/app/shell/tests/setup.ts +15 -0
- package/stack-template/app/shell/tests/shell-chrome.test.tsx +126 -0
- package/stack-template/app/shell/tsconfig.json +26 -0
- package/stack-template/app/shell/vitest.config.ts +42 -0
- package/stack-template/app/spike/README.md +35 -0
- package/stack-template/app/spike/host/index.html +11 -0
- package/stack-template/app/spike/host/package.json +17 -0
- package/stack-template/app/spike/host/rspack.config.mjs +34 -0
- package/stack-template/app/spike/host/src/bootstrap.jsx +26 -0
- package/stack-template/app/spike/host/src/index.jsx +3 -0
- package/stack-template/app/spike/remote/package.json +17 -0
- package/stack-template/app/spike/remote/rspack.config.mjs +36 -0
- package/stack-template/app/spike/remote/src/Hello.jsx +7 -0
- package/stack-template/app/spike/remote/src/index.js +2 -0
- package/stack-template/app/spike/serve.mjs +31 -0
- package/stack-template/app/starter-templates/template-feats/extras/carousel/src/DemoCarousel.tsx +99 -0
- package/stack-template/app/starter-templates/template-feats/extras/chart/src/DemoChart.tsx +84 -0
- package/stack-template/app/starter-templates/template-feats/extras/editor/src/DemoEditor.tsx +110 -0
- package/stack-template/app/starter-templates/template-feats/extras/schedule/src/DemoSchedule.tsx +81 -0
- package/stack-template/app/starter-templates/template-feats/router/src/App.tsx +332 -0
- package/stack-template/app/starter-templates/template-feats/router/src/main.tsx +14 -0
- package/stack-template/app/starter-templates/vite-js/README.md +72 -0
- package/stack-template/app/starter-templates/vite-js/index.html +12 -0
- package/stack-template/app/starter-templates/vite-js/jsconfig.json +10 -0
- package/stack-template/app/starter-templates/vite-js/package.json +22 -0
- package/stack-template/app/starter-templates/vite-js/src/App.jsx +158 -0
- package/stack-template/app/starter-templates/vite-js/src/main.jsx +10 -0
- package/stack-template/app/starter-templates/vite-js/src/styles.css +15 -0
- package/stack-template/app/starter-templates/vite-js/src/theme.js +21 -0
- package/stack-template/app/starter-templates/vite-js/vite.config.mjs +8 -0
- package/stack-template/app/starter-templates/vite-ts/README.md +53 -0
- package/stack-template/app/starter-templates/vite-ts/index.html +12 -0
- package/stack-template/app/starter-templates/vite-ts/package.json +29 -0
- package/stack-template/app/starter-templates/vite-ts/src/App.tsx +181 -0
- package/stack-template/app/starter-templates/vite-ts/src/main.tsx +12 -0
- package/stack-template/app/starter-templates/vite-ts/src/styles.css +21 -0
- package/stack-template/app/starter-templates/vite-ts/src/theme.ts +16 -0
- package/stack-template/app/starter-templates/vite-ts/tsconfig.json +25 -0
- package/stack-template/app/starter-templates/vite-ts/tsconfig.node.json +11 -0
- package/stack-template/app/starter-templates/vite-ts/vite.config.ts +10 -0
- package/stack-template/app/ui-kit/.storybook/main.ts +29 -0
- package/stack-template/app/ui-kit/.storybook/manager-head.html +97 -0
- package/stack-template/app/ui-kit/.storybook/manager.ts +138 -0
- package/stack-template/app/ui-kit/.storybook/preview-head.html +57 -0
- package/stack-template/app/ui-kit/.storybook/preview.ts +62 -0
- package/stack-template/app/ui-kit/.storybook/tailwind-preview.css +3 -0
- package/stack-template/app/ui-kit/.storybook/test-runner.config.ts +20 -0
- package/stack-template/app/ui-kit/CHANGELOG.md +137 -0
- package/stack-template/app/ui-kit/LICENSE +21 -0
- package/stack-template/app/ui-kit/MIGRATION.md +84 -0
- package/stack-template/app/ui-kit/README.md +173 -0
- package/stack-template/app/ui-kit/RELEASE.md +77 -0
- package/stack-template/app/ui-kit/USAGE.md +380 -0
- package/stack-template/app/ui-kit/eslint.config.js +47 -0
- package/stack-template/app/ui-kit/package.json +166 -0
- package/stack-template/app/ui-kit/scripts/publish-github.sh +39 -0
- package/stack-template/app/ui-kit/scripts/publish-npm.sh +76 -0
- package/stack-template/app/ui-kit/scripts/stamp-build.cjs +13 -0
- package/stack-template/app/ui-kit/src/KitchenSink.stories.tsx +576 -0
- package/stack-template/app/ui-kit/src/Tokens.stories.tsx +193 -0
- package/stack-template/app/ui-kit/src/entries/carousel.ts +7 -0
- package/stack-template/app/ui-kit/src/entries/chart.ts +4 -0
- package/stack-template/app/ui-kit/src/entries/editor.ts +4 -0
- package/stack-template/app/ui-kit/src/entries/experience3d.ts +5 -0
- package/stack-template/app/ui-kit/src/entries/schedule.ts +5 -0
- package/stack-template/app/ui-kit/src/env.d.ts +3 -0
- package/stack-template/app/ui-kit/src/hooks/form.stories.tsx +80 -0
- package/stack-template/app/ui-kit/src/hooks/hooks-new.stories.tsx +392 -0
- package/stack-template/app/ui-kit/src/hooks/hooks.stories.tsx +167 -0
- package/stack-template/app/ui-kit/src/hooks/useClickAway.test.tsx +63 -0
- package/stack-template/app/ui-kit/src/hooks/useClickAway.ts +30 -0
- package/stack-template/app/ui-kit/src/hooks/useControllableState.test.ts +36 -0
- package/stack-template/app/ui-kit/src/hooks/useControllableState.ts +41 -0
- package/stack-template/app/ui-kit/src/hooks/useCopyToClipboard.test.ts +89 -0
- package/stack-template/app/ui-kit/src/hooks/useCopyToClipboard.ts +20 -0
- package/stack-template/app/ui-kit/src/hooks/useCountdown.test.ts +88 -0
- package/stack-template/app/ui-kit/src/hooks/useCountdown.ts +38 -0
- package/stack-template/app/ui-kit/src/hooks/useDebounce.test.ts +71 -0
- package/stack-template/app/ui-kit/src/hooks/useDebounce.ts +14 -0
- package/stack-template/app/ui-kit/src/hooks/useDefault.test.ts +37 -0
- package/stack-template/app/ui-kit/src/hooks/useDefault.ts +15 -0
- package/stack-template/app/ui-kit/src/hooks/useEventListener.test.ts +47 -0
- package/stack-template/app/ui-kit/src/hooks/useEventListener.ts +28 -0
- package/stack-template/app/ui-kit/src/hooks/useFieldArray.test.tsx +160 -0
- package/stack-template/app/ui-kit/src/hooks/useFieldArray.ts +85 -0
- package/stack-template/app/ui-kit/src/hooks/useFocusTrap.ts +67 -0
- package/stack-template/app/ui-kit/src/hooks/useForm.test.tsx +192 -0
- package/stack-template/app/ui-kit/src/hooks/useForm.ts +119 -0
- package/stack-template/app/ui-kit/src/hooks/useFullscreen.test.tsx +71 -0
- package/stack-template/app/ui-kit/src/hooks/useFullscreen.ts +68 -0
- package/stack-template/app/ui-kit/src/hooks/useHover.test.tsx +30 -0
- package/stack-template/app/ui-kit/src/hooks/useHover.ts +23 -0
- package/stack-template/app/ui-kit/src/hooks/useInView.test.tsx +70 -0
- package/stack-template/app/ui-kit/src/hooks/useInView.ts +55 -0
- package/stack-template/app/ui-kit/src/hooks/useInfiniteScroll.test.tsx +72 -0
- package/stack-template/app/ui-kit/src/hooks/useInfiniteScroll.ts +45 -0
- package/stack-template/app/ui-kit/src/hooks/useIsFirstRender.test.ts +30 -0
- package/stack-template/app/ui-kit/src/hooks/useIsFirstRender.ts +14 -0
- package/stack-template/app/ui-kit/src/hooks/useKeyPress.test.ts +45 -0
- package/stack-template/app/ui-kit/src/hooks/useKeyPress.ts +31 -0
- package/stack-template/app/ui-kit/src/hooks/useLocalStorage.test.ts +102 -0
- package/stack-template/app/ui-kit/src/hooks/useLocalStorage.ts +34 -0
- package/stack-template/app/ui-kit/src/hooks/useLockBodyScroll.test.ts +42 -0
- package/stack-template/app/ui-kit/src/hooks/useLockBodyScroll.ts +13 -0
- package/stack-template/app/ui-kit/src/hooks/useMeasure.test.tsx +57 -0
- package/stack-template/app/ui-kit/src/hooks/useMeasure.ts +32 -0
- package/stack-template/app/ui-kit/src/hooks/useMediaQuery.test.ts +73 -0
- package/stack-template/app/ui-kit/src/hooks/useMediaQuery.ts +20 -0
- package/stack-template/app/ui-kit/src/hooks/useMountEffect.test.ts +22 -0
- package/stack-template/app/ui-kit/src/hooks/useMountEffect.ts +10 -0
- package/stack-template/app/ui-kit/src/hooks/useOnlineStatus.test.ts +36 -0
- package/stack-template/app/ui-kit/src/hooks/useOnlineStatus.ts +21 -0
- package/stack-template/app/ui-kit/src/hooks/usePrevious.test.ts +35 -0
- package/stack-template/app/ui-kit/src/hooks/usePrevious.ts +13 -0
- package/stack-template/app/ui-kit/src/hooks/useScrollProgress.test.ts +59 -0
- package/stack-template/app/ui-kit/src/hooks/useScrollProgress.ts +31 -0
- package/stack-template/app/ui-kit/src/hooks/useSessionStorage.test.ts +80 -0
- package/stack-template/app/ui-kit/src/hooks/useSessionStorage.ts +34 -0
- package/stack-template/app/ui-kit/src/hooks/useThrottle.test.ts +61 -0
- package/stack-template/app/ui-kit/src/hooks/useThrottle.ts +30 -0
- package/stack-template/app/ui-kit/src/hooks/useTimeout.test.ts +95 -0
- package/stack-template/app/ui-kit/src/hooks/useTimeout.ts +38 -0
- package/stack-template/app/ui-kit/src/hooks/useTitle.test.ts +34 -0
- package/stack-template/app/ui-kit/src/hooks/useTitle.ts +24 -0
- package/stack-template/app/ui-kit/src/hooks/useToggle.test.ts +46 -0
- package/stack-template/app/ui-kit/src/hooks/useToggle.ts +16 -0
- package/stack-template/app/ui-kit/src/hooks/useUpdateEffect.test.ts +25 -0
- package/stack-template/app/ui-kit/src/hooks/useUpdateEffect.ts +18 -0
- package/stack-template/app/ui-kit/src/hooks/useWindowSize.test.ts +33 -0
- package/stack-template/app/ui-kit/src/hooks/useWindowSize.ts +23 -0
- package/stack-template/app/ui-kit/src/index.ts +218 -0
- package/stack-template/app/ui-kit/src/intro-showcase.stories.tsx +272 -0
- package/stack-template/app/ui-kit/src/intro.docs.mdx +247 -0
- package/stack-template/app/ui-kit/src/motion/motion-showcase.stories.tsx +234 -0
- package/stack-template/app/ui-kit/src/motion/motion.md +38 -0
- package/stack-template/app/ui-kit/src/provider/index.tsx +77 -0
- package/stack-template/app/ui-kit/src/provider/provider.stories.tsx +87 -0
- package/stack-template/app/ui-kit/src/provider/provider.test.tsx +121 -0
- package/stack-template/app/ui-kit/src/styles/base.css +171 -0
- package/stack-template/app/ui-kit/src/styles/dark-theme.test.ts +21 -0
- package/stack-template/app/ui-kit/src/styles/tailwind.css +220 -0
- package/stack-template/app/ui-kit/src/styles/themes/dark.css +71 -0
- package/stack-template/app/ui-kit/src/styles/tokens.css +133 -0
- package/stack-template/app/ui-kit/src/styles/ui-kit.css +10 -0
- package/stack-template/app/ui-kit/src/templates/auth.stories.tsx +425 -0
- package/stack-template/app/ui-kit/src/templates/crud.stories.tsx +416 -0
- package/stack-template/app/ui-kit/src/templates/dashboard.stories.tsx +504 -0
- package/stack-template/app/ui-kit/src/templates/experience/chapters/ch1-deep-focus.tsx +96 -0
- package/stack-template/app/ui-kit/src/templates/experience/chapters/ch2-living-docs.tsx +134 -0
- package/stack-template/app/ui-kit/src/templates/experience/chapters/ch3-team-velocity.tsx +148 -0
- package/stack-template/app/ui-kit/src/templates/experience/chapters/ch4-ship-your-app.tsx +100 -0
- package/stack-template/app/ui-kit/src/templates/experience/chapters/ch5-future.tsx +67 -0
- package/stack-template/app/ui-kit/src/templates/experience/chapters/hero.tsx +434 -0
- package/stack-template/app/ui-kit/src/templates/experience/chapters/nav-footer.tsx +85 -0
- package/stack-template/app/ui-kit/src/templates/experience/hero.stories.tsx +27 -0
- package/stack-template/app/ui-kit/src/templates/experience/hero.test.tsx +108 -0
- package/stack-template/app/ui-kit/src/templates/experience/index.stories.tsx +51 -0
- package/stack-template/app/ui-kit/src/templates/experience/lib/ChapterShell.tsx +84 -0
- package/stack-template/app/ui-kit/src/templates/experience/lib/SideNav.tsx +173 -0
- package/stack-template/app/ui-kit/src/templates/experience/lib/chapter-shell.test.tsx +266 -0
- package/stack-template/app/ui-kit/src/templates/experience/lib/scroll-mood.tsx +143 -0
- package/stack-template/app/ui-kit/src/templates/experience/lib/starfield.test.tsx +31 -0
- package/stack-template/app/ui-kit/src/templates/experience/lib/starfield.tsx +190 -0
- package/stack-template/app/ui-kit/src/templates/experience/mood-engine.stories.tsx +114 -0
- package/stack-template/app/ui-kit/src/templates/experience/shell-nav.stories.tsx +113 -0
- package/stack-template/app/ui-kit/src/templates/kanban-project.stories.tsx +352 -0
- package/stack-template/app/ui-kit/src/templates/landing.stories.tsx +380 -0
- package/stack-template/app/ui-kit/src/templates/parallax-landing.stories.tsx +633 -0
- package/stack-template/app/ui-kit/src/templates/settings.stories.tsx +474 -0
- package/stack-template/app/ui-kit/src/ui/accordion/accordion.stories.tsx +91 -0
- package/stack-template/app/ui-kit/src/ui/accordion/accordion.test.tsx +99 -0
- package/stack-template/app/ui-kit/src/ui/accordion/index.tsx +107 -0
- package/stack-template/app/ui-kit/src/ui/affix/affix.stories.tsx +104 -0
- package/stack-template/app/ui-kit/src/ui/affix/affix.test.tsx +138 -0
- package/stack-template/app/ui-kit/src/ui/affix/index.tsx +89 -0
- package/stack-template/app/ui-kit/src/ui/alert/alert.stories.tsx +149 -0
- package/stack-template/app/ui-kit/src/ui/alert/alert.test.tsx +85 -0
- package/stack-template/app/ui-kit/src/ui/alert/index.tsx +118 -0
- package/stack-template/app/ui-kit/src/ui/anchor/anchor.stories.tsx +96 -0
- package/stack-template/app/ui-kit/src/ui/anchor/anchor.test.tsx +191 -0
- package/stack-template/app/ui-kit/src/ui/anchor/index.tsx +144 -0
- package/stack-template/app/ui-kit/src/ui/auto-complete/auto-complete.stories.tsx +67 -0
- package/stack-template/app/ui-kit/src/ui/auto-complete/auto-complete.test.tsx +94 -0
- package/stack-template/app/ui-kit/src/ui/auto-complete/index.tsx +54 -0
- package/stack-template/app/ui-kit/src/ui/avatar/avatar.stories.tsx +132 -0
- package/stack-template/app/ui-kit/src/ui/avatar/avatar.test.tsx +65 -0
- package/stack-template/app/ui-kit/src/ui/avatar/index.tsx +48 -0
- package/stack-template/app/ui-kit/src/ui/avatar-group/avatar-group.stories.tsx +113 -0
- package/stack-template/app/ui-kit/src/ui/avatar-group/avatar-group.test.tsx +71 -0
- package/stack-template/app/ui-kit/src/ui/avatar-group/index.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/backdrop/backdrop.stories.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/backdrop/backdrop.test.tsx +37 -0
- package/stack-template/app/ui-kit/src/ui/backdrop/index.tsx +29 -0
- package/stack-template/app/ui-kit/src/ui/badge/badge.stories.tsx +105 -0
- package/stack-template/app/ui-kit/src/ui/badge/badge.test.tsx +115 -0
- package/stack-template/app/ui-kit/src/ui/badge/index.tsx +154 -0
- package/stack-template/app/ui-kit/src/ui/blockui/blockui.stories.tsx +34 -0
- package/stack-template/app/ui-kit/src/ui/blockui/blockui.test.tsx +29 -0
- package/stack-template/app/ui-kit/src/ui/blockui/index.tsx +25 -0
- package/stack-template/app/ui-kit/src/ui/bottom-navigation/bottom-navigation.stories.tsx +70 -0
- package/stack-template/app/ui-kit/src/ui/bottom-navigation/bottom-navigation.test.tsx +68 -0
- package/stack-template/app/ui-kit/src/ui/bottom-navigation/index.tsx +82 -0
- package/stack-template/app/ui-kit/src/ui/branch-fill.test.tsx +245 -0
- package/stack-template/app/ui-kit/src/ui/breadcrumb/breadcrumb.stories.tsx +103 -0
- package/stack-template/app/ui-kit/src/ui/breadcrumb/breadcrumb.test.tsx +49 -0
- package/stack-template/app/ui-kit/src/ui/breadcrumb/index.tsx +37 -0
- package/stack-template/app/ui-kit/src/ui/busy-box/busy-box.stories.tsx +30 -0
- package/stack-template/app/ui-kit/src/ui/busy-box/busy-box.test.tsx +29 -0
- package/stack-template/app/ui-kit/src/ui/busy-box/index.tsx +25 -0
- package/stack-template/app/ui-kit/src/ui/button/button.stories.tsx +121 -0
- package/stack-template/app/ui-kit/src/ui/button/button.test.tsx +207 -0
- package/stack-template/app/ui-kit/src/ui/button/index.tsx +128 -0
- package/stack-template/app/ui-kit/src/ui/calendar/calendar.stories.tsx +100 -0
- package/stack-template/app/ui-kit/src/ui/calendar/calendar.test.tsx +92 -0
- package/stack-template/app/ui-kit/src/ui/calendar/index.tsx +163 -0
- package/stack-template/app/ui-kit/src/ui/card/card.stories.tsx +203 -0
- package/stack-template/app/ui-kit/src/ui/card/card.test.tsx +135 -0
- package/stack-template/app/ui-kit/src/ui/card/index.tsx +84 -0
- package/stack-template/app/ui-kit/src/ui/carousel/carousel.stories.tsx +533 -0
- package/stack-template/app/ui-kit/src/ui/carousel/carousel.test.tsx +148 -0
- package/stack-template/app/ui-kit/src/ui/carousel/index.tsx +195 -0
- package/stack-template/app/ui-kit/src/ui/cascade-select/cascade-select.stories.tsx +126 -0
- package/stack-template/app/ui-kit/src/ui/cascade-select/cascade-select.test.tsx +132 -0
- package/stack-template/app/ui-kit/src/ui/cascade-select/index.tsx +87 -0
- package/stack-template/app/ui-kit/src/ui/chart/chart-theme.test.tsx +79 -0
- package/stack-template/app/ui-kit/src/ui/chart/chart.stories.tsx +278 -0
- package/stack-template/app/ui-kit/src/ui/chart/chart.test.tsx +103 -0
- package/stack-template/app/ui-kit/src/ui/chart/index.tsx +172 -0
- package/stack-template/app/ui-kit/src/ui/checkbox/checkbox.stories.tsx +67 -0
- package/stack-template/app/ui-kit/src/ui/checkbox/checkbox.test.tsx +99 -0
- package/stack-template/app/ui-kit/src/ui/checkbox/index.tsx +52 -0
- package/stack-template/app/ui-kit/src/ui/chips/chips.stories.tsx +53 -0
- package/stack-template/app/ui-kit/src/ui/chips/chips.test.tsx +86 -0
- package/stack-template/app/ui-kit/src/ui/chips/index.tsx +44 -0
- package/stack-template/app/ui-kit/src/ui/collapse/collapse.stories.tsx +93 -0
- package/stack-template/app/ui-kit/src/ui/collapse/collapse.test.tsx +128 -0
- package/stack-template/app/ui-kit/src/ui/collapse/index.tsx +75 -0
- package/stack-template/app/ui-kit/src/ui/color-picker/color-picker.stories.tsx +48 -0
- package/stack-template/app/ui-kit/src/ui/color-picker/color-picker.test.tsx +68 -0
- package/stack-template/app/ui-kit/src/ui/color-picker/index.tsx +38 -0
- package/stack-template/app/ui-kit/src/ui/context-menu/context-menu.stories.tsx +73 -0
- package/stack-template/app/ui-kit/src/ui/context-menu/context-menu.test.tsx +93 -0
- package/stack-template/app/ui-kit/src/ui/context-menu/index.tsx +79 -0
- package/stack-template/app/ui-kit/src/ui/count-up/count-up.stories.tsx +80 -0
- package/stack-template/app/ui-kit/src/ui/count-up/count-up.test.tsx +121 -0
- package/stack-template/app/ui-kit/src/ui/count-up/index.tsx +70 -0
- package/stack-template/app/ui-kit/src/ui/date-picker/date-picker.stories.tsx +154 -0
- package/stack-template/app/ui-kit/src/ui/date-picker/date-picker.test.tsx +221 -0
- package/stack-template/app/ui-kit/src/ui/date-picker/index.tsx +287 -0
- package/stack-template/app/ui-kit/src/ui/date-picker/locale-constants.ts +90 -0
- package/stack-template/app/ui-kit/src/ui/date-picker/locale.tsx +15 -0
- package/stack-template/app/ui-kit/src/ui/deferred-content/deferred-content.stories.tsx +62 -0
- package/stack-template/app/ui-kit/src/ui/deferred-content/deferred-content.test.tsx +94 -0
- package/stack-template/app/ui-kit/src/ui/deferred-content/index.tsx +61 -0
- package/stack-template/app/ui-kit/src/ui/descriptions/descriptions.stories.tsx +114 -0
- package/stack-template/app/ui-kit/src/ui/descriptions/descriptions.test.tsx +75 -0
- package/stack-template/app/ui-kit/src/ui/descriptions/index.tsx +48 -0
- package/stack-template/app/ui-kit/src/ui/divider/divider.stories.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/divider/divider.test.tsx +83 -0
- package/stack-template/app/ui-kit/src/ui/divider/index.tsx +65 -0
- package/stack-template/app/ui-kit/src/ui/drag-drop/drag-drop.stories.tsx +145 -0
- package/stack-template/app/ui-kit/src/ui/drag-drop/drag-drop.test.tsx +352 -0
- package/stack-template/app/ui-kit/src/ui/drag-drop/index.tsx +456 -0
- package/stack-template/app/ui-kit/src/ui/drawer/drawer.stories.tsx +108 -0
- package/stack-template/app/ui-kit/src/ui/drawer/drawer.test.tsx +132 -0
- package/stack-template/app/ui-kit/src/ui/drawer/index.tsx +113 -0
- package/stack-template/app/ui-kit/src/ui/dropdown/dropdown.stories.tsx +61 -0
- package/stack-template/app/ui-kit/src/ui/dropdown/dropdown.test.tsx +101 -0
- package/stack-template/app/ui-kit/src/ui/dropdown/index.tsx +162 -0
- package/stack-template/app/ui-kit/src/ui/editor/EditorInner.tsx +93 -0
- package/stack-template/app/ui-kit/src/ui/editor/editor.stories.tsx +37 -0
- package/stack-template/app/ui-kit/src/ui/editor/editor.test.tsx +84 -0
- package/stack-template/app/ui-kit/src/ui/editor/index.tsx +58 -0
- package/stack-template/app/ui-kit/src/ui/empty-state/empty-state.stories.tsx +24 -0
- package/stack-template/app/ui-kit/src/ui/empty-state/empty-state.test.tsx +48 -0
- package/stack-template/app/ui-kit/src/ui/empty-state/index.tsx +22 -0
- package/stack-template/app/ui-kit/src/ui/experience3d/experience3d.stories.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/experience3d/experience3d.test.tsx +50 -0
- package/stack-template/app/ui-kit/src/ui/experience3d/index.tsx +457 -0
- package/stack-template/app/ui-kit/src/ui/field/field-array.stories.tsx +214 -0
- package/stack-template/app/ui-kit/src/ui/field/field.stories.tsx +158 -0
- package/stack-template/app/ui-kit/src/ui/field/field.test.tsx +68 -0
- package/stack-template/app/ui-kit/src/ui/field/index.tsx +48 -0
- package/stack-template/app/ui-kit/src/ui/fieldset/fieldset.stories.tsx +49 -0
- package/stack-template/app/ui-kit/src/ui/fieldset/fieldset.test.tsx +88 -0
- package/stack-template/app/ui-kit/src/ui/fieldset/index.tsx +62 -0
- package/stack-template/app/ui-kit/src/ui/flex/flex.stories.tsx +96 -0
- package/stack-template/app/ui-kit/src/ui/flex/flex.test.tsx +79 -0
- package/stack-template/app/ui-kit/src/ui/flex/index.tsx +45 -0
- package/stack-template/app/ui-kit/src/ui/float-button/float-button.stories.tsx +82 -0
- package/stack-template/app/ui-kit/src/ui/float-button/float-button.test.tsx +107 -0
- package/stack-template/app/ui-kit/src/ui/float-button/index.tsx +124 -0
- package/stack-template/app/ui-kit/src/ui/galleria/galleria.stories.tsx +78 -0
- package/stack-template/app/ui-kit/src/ui/galleria/galleria.test.tsx +67 -0
- package/stack-template/app/ui-kit/src/ui/galleria/index.tsx +47 -0
- package/stack-template/app/ui-kit/src/ui/grid/grid.stories.tsx +179 -0
- package/stack-template/app/ui-kit/src/ui/grid/grid.test.tsx +286 -0
- package/stack-template/app/ui-kit/src/ui/grid/index.tsx +104 -0
- package/stack-template/app/ui-kit/src/ui/icons/icons.stories.tsx +52 -0
- package/stack-template/app/ui-kit/src/ui/icons/icons.test.tsx +60 -0
- package/stack-template/app/ui-kit/src/ui/icons/index.tsx +294 -0
- package/stack-template/app/ui-kit/src/ui/image/image.stories.tsx +231 -0
- package/stack-template/app/ui-kit/src/ui/image/image.test.tsx +79 -0
- package/stack-template/app/ui-kit/src/ui/image/index.tsx +76 -0
- package/stack-template/app/ui-kit/src/ui/inplace/index.tsx +33 -0
- package/stack-template/app/ui-kit/src/ui/inplace/inplace.stories.tsx +75 -0
- package/stack-template/app/ui-kit/src/ui/inplace/inplace.test.tsx +58 -0
- package/stack-template/app/ui-kit/src/ui/input/index.tsx +133 -0
- package/stack-template/app/ui-kit/src/ui/input/input-search.stories.tsx +112 -0
- package/stack-template/app/ui-kit/src/ui/input/input-search.test.tsx +116 -0
- package/stack-template/app/ui-kit/src/ui/input/input-search.tsx +116 -0
- package/stack-template/app/ui-kit/src/ui/input/input.stories.tsx +176 -0
- package/stack-template/app/ui-kit/src/ui/input/input.test.tsx +106 -0
- package/stack-template/app/ui-kit/src/ui/input-mask/index.tsx +39 -0
- package/stack-template/app/ui-kit/src/ui/input-mask/input-mask.stories.tsx +46 -0
- package/stack-template/app/ui-kit/src/ui/input-mask/input-mask.test.tsx +57 -0
- package/stack-template/app/ui-kit/src/ui/input-number/index.tsx +125 -0
- package/stack-template/app/ui-kit/src/ui/input-number/input-number.stories.tsx +190 -0
- package/stack-template/app/ui-kit/src/ui/input-number/input-number.test.tsx +157 -0
- package/stack-template/app/ui-kit/src/ui/input-otp/index.tsx +57 -0
- package/stack-template/app/ui-kit/src/ui/input-otp/input-otp.stories.tsx +90 -0
- package/stack-template/app/ui-kit/src/ui/input-otp/input-otp.test.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/kanban/index.tsx +277 -0
- package/stack-template/app/ui-kit/src/ui/kanban/kanban.stories.tsx +219 -0
- package/stack-template/app/ui-kit/src/ui/kanban/kanban.test.tsx +234 -0
- package/stack-template/app/ui-kit/src/ui/knob/index.tsx +58 -0
- package/stack-template/app/ui-kit/src/ui/knob/knob.stories.tsx +49 -0
- package/stack-template/app/ui-kit/src/ui/knob/knob.test.tsx +42 -0
- package/stack-template/app/ui-kit/src/ui/layout/index.tsx +145 -0
- package/stack-template/app/ui-kit/src/ui/layout/layout.stories.tsx +158 -0
- package/stack-template/app/ui-kit/src/ui/layout/layout.test.tsx +154 -0
- package/stack-template/app/ui-kit/src/ui/link/index.tsx +61 -0
- package/stack-template/app/ui-kit/src/ui/link/link.stories.tsx +68 -0
- package/stack-template/app/ui-kit/src/ui/link/link.test.tsx +69 -0
- package/stack-template/app/ui-kit/src/ui/list/index.tsx +135 -0
- package/stack-template/app/ui-kit/src/ui/list/list.stories.tsx +194 -0
- package/stack-template/app/ui-kit/src/ui/list/list.test.tsx +164 -0
- package/stack-template/app/ui-kit/src/ui/listbox/index.tsx +27 -0
- package/stack-template/app/ui-kit/src/ui/listbox/listbox.stories.tsx +57 -0
- package/stack-template/app/ui-kit/src/ui/listbox/listbox.test.tsx +49 -0
- package/stack-template/app/ui-kit/src/ui/mega-menu/index.tsx +142 -0
- package/stack-template/app/ui-kit/src/ui/mega-menu/mega-menu.stories.tsx +137 -0
- package/stack-template/app/ui-kit/src/ui/mega-menu/mega-menu.test.tsx +130 -0
- package/stack-template/app/ui-kit/src/ui/mention/index.tsx +76 -0
- package/stack-template/app/ui-kit/src/ui/mention/mention.stories.tsx +44 -0
- package/stack-template/app/ui-kit/src/ui/mention/mention.test.tsx +87 -0
- package/stack-template/app/ui-kit/src/ui/menu/index.tsx +256 -0
- package/stack-template/app/ui-kit/src/ui/menu/menu.stories.tsx +124 -0
- package/stack-template/app/ui-kit/src/ui/menu/menu.test.tsx +251 -0
- package/stack-template/app/ui-kit/src/ui/menubar/index.tsx +42 -0
- package/stack-template/app/ui-kit/src/ui/menubar/menubar.stories.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/menubar/menubar.test.tsx +65 -0
- package/stack-template/app/ui-kit/src/ui/message/index.tsx +123 -0
- package/stack-template/app/ui-kit/src/ui/message/message.stories.tsx +104 -0
- package/stack-template/app/ui-kit/src/ui/message/message.test.tsx +109 -0
- package/stack-template/app/ui-kit/src/ui/modal/index.tsx +142 -0
- package/stack-template/app/ui-kit/src/ui/modal/modal.stories.tsx +128 -0
- package/stack-template/app/ui-kit/src/ui/modal/modal.test.tsx +166 -0
- package/stack-template/app/ui-kit/src/ui/notification/index.tsx +142 -0
- package/stack-template/app/ui-kit/src/ui/notification/notification.stories.tsx +155 -0
- package/stack-template/app/ui-kit/src/ui/notification/notification.test.tsx +83 -0
- package/stack-template/app/ui-kit/src/ui/order-list/index.tsx +38 -0
- package/stack-template/app/ui-kit/src/ui/order-list/order-list.stories.tsx +38 -0
- package/stack-template/app/ui-kit/src/ui/order-list/order-list.test.tsx +54 -0
- package/stack-template/app/ui-kit/src/ui/org-chart/index.tsx +138 -0
- package/stack-template/app/ui-kit/src/ui/org-chart/org-chart.stories.tsx +76 -0
- package/stack-template/app/ui-kit/src/ui/org-chart/org-chart.test.tsx +98 -0
- package/stack-template/app/ui-kit/src/ui/pagination/index.tsx +102 -0
- package/stack-template/app/ui-kit/src/ui/pagination/pagination.stories.tsx +103 -0
- package/stack-template/app/ui-kit/src/ui/pagination/pagination.test.tsx +112 -0
- package/stack-template/app/ui-kit/src/ui/panel-menu/index.tsx +59 -0
- package/stack-template/app/ui-kit/src/ui/panel-menu/panel-menu.stories.tsx +96 -0
- package/stack-template/app/ui-kit/src/ui/panel-menu/panel-menu.test.tsx +64 -0
- package/stack-template/app/ui-kit/src/ui/parallax/index.tsx +62 -0
- package/stack-template/app/ui-kit/src/ui/parallax/parallax.stories.tsx +115 -0
- package/stack-template/app/ui-kit/src/ui/parallax/parallax.test.tsx +148 -0
- package/stack-template/app/ui-kit/src/ui/password/index.tsx +67 -0
- package/stack-template/app/ui-kit/src/ui/password/password.stories.tsx +43 -0
- package/stack-template/app/ui-kit/src/ui/password/password.test.tsx +45 -0
- package/stack-template/app/ui-kit/src/ui/pick-list/index.tsx +103 -0
- package/stack-template/app/ui-kit/src/ui/pick-list/pick-list.stories.tsx +59 -0
- package/stack-template/app/ui-kit/src/ui/pick-list/pick-list.test.tsx +94 -0
- package/stack-template/app/ui-kit/src/ui/popconfirm/index.tsx +102 -0
- package/stack-template/app/ui-kit/src/ui/popconfirm/popconfirm.stories.tsx +73 -0
- package/stack-template/app/ui-kit/src/ui/popconfirm/popconfirm.test.tsx +127 -0
- package/stack-template/app/ui-kit/src/ui/popover/index.tsx +136 -0
- package/stack-template/app/ui-kit/src/ui/popover/popover.stories.tsx +114 -0
- package/stack-template/app/ui-kit/src/ui/popover/popover.test.tsx +172 -0
- package/stack-template/app/ui-kit/src/ui/progress/index.tsx +46 -0
- package/stack-template/app/ui-kit/src/ui/progress/progress.stories.tsx +57 -0
- package/stack-template/app/ui-kit/src/ui/progress/progress.test.tsx +90 -0
- package/stack-template/app/ui-kit/src/ui/qr-code/index.tsx +88 -0
- package/stack-template/app/ui-kit/src/ui/qr-code/qr-code.stories.tsx +109 -0
- package/stack-template/app/ui-kit/src/ui/qr-code/qr-code.test.tsx +155 -0
- package/stack-template/app/ui-kit/src/ui/qr-code/qrcode-core.ts +56 -0
- package/stack-template/app/ui-kit/src/ui/qr-code/qrcode-generator.vendor.ts +2300 -0
- package/stack-template/app/ui-kit/src/ui/radio/index.tsx +62 -0
- package/stack-template/app/ui-kit/src/ui/radio/radio.stories.tsx +94 -0
- package/stack-template/app/ui-kit/src/ui/radio/radio.test.tsx +83 -0
- package/stack-template/app/ui-kit/src/ui/rating/index.tsx +36 -0
- package/stack-template/app/ui-kit/src/ui/rating/rating.stories.tsx +42 -0
- package/stack-template/app/ui-kit/src/ui/rating/rating.test.tsx +45 -0
- package/stack-template/app/ui-kit/src/ui/result/index.tsx +72 -0
- package/stack-template/app/ui-kit/src/ui/result/result.stories.tsx +82 -0
- package/stack-template/app/ui-kit/src/ui/result/result.test.tsx +57 -0
- package/stack-template/app/ui-kit/src/ui/reveal/index.tsx +83 -0
- package/stack-template/app/ui-kit/src/ui/reveal/reveal.stories.tsx +91 -0
- package/stack-template/app/ui-kit/src/ui/reveal/reveal.test.tsx +148 -0
- package/stack-template/app/ui-kit/src/ui/schedule/index.tsx +104 -0
- package/stack-template/app/ui-kit/src/ui/schedule/schedule.fc.test.tsx +95 -0
- package/stack-template/app/ui-kit/src/ui/schedule/schedule.stories.tsx +61 -0
- package/stack-template/app/ui-kit/src/ui/schedule/schedule.test.tsx +41 -0
- package/stack-template/app/ui-kit/src/ui/scroll-page/index.tsx +46 -0
- package/stack-template/app/ui-kit/src/ui/scroll-page/scroll-page.stories.tsx +92 -0
- package/stack-template/app/ui-kit/src/ui/scroll-page/scroll-page.test.tsx +51 -0
- package/stack-template/app/ui-kit/src/ui/scroll-panel/index.tsx +16 -0
- package/stack-template/app/ui-kit/src/ui/scroll-panel/scroll-panel.stories.tsx +37 -0
- package/stack-template/app/ui-kit/src/ui/scroll-panel/scroll-panel.test.tsx +41 -0
- package/stack-template/app/ui-kit/src/ui/scrolltop/index.tsx +27 -0
- package/stack-template/app/ui-kit/src/ui/scrolltop/scrolltop.stories.tsx +41 -0
- package/stack-template/app/ui-kit/src/ui/scrolltop/scrolltop.test.tsx +37 -0
- package/stack-template/app/ui-kit/src/ui/segmented/index.tsx +47 -0
- package/stack-template/app/ui-kit/src/ui/segmented/segmented.stories.tsx +126 -0
- package/stack-template/app/ui-kit/src/ui/segmented/segmented.test.tsx +77 -0
- package/stack-template/app/ui-kit/src/ui/select/index.tsx +302 -0
- package/stack-template/app/ui-kit/src/ui/select/select.stories.tsx +268 -0
- package/stack-template/app/ui-kit/src/ui/select/select.test.tsx +226 -0
- package/stack-template/app/ui-kit/src/ui/sidebar/index.tsx +83 -0
- package/stack-template/app/ui-kit/src/ui/sidebar/sidebar.stories.tsx +71 -0
- package/stack-template/app/ui-kit/src/ui/sidebar/sidebar.test.tsx +101 -0
- package/stack-template/app/ui-kit/src/ui/skeleton/index.tsx +55 -0
- package/stack-template/app/ui-kit/src/ui/skeleton/skeleton.stories.tsx +110 -0
- package/stack-template/app/ui-kit/src/ui/skeleton/skeleton.test.tsx +74 -0
- package/stack-template/app/ui-kit/src/ui/slide-menu/index.tsx +103 -0
- package/stack-template/app/ui-kit/src/ui/slide-menu/slide-menu.stories.tsx +92 -0
- package/stack-template/app/ui-kit/src/ui/slide-menu/slide-menu.test.tsx +120 -0
- package/stack-template/app/ui-kit/src/ui/slider/index.tsx +90 -0
- package/stack-template/app/ui-kit/src/ui/slider/slider.stories.tsx +60 -0
- package/stack-template/app/ui-kit/src/ui/slider/slider.test.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/space/index.tsx +32 -0
- package/stack-template/app/ui-kit/src/ui/space/space.stories.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/space/space.test.tsx +56 -0
- package/stack-template/app/ui-kit/src/ui/speed-dial/index.tsx +32 -0
- package/stack-template/app/ui-kit/src/ui/speed-dial/speed-dial.stories.tsx +34 -0
- package/stack-template/app/ui-kit/src/ui/speed-dial/speed-dial.test.tsx +34 -0
- package/stack-template/app/ui-kit/src/ui/spinner/index.tsx +74 -0
- package/stack-template/app/ui-kit/src/ui/spinner/spinner.stories.tsx +64 -0
- package/stack-template/app/ui-kit/src/ui/spinner/spinner.test.tsx +66 -0
- package/stack-template/app/ui-kit/src/ui/split-button/index.tsx +155 -0
- package/stack-template/app/ui-kit/src/ui/split-button/split-button.stories.tsx +137 -0
- package/stack-template/app/ui-kit/src/ui/split-button/split-button.test.tsx +152 -0
- package/stack-template/app/ui-kit/src/ui/splitter/index.tsx +49 -0
- package/stack-template/app/ui-kit/src/ui/splitter/splitter.stories.tsx +24 -0
- package/stack-template/app/ui-kit/src/ui/splitter/splitter.test.tsx +21 -0
- package/stack-template/app/ui-kit/src/ui/statistic/index.tsx +28 -0
- package/stack-template/app/ui-kit/src/ui/statistic/statistic.stories.tsx +112 -0
- package/stack-template/app/ui-kit/src/ui/statistic/statistic.test.tsx +39 -0
- package/stack-template/app/ui-kit/src/ui/steps/index.tsx +50 -0
- package/stack-template/app/ui-kit/src/ui/steps/steps.stories.tsx +57 -0
- package/stack-template/app/ui-kit/src/ui/steps/steps.test.tsx +55 -0
- package/stack-template/app/ui-kit/src/ui/switch/index.tsx +87 -0
- package/stack-template/app/ui-kit/src/ui/switch/switch.stories.tsx +123 -0
- package/stack-template/app/ui-kit/src/ui/switch/switch.test.tsx +98 -0
- package/stack-template/app/ui-kit/src/ui/tab-menu/index.tsx +33 -0
- package/stack-template/app/ui-kit/src/ui/tab-menu/tab-menu.stories.tsx +49 -0
- package/stack-template/app/ui-kit/src/ui/tab-menu/tab-menu.test.tsx +50 -0
- package/stack-template/app/ui-kit/src/ui/table/index.tsx +690 -0
- package/stack-template/app/ui-kit/src/ui/table/table-advanced.stories.tsx +91 -0
- package/stack-template/app/ui-kit/src/ui/table/table-advanced.test.tsx +188 -0
- package/stack-template/app/ui-kit/src/ui/table/table-expandable.stories.tsx +91 -0
- package/stack-template/app/ui-kit/src/ui/table/table-expandable.test.tsx +143 -0
- package/stack-template/app/ui-kit/src/ui/table/table.stories.tsx +342 -0
- package/stack-template/app/ui-kit/src/ui/table/table.test.tsx +465 -0
- package/stack-template/app/ui-kit/src/ui/table/types.ts +173 -0
- package/stack-template/app/ui-kit/src/ui/tabs/index.tsx +118 -0
- package/stack-template/app/ui-kit/src/ui/tabs/tabs.stories.tsx +113 -0
- package/stack-template/app/ui-kit/src/ui/tabs/tabs.test.tsx +77 -0
- package/stack-template/app/ui-kit/src/ui/tag/index.tsx +68 -0
- package/stack-template/app/ui-kit/src/ui/tag/tag.stories.tsx +88 -0
- package/stack-template/app/ui-kit/src/ui/tag/tag.test.tsx +126 -0
- package/stack-template/app/ui-kit/src/ui/team/debt-board/debt-board.stories.tsx +52 -0
- package/stack-template/app/ui-kit/src/ui/team/debt-board/debt-board.test.tsx +72 -0
- package/stack-template/app/ui-kit/src/ui/team/debt-board/index.tsx +125 -0
- package/stack-template/app/ui-kit/src/ui/team/inbox-thread/inbox-thread.stories.tsx +70 -0
- package/stack-template/app/ui-kit/src/ui/team/inbox-thread/inbox-thread.test.tsx +56 -0
- package/stack-template/app/ui-kit/src/ui/team/inbox-thread/index.tsx +107 -0
- package/stack-template/app/ui-kit/src/ui/team/ping-feed/index.tsx +102 -0
- package/stack-template/app/ui-kit/src/ui/team/ping-feed/ping-feed.stories.tsx +57 -0
- package/stack-template/app/ui-kit/src/ui/team/ping-feed/ping-feed.test.tsx +60 -0
- package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/index.tsx +60 -0
- package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/stage-pipeline.stories.tsx +68 -0
- package/stack-template/app/ui-kit/src/ui/team/stage-pipeline/stage-pipeline.test.tsx +50 -0
- package/stack-template/app/ui-kit/src/ui/team/team-dashboard/index.tsx +103 -0
- package/stack-template/app/ui-kit/src/ui/team/team-dashboard/team-dashboard.stories.tsx +72 -0
- package/stack-template/app/ui-kit/src/ui/team/team-dashboard/team-dashboard.test.tsx +72 -0
- package/stack-template/app/ui-kit/src/ui/time-picker/index.tsx +143 -0
- package/stack-template/app/ui-kit/src/ui/time-picker/time-picker.stories.tsx +90 -0
- package/stack-template/app/ui-kit/src/ui/time-picker/time-picker.test.tsx +64 -0
- package/stack-template/app/ui-kit/src/ui/timeline/index.tsx +91 -0
- package/stack-template/app/ui-kit/src/ui/timeline/timeline.stories.tsx +209 -0
- package/stack-template/app/ui-kit/src/ui/timeline/timeline.test.tsx +116 -0
- package/stack-template/app/ui-kit/src/ui/timesheet/index.tsx +277 -0
- package/stack-template/app/ui-kit/src/ui/timesheet/timesheet.stories.tsx +97 -0
- package/stack-template/app/ui-kit/src/ui/timesheet/timesheet.test.tsx +103 -0
- package/stack-template/app/ui-kit/src/ui/toggle-button/index.tsx +28 -0
- package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.stories.tsx +85 -0
- package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.test.tsx +97 -0
- package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button-group.tsx +81 -0
- package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button.stories.tsx +46 -0
- package/stack-template/app/ui-kit/src/ui/toggle-button/toggle-button.test.tsx +38 -0
- package/stack-template/app/ui-kit/src/ui/toolbar/index.tsx +18 -0
- package/stack-template/app/ui-kit/src/ui/toolbar/toolbar.stories.tsx +35 -0
- package/stack-template/app/ui-kit/src/ui/toolbar/toolbar.test.tsx +11 -0
- package/stack-template/app/ui-kit/src/ui/tooltip/index.tsx +61 -0
- package/stack-template/app/ui-kit/src/ui/tooltip/tooltip.stories.tsx +81 -0
- package/stack-template/app/ui-kit/src/ui/tooltip/tooltip.test.tsx +120 -0
- package/stack-template/app/ui-kit/src/ui/tour/index.tsx +210 -0
- package/stack-template/app/ui-kit/src/ui/tour/tour.stories.tsx +153 -0
- package/stack-template/app/ui-kit/src/ui/tour/tour.test.tsx +131 -0
- package/stack-template/app/ui-kit/src/ui/transition/index.tsx +377 -0
- package/stack-template/app/ui-kit/src/ui/transition/transition.stories.tsx +254 -0
- package/stack-template/app/ui-kit/src/ui/transition/transition.test.tsx +285 -0
- package/stack-template/app/ui-kit/src/ui/tree/index.tsx +68 -0
- package/stack-template/app/ui-kit/src/ui/tree/tree.stories.tsx +139 -0
- package/stack-template/app/ui-kit/src/ui/tree/tree.test.tsx +77 -0
- package/stack-template/app/ui-kit/src/ui/tree-select/index.tsx +251 -0
- package/stack-template/app/ui-kit/src/ui/tree-select/tree-select.stories.tsx +105 -0
- package/stack-template/app/ui-kit/src/ui/tree-select/tree-select.test.tsx +174 -0
- package/stack-template/app/ui-kit/src/ui/tree-table/index.tsx +229 -0
- package/stack-template/app/ui-kit/src/ui/tree-table/tree-table.stories.tsx +111 -0
- package/stack-template/app/ui-kit/src/ui/tree-table/tree-table.test.tsx +137 -0
- package/stack-template/app/ui-kit/src/ui/typography/index.tsx +124 -0
- package/stack-template/app/ui-kit/src/ui/typography/typography.stories.tsx +65 -0
- package/stack-template/app/ui-kit/src/ui/typography/typography.test.tsx +117 -0
- package/stack-template/app/ui-kit/src/ui/upload/index.tsx +39 -0
- package/stack-template/app/ui-kit/src/ui/upload/upload-core.tsx +204 -0
- package/stack-template/app/ui-kit/src/ui/upload/upload-dropzone.tsx +79 -0
- package/stack-template/app/ui-kit/src/ui/upload/upload.stories.tsx +67 -0
- package/stack-template/app/ui-kit/src/ui/upload/upload.test.tsx +204 -0
- package/stack-template/app/ui-kit/src/ui/virtual-scroll/index.tsx +86 -0
- package/stack-template/app/ui-kit/src/ui/virtual-scroll/virtual-scroll.stories.tsx +111 -0
- package/stack-template/app/ui-kit/src/ui/virtual-scroll/virtual-scroll.test.tsx +125 -0
- package/stack-template/app/ui-kit/src/ui/watermark/index.tsx +182 -0
- package/stack-template/app/ui-kit/src/ui/watermark/watermark.stories.tsx +96 -0
- package/stack-template/app/ui-kit/src/ui/watermark/watermark.test.tsx +120 -0
- package/stack-template/app/ui-kit/src/utils/array.test.ts +88 -0
- package/stack-template/app/ui-kit/src/utils/array.ts +51 -0
- package/stack-template/app/ui-kit/src/utils/dom.test.tsx +69 -0
- package/stack-template/app/ui-kit/src/utils/dom.ts +38 -0
- package/stack-template/app/ui-kit/src/utils/format.test.ts +63 -0
- package/stack-template/app/ui-kit/src/utils/format.ts +81 -0
- package/stack-template/app/ui-kit/tests/setup.ts +15 -0
- package/stack-template/app/ui-kit/tsconfig.json +18 -0
- package/stack-template/app/ui-kit/tsup.config.ts +37 -0
- package/stack-template/app/ui-kit/vercel.json +6 -0
- package/stack-template/app/ui-kit/vitest.config.ts +22 -0
- package/stack-template/contracts/auth/token-contract.md +119 -0
- package/stack-template/contracts/auth/users.json +35 -0
- package/stack-template/contracts/db/tasks-schema.sql +62 -0
- package/stack-template/contracts/events/fixtures/task.assigned.json +11 -0
- package/stack-template/contracts/events/fixtures/task.assignment_failed.json +11 -0
- package/stack-template/contracts/events/fixtures/task.created.json +12 -0
- package/stack-template/contracts/events/fixtures/task.deleted.json +10 -0
- package/stack-template/contracts/events/fixtures/task.updated.json +12 -0
- package/stack-template/contracts/events/task-events.md +80 -0
- package/stack-template/contracts/openapi/activity.yaml +196 -0
- package/stack-template/contracts/openapi/auth.yaml +310 -0
- package/stack-template/contracts/openapi/tasks.yaml +316 -0
- package/stack-template/contracts/openapi/users.yaml +345 -0
- package/stack-template/docs/adr/0001-mixed-stack.md +14 -0
- package/stack-template/docs/adr/0002-mf-rspack.md +14 -0
- package/stack-template/docs/adr/0003-contract-first.md +14 -0
- package/stack-template/docs/adr/0004-readonly-schema-tradeoff.md +14 -0
- package/stack-template/docs/adr/0005-fail-closed.md +14 -0
- package/stack-template/docs/adr/0006-fire-and-forget-events.md +14 -0
- package/stack-template/docs/adr/0007-fork-not-upgrade.md +14 -0
- package/stack-template/docs/adr/0008-kafka-outbox-saga.md +24 -0
- package/stack-template/docs/adr/0009-ui-kit-split.md +39 -0
- package/stack-template/docs/adr/README.md +15 -0
- package/stack-template/docs/ai/recipes.md +956 -0
- package/stack-template/docs/ai/table-Theming.md +25 -0
- package/stack-template/docs/ai/table-datadisplay-mz.md +20 -0
- package/stack-template/docs/ai/table-feedback.md +20 -0
- package/stack-template/docs/ai/table-forms.md +26 -0
- package/stack-template/docs/git-flow.md +70 -0
- package/stack-template/docs/parity-matrix.md +102 -0
- package/stack-template/docs/superpowers/contexts/auth-real/gap-answer.md +195 -0
- package/stack-template/docs/superpowers/contexts/auth-real/sf-1.md +21 -0
- package/stack-template/docs/superpowers/contexts/auth-real/sf-2.md +21 -0
- package/stack-template/docs/superpowers/contexts/auth-real/sf-3.md +17 -0
- package/stack-template/docs/superpowers/contexts/auth-real/sf-4.md +20 -0
- package/stack-template/docs/superpowers/contexts/auth-real/sf-5.md +21 -0
- package/stack-template/docs/superpowers/contexts/experience-design.md +85 -0
- package/stack-template/docs/superpowers/contexts/sf-1.md +39 -0
- package/stack-template/docs/superpowers/contexts/sf-2.md +42 -0
- package/stack-template/docs/superpowers/contexts/sf-3.md +42 -0
- package/stack-template/docs/superpowers/contexts/sf-4.md +26 -0
- package/stack-template/docs/superpowers/contexts/sf-5.md +36 -0
- package/stack-template/docs/superpowers/contexts/sf-6.md +36 -0
- package/stack-template/docs/superpowers/contexts/sf-7.md +35 -0
- package/stack-template/docs/superpowers/contexts/sf-cin-overview.md +21 -0
- package/stack-template/docs/superpowers/contexts/ui-redesign/sf-1.md +46 -0
- package/stack-template/docs/superpowers/contexts/ui-redesign/sf-2.md +44 -0
- package/stack-template/docs/superpowers/contexts/ui-redesign/sf-3.md +47 -0
- package/stack-template/docs/superpowers/contexts/ui-redesign/sf-4.md +44 -0
- package/stack-template/docs/superpowers/contexts/ui-redesign/sf-5.md +36 -0
- package/stack-template/docs/superpowers/designs/direction-approved.md +11 -0
- package/stack-template/docs/superpowers/designs/ui-redesign/drafts/a-roulette-soundviz.html +353 -0
- package/stack-template/docs/superpowers/designs/ui-redesign/drafts/b-reference.html +347 -0
- package/stack-template/docs/superpowers/designs/ui-redesign/drafts/c-designer.html +375 -0
- package/stack-template/docs/superpowers/designs/ui-redesign/ds-demo.html +140 -0
- package/stack-template/docs/superpowers/designs/ui-redesign-direction.md +93 -0
- package/stack-template/docs/superpowers/improvements-log.md +158 -0
- package/stack-template/docs/superpowers/mindmaps/auth-real.wakii +115 -0
- package/stack-template/docs/superpowers/mindmaps/kafka-outbox-saga.wakii +110 -0
- package/stack-template/docs/superpowers/mindmaps/micro-boilerplate.wakii +171 -0
- package/stack-template/docs/superpowers/mindmaps/ui-redesign.wakii +116 -0
- package/stack-template/docs/superpowers/mindmaps/vu53-cinematic-experience.wakii +32 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf-1-contracts-platform-plan.md +44 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf-3-spring-svc-impact.md +69 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf-3-spring-svc-plan.md +27 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf-4-go-svc-plan.md +99 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf-5-fe-shell-plan.md +64 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf-6-fe-remotes-plan.md +83 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf-7-convergence-plan.md +59 -0
- package/stack-template/docs/superpowers/plans/2026-10-12-sf2-node-svc-plan.md +19 -0
- package/stack-template/docs/superpowers/plans/2026-10-13-sf-1-kafka-foundation-plan.md +30 -0
- package/stack-template/docs/superpowers/plans/2026-10-13-sf-1-ui-redesign-plan.md +28 -0
- package/stack-template/docs/superpowers/plans/2026-10-13-sf-2-node-outbox-plan.md +46 -0
- package/stack-template/docs/superpowers/plans/2026-10-13-sf-3-go-consumer-plan.md +31 -0
- package/stack-template/docs/superpowers/plans/2026-10-13-sf-4-spring-tx-plan.md +96 -0
- package/stack-template/docs/superpowers/plans/2026-10-13-sf-5-convergence-plan.md +21 -0
- package/stack-template/docs/superpowers/plans/2026-10-14-sf-2-ui-redesign-plan.md +32 -0
- package/stack-template/docs/superpowers/plans/2026-10-14-sf-3-ui-redesign-plan.md +34 -0
- package/stack-template/docs/superpowers/plans/2026-10-14-sf-5-ui-redesign-plan.md +35 -0
- package/stack-template/docs/superpowers/plans/2026-10-17-auth-real-plan.md +112 -0
- package/stack-template/docs/superpowers/plans/2026-10-17-ui-kit-split-plan.md +18 -0
- package/stack-template/docs/superpowers/reviews/2026-10-18-data-display-coverage.md +52 -0
- package/stack-template/docs/superpowers/reviews/code-reviewer-sf-5-r1.md +65 -0
- package/stack-template/docs/superpowers/reviews/security-audit-sf-5-auth-real.md +39 -0
- package/stack-template/docs/superpowers/specs/2026-10-12-boilerplate-microservice-mfe.md +110 -0
- package/stack-template/docs/superpowers/specs/2026-10-12-sf-3-spring-svc-design.md +160 -0
- package/stack-template/docs/superpowers/specs/2026-10-12-sf-7-convergence-spec.md +114 -0
- package/stack-template/docs/superpowers/specs/2026-10-12-sf2-node-svc-spec.md +42 -0
- package/stack-template/docs/superpowers/specs/2026-10-13-kafka-outbox-saga.md +111 -0
- package/stack-template/docs/superpowers/specs/2026-10-13-ui-redesign.md +173 -0
- package/stack-template/docs/superpowers/specs/2026-10-14-sf-3-ui-redesign.md +46 -0
- package/stack-template/docs/superpowers/specs/2026-10-14-sf-5-ui-redesign.md +30 -0
- package/stack-template/docs/superpowers/specs/2026-10-17-antd-look-tokens.md +28 -0
- package/stack-template/docs/superpowers/specs/2026-10-17-auth-real-design.md +124 -0
- package/stack-template/docs/superpowers/specs/2026-10-17-tailwind-migration.md +32 -0
- package/stack-template/docs/superpowers/specs/2026-10-17-ui-kit-split.md +44 -0
- package/stack-template/docs/superpowers/specs/2026-10-18-0.3.0-release-notes.md +77 -0
- package/stack-template/docs/toolchain.md +28 -0
- package/stack-template/docs/wakii-playbook.md +172 -0
- package/stack-template/docs/walkthrough.md +204 -0
- package/stack-template/orca.yaml +146 -0
- package/stack-template/package.json +19 -0
- package/stack-template/platform/.env.example +72 -0
- package/stack-template/platform/conventions/01-dockerfile-pattern.md +78 -0
- package/stack-template/platform/conventions/02-healthcheck.md +26 -0
- package/stack-template/platform/conventions/03-logging.md +41 -0
- package/stack-template/platform/conventions/04-error-envelope.md +41 -0
- package/stack-template/platform/conventions/05-ports.md +38 -0
- package/stack-template/platform/conventions/06-configuration.md +25 -0
- package/stack-template/platform/conventions/07-cors.md +23 -0
- package/stack-template/platform/conventions/08-gateway-and-remotes.md +33 -0
- package/stack-template/platform/conventions/09-async-messaging.md +42 -0
- package/stack-template/platform/conventions/README.md +15 -0
- package/stack-template/platform/docker-compose.yml +255 -0
- package/stack-template/platform/gateway/nginx/nginx.conf +137 -0
- package/stack-template/platform/postgres/init/01-init.sh +55 -0
- package/stack-template/pnpm-lock.yaml +15992 -0
- package/stack-template/pnpm-workspace.yaml +24 -0
- package/stack-template/scripts/scaffold/scaffold.sh +110 -0
- package/stack-template/scripts/smoke/e2e.sh +305 -0
- package/stack-template/scripts/snapshot-stack-template.sh +84 -0
- package/stack-template/services/auth-svc/.dockerignore +5 -0
- package/stack-template/services/auth-svc/Dockerfile +32 -0
- package/stack-template/services/auth-svc/README.md +101 -0
- package/stack-template/services/auth-svc/drizzle/0000_init.sql +25 -0
- package/stack-template/services/auth-svc/drizzle/meta/0000_snapshot.json +190 -0
- package/stack-template/services/auth-svc/drizzle/meta/_journal.json +13 -0
- package/stack-template/services/auth-svc/drizzle.config.ts +10 -0
- package/stack-template/services/auth-svc/package.json +35 -0
- package/stack-template/services/auth-svc/pnpm-lock.yaml +2425 -0
- package/stack-template/services/auth-svc/src/app.test.ts +403 -0
- package/stack-template/services/auth-svc/src/app.ts +103 -0
- package/stack-template/services/auth-svc/src/auth-crypto.test.ts +32 -0
- package/stack-template/services/auth-svc/src/auth-crypto.ts +25 -0
- package/stack-template/services/auth-svc/src/db/client.ts +24 -0
- package/stack-template/services/auth-svc/src/db/migrate.ts +72 -0
- package/stack-template/services/auth-svc/src/db/schema.ts +39 -0
- package/stack-template/services/auth-svc/src/db/seed.ts +60 -0
- package/stack-template/services/auth-svc/src/env.test.ts +55 -0
- package/stack-template/services/auth-svc/src/env.ts +57 -0
- package/stack-template/services/auth-svc/src/logger.ts +31 -0
- package/stack-template/services/auth-svc/src/plugins/auth.ts +70 -0
- package/stack-template/services/auth-svc/src/repo.drizzle.integration.test.ts +182 -0
- package/stack-template/services/auth-svc/src/repo.drizzle.ts +144 -0
- package/stack-template/services/auth-svc/src/repo.test-support.ts +168 -0
- package/stack-template/services/auth-svc/src/repo.ts +60 -0
- package/stack-template/services/auth-svc/src/routes/auth.ts +193 -0
- package/stack-template/services/auth-svc/src/routes/health.ts +40 -0
- package/stack-template/services/auth-svc/src/server.ts +54 -0
- package/stack-template/services/auth-svc/tsconfig.json +20 -0
- package/stack-template/services/go-svc/.dockerignore +5 -0
- package/stack-template/services/go-svc/Dockerfile +19 -0
- package/stack-template/services/go-svc/README.md +93 -0
- package/stack-template/services/go-svc/cmd/server/main.go +105 -0
- package/stack-template/services/go-svc/go.mod +12 -0
- package/stack-template/services/go-svc/internal/api/auth.go +83 -0
- package/stack-template/services/go-svc/internal/api/auth_test.go +92 -0
- package/stack-template/services/go-svc/internal/api/envelope.go +61 -0
- package/stack-template/services/go-svc/internal/api/envelope_test.go +51 -0
- package/stack-template/services/go-svc/internal/api/fakes_test.go +105 -0
- package/stack-template/services/go-svc/internal/api/feed.go +98 -0
- package/stack-template/services/go-svc/internal/api/feed_test.go +118 -0
- package/stack-template/services/go-svc/internal/api/health.go +34 -0
- package/stack-template/services/go-svc/internal/api/health_test.go +46 -0
- package/stack-template/services/go-svc/internal/api/json.go +13 -0
- package/stack-template/services/go-svc/internal/api/middleware.go +82 -0
- package/stack-template/services/go-svc/internal/api/middleware_test.go +48 -0
- package/stack-template/services/go-svc/internal/api/openapi/activity.yaml +196 -0
- package/stack-template/services/go-svc/internal/api/openapi.go +29 -0
- package/stack-template/services/go-svc/internal/api/openapi_test.go +38 -0
- package/stack-template/services/go-svc/internal/api/router.go +86 -0
- package/stack-template/services/go-svc/internal/api/stats.go +63 -0
- package/stack-template/services/go-svc/internal/api/stats_test.go +83 -0
- package/stack-template/services/go-svc/internal/api/types.go +32 -0
- package/stack-template/services/go-svc/internal/apperr/apperr.go +9 -0
- package/stack-template/services/go-svc/internal/config/config.go +115 -0
- package/stack-template/services/go-svc/internal/config/config_test.go +92 -0
- package/stack-template/services/go-svc/internal/consumer/envelope.go +78 -0
- package/stack-template/services/go-svc/internal/consumer/envelope_test.go +154 -0
- package/stack-template/services/go-svc/internal/consumer/handler.go +91 -0
- package/stack-template/services/go-svc/internal/consumer/handler_test.go +136 -0
- package/stack-template/services/go-svc/internal/consumer/producer.go +117 -0
- package/stack-template/services/go-svc/internal/consumer/runner.go +194 -0
- package/stack-template/services/go-svc/internal/consumer/runner_test.go +351 -0
- package/stack-template/services/go-svc/internal/logging/logging.go +49 -0
- package/stack-template/services/go-svc/internal/model/model.go +37 -0
- package/stack-template/services/go-svc/internal/resolve/resolver.go +134 -0
- package/stack-template/services/go-svc/internal/resolve/resolver_test.go +82 -0
- package/stack-template/services/go-svc/internal/resolve/token.go +130 -0
- package/stack-template/services/go-svc/internal/resolve/token_test.go +151 -0
- package/stack-template/services/go-svc/internal/store/events.go +71 -0
- package/stack-template/services/go-svc/internal/store/migrate.go +90 -0
- package/stack-template/services/go-svc/internal/store/migrate_test.go +34 -0
- package/stack-template/services/go-svc/internal/store/migrations/0001_create_events.sql +20 -0
- package/stack-template/services/go-svc/internal/store/migrations/0002_widen_action_cascade.sql +14 -0
- package/stack-template/services/go-svc/internal/store/store.go +65 -0
- package/stack-template/services/go-svc/internal/store/tasks.go +109 -0
- package/stack-template/services/go-svc/internal/swagger/assets/LICENSE +202 -0
- package/stack-template/services/go-svc/internal/swagger/assets/NOTICE +2 -0
- package/stack-template/services/go-svc/internal/swagger/assets/favicon-16x16.png +0 -0
- package/stack-template/services/go-svc/internal/swagger/assets/favicon-32x32.png +0 -0
- package/stack-template/services/go-svc/internal/swagger/assets/swagger-ui-bundle.js +2 -0
- package/stack-template/services/go-svc/internal/swagger/assets/swagger-ui.css +3 -0
- package/stack-template/services/go-svc/internal/swagger/index.html +28 -0
- package/stack-template/services/go-svc/internal/swagger/swagger.go +38 -0
- package/stack-template/services/go-svc/test/integration/integration_test.go +523 -0
- package/stack-template/services/node-svc/.dockerignore +5 -0
- package/stack-template/services/node-svc/Dockerfile +27 -0
- package/stack-template/services/node-svc/README.md +155 -0
- package/stack-template/services/node-svc/drizzle/0000_init.sql +17 -0
- package/stack-template/services/node-svc/drizzle/0001_status-assignment-failed.sql +2 -0
- package/stack-template/services/node-svc/drizzle/0002_outbox-table.sql +7 -0
- package/stack-template/services/node-svc/drizzle/meta/0000_snapshot.json +136 -0
- package/stack-template/services/node-svc/drizzle/meta/0001_snapshot.json +136 -0
- package/stack-template/services/node-svc/drizzle/meta/0002_snapshot.json +180 -0
- package/stack-template/services/node-svc/drizzle/meta/_journal.json +27 -0
- package/stack-template/services/node-svc/drizzle.config.ts +10 -0
- package/stack-template/services/node-svc/package.json +39 -0
- package/stack-template/services/node-svc/pnpm-lock.yaml +2706 -0
- package/stack-template/services/node-svc/src/app.test.ts +611 -0
- package/stack-template/services/node-svc/src/app.ts +126 -0
- package/stack-template/services/node-svc/src/clients/spring.ts +53 -0
- package/stack-template/services/node-svc/src/compensation-consumer.test.ts +157 -0
- package/stack-template/services/node-svc/src/compensation-consumer.ts +170 -0
- package/stack-template/services/node-svc/src/db/client.ts +23 -0
- package/stack-template/services/node-svc/src/db/migrate.ts +63 -0
- package/stack-template/services/node-svc/src/db/schema-diff.test.ts +252 -0
- package/stack-template/services/node-svc/src/db/schema.ts +64 -0
- package/stack-template/services/node-svc/src/env.ts +52 -0
- package/stack-template/services/node-svc/src/logger.ts +18 -0
- package/stack-template/services/node-svc/src/outbox-relay.test.ts +141 -0
- package/stack-template/services/node-svc/src/outbox-relay.ts +182 -0
- package/stack-template/services/node-svc/src/plugins/auth.ts +76 -0
- package/stack-template/services/node-svc/src/repo.drizzle.test.ts +182 -0
- package/stack-template/services/node-svc/src/repo.drizzle.ts +158 -0
- package/stack-template/services/node-svc/src/repo.ts +73 -0
- package/stack-template/services/node-svc/src/routes/health.ts +42 -0
- package/stack-template/services/node-svc/src/routes/tasks.ts +287 -0
- package/stack-template/services/node-svc/src/server.ts +91 -0
- package/stack-template/services/node-svc/src/types/api.d.ts +391 -0
- package/stack-template/services/node-svc/src/types/log.ts +3 -0
- package/stack-template/services/node-svc/tsconfig.json +20 -0
- package/stack-template/services/spring-svc/.dockerignore +5 -0
- package/stack-template/services/spring-svc/.mvn/wrapper/maven-wrapper.properties +20 -0
- package/stack-template/services/spring-svc/Dockerfile +22 -0
- package/stack-template/services/spring-svc/README.md +121 -0
- package/stack-template/services/spring-svc/mvnw +332 -0
- package/stack-template/services/spring-svc/mvnw.cmd +206 -0
- package/stack-template/services/spring-svc/pom.xml +144 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/SpringSvcApplication.java +12 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/Team.java +64 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/TeamRepository.java +34 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/User.java +72 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/domain/UserRepository.java +10 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/logging/LowercaseLevelJsonProvider.java +24 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/security/JwtAuthFilter.java +89 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/security/JwtVerifier.java +48 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/service/TeamService.java +84 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ApiError.java +15 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ApiException.java +37 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/DevCorsConfig.java +41 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ErrorEnvelope.java +27 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/GlobalExceptionHandler.java +90 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/HealthController.java +46 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/ReadinessService.java +40 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/TeamController.java +79 -0
- package/stack-template/services/spring-svc/src/main/java/com/example/springsvc/web/UserController.java +187 -0
- package/stack-template/services/spring-svc/src/main/java/db/migration/V2__SeedUsers.java +66 -0
- package/stack-template/services/spring-svc/src/main/resources/application.yml +42 -0
- package/stack-template/services/spring-svc/src/main/resources/db/migration/V1__init.sql +24 -0
- package/stack-template/services/spring-svc/src/main/resources/logback-spring.xml +34 -0
- package/stack-template/services/spring-svc/src/main/resources/openapi/users.yaml +345 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/logging/LogShapeTest.java +39 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/security/JwtAuthFilterTest.java +106 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/seed/SeedMatchIntegrationTest.java +68 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/service/TeamServiceRollbackTest.java +122 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/DevCorsTest.java +45 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/HealthCheckTest.java +56 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/TeamApiTest.java +139 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/TestPingController.java +21 -0
- package/stack-template/services/spring-svc/src/test/java/com/example/springsvc/web/UserApiTest.java +182 -0
- package/stack-template/stack-manifest.json +285 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Fresh-clone walkthrough — từ clone đến demo chạy được
|
|
2
|
+
|
|
3
|
+
Checklist cho người MỚI copy boilerplate. Mọi lệnh dưới đây là những gì đã chạy thật trong CI (evidence: `docs/superpowers/evidence/sf-5-convergence/test-run.txt` — convergence 10 services + e2e 2 chiều; các SF trước: `evidence/sf-*/`).
|
|
4
|
+
|
|
5
|
+
## 0. Toolchain cần có
|
|
6
|
+
|
|
7
|
+
Đọc [toolchain.md](toolchain.md). Tóm tắt: Node 22 + pnpm 9 (corepack) + JDK 21 + Go 1.24 + bash/curl. Docker TÙY CHỌN (không có vẫn xong được — chọn đường A hoặc B bên dưới). LƯU Ý: saga demo (mục 4b) + DLQ cần Kafka → đường A (compose); đường B chỉ chạy happy path (`SMOKE_SAGA=0`).
|
|
8
|
+
|
|
9
|
+
## 1. Clone + cài đặt
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git clone <repo> && cd <repo>
|
|
13
|
+
pnpm install --frozen-lockfile # FE workspace (app/*)
|
|
14
|
+
cd services/node-svc && pnpm install --frozen-lockfile --ignore-workspace && cd ../.. # node-svc standalone lockfile
|
|
15
|
+
cd services/auth-svc && pnpm install --frozen-lockfile --ignore-workspace && cd ../.. # auth-svc standalone lockfile
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 2. Postgres + seed
|
|
19
|
+
|
|
20
|
+
Cần Postgres 16 chạy sẵn với init script của platform (schemas + roles + readonly grants):
|
|
21
|
+
|
|
22
|
+
- **Có Docker (dễ nhất):** `cd platform && cp .env.example .env` (điền mật khẩu) → `docker compose up -d postgres` — init script `platform/postgres/init/01-init.sh` tự chạy lần đầu.
|
|
23
|
+
- **Không Docker:** cài/portable Postgres 16, `initdb` một data dir rồi chạy nội dung `platform/postgres/init/01-init.sh` tay (tạo db `boilerplate`, roles `node_svc`/`spring_svc`/`go_svc`/`go_readonly`/`auth_svc` với mật khẩu khớp .env, schemas + default privileges).
|
|
24
|
+
|
|
25
|
+
## 3. Chọn đường chạy demo
|
|
26
|
+
|
|
27
|
+
### Đường A — Compose (có Docker — khuyến nghị)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cd platform
|
|
31
|
+
cp .env.example .env # điền JWT_SECRET (openssl rand -base64 48) + passwords
|
|
32
|
+
docker compose down -v # ⚠️ CHẠY 1 LẦN sau pull nếu máy có pgdata volume TỪ bản cũ:
|
|
33
|
+
# (1) Flyway V2 seed user svc-fail/svc-activity + (2) init script tạo
|
|
34
|
+
# schema `auth` + role `auth_svc` (auth-real SF-5) CHỈ chạy lúc volume
|
|
35
|
+
# MỚI — volume cũ thiếu → saga chết ở auth/validate, auth-svc chết ở
|
|
36
|
+
# DATABASE auth (healthcheck /readyz đỏ, gateway không lên được).
|
|
37
|
+
# ⚠️ `.env` tạo từ bản cũ: thêm `AUTH_SVC_DB_PASSWORD` (cp từ .env.example).
|
|
38
|
+
# Kafka KHÔNG có data volume — topics mất sau mỗi `down` → tạo tường minh
|
|
39
|
+
# TRƯỚC khi boot services (giống CI convergence.yml; tránh 2 race: go consumer
|
|
40
|
+
# kẹt empty-assignment khi subscribe trước topic + DLQ publish Unknown Topic):
|
|
41
|
+
docker compose up -d postgres kafka
|
|
42
|
+
until docker compose exec -T kafka /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 >/dev/null 2>&1; do sleep 2; done
|
|
43
|
+
for topic in task-events task-events.dlq; do
|
|
44
|
+
docker compose exec -T kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 \
|
|
45
|
+
--create --if-not-exists --topic "$topic" --partitions 1 --replication-factor 1
|
|
46
|
+
done
|
|
47
|
+
docker compose up -d --build # health-gated chain tự đợi đúng thứ tự (10 services, kafka lazy-connect)
|
|
48
|
+
bash ../scripts/smoke/e2e.sh # từ platform/ — script ở repo root. PASS = 15 bước, 3 luồng:
|
|
49
|
+
# happy : login→task→feed QUA KAFKA (outbox → topic → go consumer)
|
|
50
|
+
# auth-real : register→refresh rotation→reuse→401→logout + RBAC (user DELETE 403, alice 204)
|
|
51
|
+
# saga : assign svc-fail → task assignment_failed + event gốc ở task-events.dlq
|
|
52
|
+
# Mở browser: http://localhost:8080/ → login alice@demo.local / demo-password
|
|
53
|
+
# (hoặc tự register account mới — tab Register, mục 4a)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Đường B — Native (không Docker — từng service một)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# 4 service BE — mỗi lệnh 1 terminal, env theo .env.example (placeholder dev):
|
|
60
|
+
cd services/auth-svc && JWT_SECRET=<dev-secret> PORT=8090 \
|
|
61
|
+
DATABASE_URL="postgres://auth_svc:<pw>@localhost:5432/boilerplate" \
|
|
62
|
+
USERS_FIXTURE_PATH=$(pwd)/../../contracts/auth/users.json \
|
|
63
|
+
AUTH_DEV_PASSWORD=demo-password pnpm dev
|
|
64
|
+
|
|
65
|
+
cd services/spring-svc && SPRING_DATASOURCE_URL="jdbc:postgresql://localhost:5432/boilerplate" \
|
|
66
|
+
SPRING_DATASOURCE_USERNAME=spring_svc SPRING_DATASOURCE_PASSWORD=<pw> \
|
|
67
|
+
JWT_SECRET=<dev-secret> SERVER_PORT=8081 USERS_FIXTURE_PATH=$(pwd)/../../contracts/auth/users.json \
|
|
68
|
+
./mvnw spring-boot:run # Windows: ./mvnw.cmd
|
|
69
|
+
|
|
70
|
+
cd services/node-svc && JWT_SECRET=<dev-secret> PORT=3001 \
|
|
71
|
+
DATABASE_URL="postgres://node_svc:<pw>@localhost:5432/boilerplate" \
|
|
72
|
+
SPRING_SVC_URL=http://localhost:8081 GO_SVC_URL=http://localhost:8082 pnpm dev
|
|
73
|
+
|
|
74
|
+
cd services/go-svc && JWT_SECRET=<dev-secret> PORT=8082 \
|
|
75
|
+
DATABASE_URL="postgres://go_svc:<pw>@localhost:5432/boilerplate" \
|
|
76
|
+
DATABASE_READONLY_URL="postgres://<owner-user>:<owner-pw>@localhost:5432/boilerplate" \
|
|
77
|
+
SPRING_SVC_URL=http://localhost:8081 go run ./cmd/server
|
|
78
|
+
|
|
79
|
+
# FE (3 terminal):
|
|
80
|
+
cd app/shell && pnpm dev # :3000
|
|
81
|
+
cd app/remotes/tasks && pnpm dev # :4001
|
|
82
|
+
cd app/remotes/activity && pnpm dev # :4002
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Native mode KHÔNG có nginx gateway — FE gọi thẳng service port theo conventions/07 (CORS dev đã mở). Chain 3 service "qua một cổng" là đặc tính của compose mode (đường A) + CI e2e-smoke job.
|
|
86
|
+
|
|
87
|
+
### Verify chain bằng smoke script (cả hai đường)
|
|
88
|
+
|
|
89
|
+
Script gọi qua prefix `/api/<svc>` (giống gateway routing — conventions/08):
|
|
90
|
+
- Đường A (từ repo root, không cd platform): `bash scripts/smoke/e2e.sh` (mặc định `GATEWAY_URL=http://localhost:8080`). Mặc định chạy **2 chiều** — happy + saga kèm DLQ assert (cần docker để exec `kafka-console-consumer` trong container kafka).
|
|
91
|
+
- Đường B (native, không Kafka): `SMOKE_SAGA=0 bash scripts/smoke/e2e.sh` — happy + auth-real (bỏ saga + DLQ). Không có gateway thật — chứng minh chain bằng cách gọi service trực tiếp, hoặc dựng proxy mapping `/api/*` (SF-7 dùng mini Node proxy cục bộ khi verify native — KHÔNG commit vì chỉ phục vụ verify).
|
|
92
|
+
|
|
93
|
+
## 4. Browser walkthrough (human gate — KHÔNG trong CI)
|
|
94
|
+
|
|
95
|
+
Trên máy có stack sống (đường A hoặc B + FE dev servers). UI theo light **antd-look** (decision 2026-10-17 — spec `docs/superpowers/specs/2026-10-17-antd-look-tokens.md`): nền canvas `#f5f5f5`, khối trắng `#ffffff`, 1 accent `#1677ff`, badge pill chấm-màu; dark (palette direction B cũ) là theme phụ qua `UiKitProvider` (`data-bp-theme`).
|
|
96
|
+
|
|
97
|
+
1. Mở `http://localhost:8080/` (đường A) hoặc `http://localhost:3000/` (đường B) → thấy **dashboard chào** với quick links Tasks/Activity + box **TÀI KHOẢN DEMO** (`alice@demo.local / demo-password`, `fail@demo.local`). Login → nav phải hiện user chip (avatar + email) + nút **Đăng xuất**.
|
|
98
|
+
2. Nav → **Tasks** (item nav active gạch accent): form **Tạo task** (Tiêu đề + Mô tả) → task mới xuất hiện đầu danh sách, heading **"Danh sách (x/total)"** cập nhật. Thử tiếp:
|
|
99
|
+
- **Sửa inline**: nút *Sửa* trên card → input inline tiêu đề/mô tả → *Lưu* (PATCH thật) / *Huỷ*.
|
|
100
|
+
- **Đổi status**: select trên card (`Cần làm` / `Đang làm` / `Xong`) — lúc PATCH đang bay item hiện spinner + select khoá (per-item busy).
|
|
101
|
+
- **Lọc**: chip `Tất cả` / `Cần làm` / `Đang làm` / `Xong` → danh sách + "x/total" lọc theo `?status=`.
|
|
102
|
+
- **Tải thêm**: nếu total > số đã tải, nút *Tải thêm* cuối danh sách nạp trang kế (limit/offset thật), "x/total" tăng dần tới đủ.
|
|
103
|
+
- **Xoá**: nút *Xoá* → xác nhận inline ("Xoá task này?" → *Xác nhận xoá* / *Huỷ*) — xoá thật qua DELETE.
|
|
104
|
+
- Mỗi card hiển thị assignee (UUID rút gọn monospace, hover thấy đủ), "Chưa gán" nếu trống, + createdAt vi-VN.
|
|
105
|
+
3. Nav → **Activity**: **stats cards** (Tổng task / Cần làm / Đang làm / Xong / Sự kiện 24h qua) + **feed timeline nhóm theo ngày** phản ánh mọi thao tác ở bước 2 qua Kafka (outbox → `task-events` → go consumer): badge "đã tạo / đã cập nhật / đã giao / đã xoá" từng màu, tên task, time vi-VN. Nút *Làm mới* load lại.
|
|
106
|
+
4. **Remote-down fallback**: dừng 1 remote rồi reload shell — đường A: `docker stop boilerplate-remote-tasks-1`; đường B: Ctrl-C dev server `:4001`. Shell vẫn nguyên (nav + user chip), slot Tasks hiện fallback "Không tải được phần **tasks**…" + nút **Thử lại**; **Activity vẫn chạy bình thường**. Khôi phục: khởi động lại remote (`docker start` / chạy lại `pnpm dev`) rồi nút *Thử lại* tải lại remote; nếu nút chưa ăn (MF runtime giữ rejection cũ) thì **reload trang** — remote sống lại mount bình thường.
|
|
107
|
+
|
|
108
|
+
### 4a. Auth thật — register / refresh / logout-all 2 tab (epic auth-real)
|
|
109
|
+
|
|
110
|
+
1. **Register**: mở `http://localhost:8080/` → tab **Register** trên login screen → email mới + password (8–72 ký tự) + tên hiển thị → tạo xong là đăng nhập luôn (roles `["user"]`). Đăng xuất → đăng nhập lại bằng account vừa tạo ✓.
|
|
111
|
+
2. **Refresh rotation (2 tab)**: đăng nhập cùng account ở 2 tab. Tab 1 đứng yên đến khi access token hết hạn (30m) — request kế tab 1 tự refresh (rotate) rồi retry, KHÔNG bị văng về login. (Nhạy hơn: `POST /api/auth/refresh` tay bằng refreshToken trong `localStorage['bp.rt']` — response trả cặp mới, token cũ không dùng lại được.)
|
|
112
|
+
3. **Logout-all (chuẩn acceptance — 1 tab chết, 1 tab còn)**: tab 2 bấm **Đăng xuất** (chỉ revoke refresh của tab đó — tab 1 VẪN sống vì access token 30m còn hạn). Để chết HẾT tab: gọi logout-all (chưa có nút UI — dùng token của account). P2 security-audit SF-5: đừng dán token thẳng vào lệnh (rơi shell history) — dùng `read -rs`:
|
|
113
|
+
```bash
|
|
114
|
+
read -rs TOKEN # dán access token rồi Enter (không echo)
|
|
115
|
+
curl -X POST http://localhost:8080/api/auth/logout-all -H "Authorization: Bearer $TOKEN"
|
|
116
|
+
unset TOKEN
|
|
117
|
+
```
|
|
118
|
+
Quay lại tab 1, bấm bất kỳ thao tác gọi API kế tiếp → 401 → auto-refresh fail (token bị revoke-all) → về màn login. Đó là hành vi ĐÚNG (không cross-tab realtime — kiểm ở request kế).
|
|
119
|
+
4. **RBAC demo**: login `bob@demo.local` / `demo-password` (roles `["user"]`) → tạo task → nút **Xoá** → bị chặn (403 FORBIDDEN — hiện thông báo lỗi, task còn nguyên). Login `alice@demo.local` (roles `["admin"]`) → xoá cùng task → thành công. e2e assert cùng chuỗi (bước 11–12).
|
|
120
|
+
|
|
121
|
+
### 4b. Saga demo (story FI-76 — cần đường A, có Kafka)
|
|
122
|
+
|
|
123
|
+
1. Trong **Tasks**, tạo task (vd `saga-demo`) rồi gán cho user fixture fail: **`fail@demo.local`** — UI hiển thị assignee ở chế độ read-only (UUID rút gọn), việc gán đi qua API: `PATCH /api/tasks/{id}` với `assigneeId=55555555-5555-4555-8555-555555555555` (swagger `:8080/api/tasks/docs` hoặc curl với Bearer token).
|
|
124
|
+
2. Go consumer cố tình fail ×3 (simulate hook — assignee trùng svc-fail) → publish compensating event `task.assignment_failed` vào topic chung → node compensation consumer cập nhật status.
|
|
125
|
+
3. Quan sát trên **Tasks**: task chuyển badge **"Gán thất bại"** (pill đỏ chấm đỏ — nhận diện rõ; task ở trạng thái này không còn select status — system-owned). Event gốc (task.assigned) nằm ở `task-events.dlq`:
|
|
126
|
+
```bash
|
|
127
|
+
docker compose -f platform/docker-compose.yml --env-file platform/.env.example exec -T kafka \
|
|
128
|
+
/opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 \
|
|
129
|
+
--topic task-events.dlq --from-beginning --timeout-ms 15000
|
|
130
|
+
# mỗi dòng = 1 DLQ message: {"schemaVersion":1,"originalEvent":"{...task.assigned...}","error":{"reason":...,"retries":3,...}}
|
|
131
|
+
```
|
|
132
|
+
4. **Recovery**: re-assign cho user hợp lệ (bob, id `22222222-2222-4222-8222-222222222222`) → saga chạy lại từ đầu (bob ≠ svc-fail, go handler xử lý thường). LƯU Ý: `assignment_failed` là system-owned — re-assign KHÔNG tự reset status (repo `update()` chỉ set field trong patch); muốn đưa task về luồng hiển thị bình thường, PATCH tường minh `{"assigneeId":"<bob-id>","status":"todo"}` (status writable 3 giá trị — `assignment_failed` PATCH cấm). Trên UI task có lại badge "Cần làm" + select status.
|
|
133
|
+
|
|
134
|
+
> ℹ️ BUG-1 standalone prod trắng trang (report VU-53, 2026-10-14) **ĐÃ FIX** (sf-5b): shared `eager:true` + entry `standalone` static + nginx alias `/remotes/<name>/` — standalone :4001/:4002 render đầy đủ ở build prod. Evidence: `docs/superpowers/evidence/sf-5b-ui-redesign-fix/` (browser walkthrough + phantom-grep trước/sau).
|
|
135
|
+
|
|
136
|
+
> ℹ️ Job `convergence/e2e-smoke` (GitHub Actions) mô tả chuỗi saga assert status + DLQ bằng `kafka-console-consumer` (không cần browser) — **hiện workflow ĐANG DISABLE (billing, xem CLAUDE.md)**; gate khi push là `.husky/pre-push` (chỉ FE checks, không chạy e2e). Cần verify saga thì chạy tay: `bash scripts/smoke/e2e.sh` (mục "Verify chain bằng smoke script" trên).
|
|
137
|
+
|
|
138
|
+
### 4c. Storybook — design system sống (Templates + 129 titles)
|
|
139
|
+
|
|
140
|
+
UI của shell/remotes build từ `@wakii/ui-kit` — xem toàn bộ + thử template ghép sẵn:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pnpm --filter @wakii/ui-kit storybook # → http://localhost:6006 (script tự stamp version)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Số liệu thật (index Storybook 2026-10-18): **129 titles · 623 story exports**, trong đó
|
|
147
|
+
nhóm **Templates** — 6 template "trang thật" (controlled state sống, không phải mock render):
|
|
148
|
+
|
|
149
|
+
| Template | Story path (`?path=/story/…`) | Ghép từ |
|
|
150
|
+
|----------|-------------------------------|---------|
|
|
151
|
+
| Dashboard admin | `templates-dashboard--dashboard` | `Layout` (Sider+Header) + Row/Col + Card/Statistic + Table + Timeline + Chart |
|
|
152
|
+
| Kanban project | `templates-kanban-project--project-board` | `KanbanBoard` (4 cột + WIP limit) + Segmented/Input.Search/Select filter + `Timesheet` + `message` toast khi move |
|
|
153
|
+
| CRUD table | `templates-crud-table--full-demo` | `Table` (sort 3-state/selection/expandable/fixed header/summary) + `Drawer` form (useForm+zod) + `Popconfirm` + `message` |
|
|
154
|
+
| Auth | `templates-auth--sign-in` · `--sign-up` · `--split-layout` | `useForm` + zod + Field/Input/Button + `Layout` split |
|
|
155
|
+
| Landing | `templates-landing--landing-alive` | `Parallax` + `Reveal` + `CountUp`/`Statistic` + `Grid` |
|
|
156
|
+
| Settings | `templates-settings--settings` | `Tabs` + `Switch` + `Field` + live theme toggle |
|
|
157
|
+
|
|
158
|
+
Mẹo: toolbar Storybook có **toggle dark** (`data-bp-theme` trên body preview — mọi component
|
|
159
|
+
theo token nên cả index đổi theme 1 click). AI agents đọc [AGENTS.md](../AGENTS.md) +
|
|
160
|
+
[docs/ai/recipes.md](ai/recipes.md) — bản đồ khi-dùng + 12 recipe copy-chạy. Chi tiết
|
|
161
|
+
Templates: `app/ui-kit/README.md` § Templates.
|
|
162
|
+
|
|
163
|
+
## 5. Copy/scaffold project mới
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
bash scripts/scaffold/scaffold.sh my-project
|
|
167
|
+
cd my-project
|
|
168
|
+
pnpm install --no-frozen-lockfile # lần đầu non-frozen — xem SCAFFOLD.md
|
|
169
|
+
# rồi lặp lại mục 2-4 trong project mới
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Phát triển tiếp project mới theo story workflow (Wakii): xem [wakii-playbook.md](wakii-playbook.md) — decision tree story/single/fix + 4 archetype chia SF + gates.
|
|
173
|
+
|
|
174
|
+
## 6. CI báo gì
|
|
175
|
+
|
|
176
|
+
| Workflow | Chạy khi | Bằng chứng |
|
|
177
|
+
|----------|---------|-----------|
|
|
178
|
+
| `contracts` | contracts/**, platform/** đổi | spectral + gitleaks + compose config + boot-smoke auth-svc + schemathesis FULL (auth.yaml v2) |
|
|
179
|
+
| `services-*` / `shell` / `remotes-*` | thư mục tương ứng đổi | build + test + docker build + boot-smoke (node/go có kafka boot-smoke) |
|
|
180
|
+
| `convergence` (SF-5, story FI-76) | mọi push | e2e 2 chiều trên compose 10 services (happy qua Kafka + saga → `assignment_failed` + DLQ assert) + copy-dir standalone + scaffold output build được |
|
|
181
|
+
|
|
182
|
+
## 7. Hành trình team — app-fit 4 apps + tài liệu nội bộ (2026-10-18)
|
|
183
|
+
|
|
184
|
+
**App-fit**: 4 app FE đã migrate hết sang `@wakii/ui-kit` (tokens + components qua source):
|
|
185
|
+
|
|
186
|
+
| App | Đã fit |
|
|
187
|
+
|-----|--------|
|
|
188
|
+
| `app/shell` (MF host :3000) | layout + nav + tokens từ phiên trước |
|
|
189
|
+
| `app/remotes/tasks` (:4001) | `TaskForm`/`TaskItem` chuyển `useForm` + zod + `Field`/`Input`/`Textarea` (+`useFieldArray` sẵn trong kit), `TaskList` giữ contract (EmptyState ở page level) |
|
|
190
|
+
| `app/remotes/activity` (:4002) | `ActivityPage` + `StatTile` → `Card`/`Statistic` ui-kit |
|
|
191
|
+
| `app/admin` | dashboard layout `Grid`/`Card`/`Statistic` giữ stat-intent |
|
|
192
|
+
|
|
193
|
+
**Templates**: 6 trang mẫu ghép sẵn trong Storybook (bảng §4) — copy điểm khởi đầu cho
|
|
194
|
+
trang thật; recipes kèm tại [docs/ai/recipes.md](ai/recipes.md).
|
|
195
|
+
|
|
196
|
+
**Hướng tới 0.3.0**: megagate 32 commits (241416f..HEAD) đã gate xanh — release notes
|
|
197
|
+
draft soạn sẵn tại [`docs/superpowers/specs/2026-10-18-0.3.0-release-notes.md`](superpowers/specs/2026-10-18-0.3.0-release-notes.md) — merge PR là chốt release
|
|
198
|
+
(ui-kit consumed qua source nên "release" = điểm merge, xem CHANGELOG head).
|
|
199
|
+
|
|
200
|
+
**Tài liệu nội bộ team (local-only, gitignored — không vào PR)**: `docs/team/` chứa
|
|
201
|
+
[RULES.md](team/RULES.md) (hiến phần vận hành: vai trò, vòng làm việc, thang tin cậy
|
|
202
|
+
T1→T3, sở hữu file), `TEAM.md` (roster + standup + report log), `DECISIONS.md`
|
|
203
|
+
(tiền-duyệt), `inbox/` (thư peer-to-peer), `CHANNEL.md`. Bản tóm tắt in-repo cho
|
|
204
|
+
session mới: [CLAUDE.md](../CLAUDE.md) § "Team protocol".
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# orca.yaml — descriptor MÁY ĐỌC cho AI agent (Claude Code / Orca agents / Codex…).
|
|
2
|
+
# ⚠️ Orca CLI KHÔNG consume file này — nó là bản đồ repo dạng structured cho agent
|
|
3
|
+
# parse khi onboard. Văn bản cho người/xét nghiệm: CLAUDE.md + docs/walkthrough.md.
|
|
4
|
+
# Quy ước: sửa file này CÙNG commit với mọi thay đổi nó mô tả (port, lệnh, path) —
|
|
5
|
+
# drift giữa descriptor và thực tế = lỗi onboarding agent (tương tự quy tắc 4 chỗ
|
|
6
|
+
# của port table — platform/conventions/05-ports.md).
|
|
7
|
+
name: architecture-overview
|
|
8
|
+
description: >
|
|
9
|
+
Boilerplate nội bộ copy-able (epic FI-62): mixed-stack services
|
|
10
|
+
(Node/Spring/Go) + Module Federation FE (Rspack), demo e2e task management
|
|
11
|
+
qua nginx gateway, Docker Compose + CI. Scaffold project mới:
|
|
12
|
+
bash scripts/scaffold/scaffold.sh <tên-mới>
|
|
13
|
+
|
|
14
|
+
stack:
|
|
15
|
+
node: ">=22"
|
|
16
|
+
pnpm: ">=9" # corepack enable — root packageManager pin 9.15.9
|
|
17
|
+
jdk: "21"
|
|
18
|
+
go: "1.24"
|
|
19
|
+
postgres: "16"
|
|
20
|
+
workspaces: pnpm workspace (root) NHƯNG node-svc + auth-svc có standalone lockfile (cài riêng, xem services.auth-svc.install)
|
|
21
|
+
|
|
22
|
+
# ── Contracts — SOURCE OF TRUTH. Sửa contract TRƯỚC, code theo sau. ──────────
|
|
23
|
+
contracts:
|
|
24
|
+
openapi: [contracts/openapi/tasks.yaml, contracts/openapi/users.yaml, contracts/openapi/activity.yaml, contracts/openapi/auth.yaml]
|
|
25
|
+
ddl_canonical: contracts/db/tasks-schema.sql
|
|
26
|
+
events_contract: contracts/events/task-events.md
|
|
27
|
+
event_fixtures: contracts/events/fixtures/ # golden envelope — node/go test cùng nguồn
|
|
28
|
+
auth_users_fixture: contracts/auth/users.json # id UUID CỐ ĐỊNH — không đổi id user cũ
|
|
29
|
+
lint: pnpm lint:contracts # spectral
|
|
30
|
+
|
|
31
|
+
services:
|
|
32
|
+
gateway:
|
|
33
|
+
type: nginx
|
|
34
|
+
port: 8080
|
|
35
|
+
path: platform/gateway
|
|
36
|
+
note: CỔNG DUY NHẤT browser/FE chạm vào — routing /api/<svc>/* + presence-check JWT (401)
|
|
37
|
+
node-svc:
|
|
38
|
+
path: services/node-svc
|
|
39
|
+
port: 3001
|
|
40
|
+
tech: Fastify + TypeScript + Drizzle
|
|
41
|
+
install: cd services/node-svc && pnpm install --frozen-lockfile --ignore-workspace
|
|
42
|
+
dev: pnpm dev # tsx watch
|
|
43
|
+
build: pnpm build # tsc
|
|
44
|
+
test: pnpm test # vitest run
|
|
45
|
+
healthz: [/healthz, /readyz]
|
|
46
|
+
owns: schema tasks — CRUD + outbox relay + compensation consumer (Kafka)
|
|
47
|
+
spring-svc:
|
|
48
|
+
path: services/spring-svc
|
|
49
|
+
port: 8081
|
|
50
|
+
tech: Spring Boot 3 + Flyway
|
|
51
|
+
run: ./mvnw spring-boot:run
|
|
52
|
+
test: ./mvnw test
|
|
53
|
+
owns: schema users + teams (@Transactional demo)
|
|
54
|
+
go-svc:
|
|
55
|
+
path: services/go-svc
|
|
56
|
+
port: 8082
|
|
57
|
+
tech: Go 1.24 + chi
|
|
58
|
+
run: go run ./cmd/server
|
|
59
|
+
test: go test ./...
|
|
60
|
+
healthz: [/healthz, /readyz]
|
|
61
|
+
owns: schema activity (tự migrate) — feed/stats + Kafka consumer (idempotent, retry ×3 → DLQ + saga)
|
|
62
|
+
note: đọc-ONLY schema tasks qua role go_readonly; snapshot openapi nhúng phải bit-identical contract (CI drift-guard)
|
|
63
|
+
auth-svc:
|
|
64
|
+
path: services/auth-svc
|
|
65
|
+
port: 8090
|
|
66
|
+
tech: Fastify + TypeScript + Drizzle (auth thật — epic auth-real VU-59)
|
|
67
|
+
install: cd services/auth-svc && pnpm install --frozen-lockfile --ignore-workspace
|
|
68
|
+
dev: pnpm dev # tsx watch
|
|
69
|
+
build: pnpm build # tsc
|
|
70
|
+
test: pnpm test # vitest run
|
|
71
|
+
healthz: [/healthz, /readyz]
|
|
72
|
+
owns: schema auth (users + refresh_tokens — seed users.json GIỮ UUID) — register/login/refresh rotation CAS/reuse-detect/logout; claims roles = RBAC source
|
|
73
|
+
note: iss JWT PINNED "auth-mock" (token-contract.md — giá trị lịch sử, KHÔNG đổi theo tên service)
|
|
74
|
+
|
|
75
|
+
app:
|
|
76
|
+
shared:
|
|
77
|
+
path: app/shared
|
|
78
|
+
scope: "@wakii/fe-shared"
|
|
79
|
+
role: LOGIC (api-client/token-storage/error-envelope/mf-bootstrap) — consumed QUA SOURCE, không build
|
|
80
|
+
read_locked: # cấm sửa ngoài story/epic được duyệt — versions + contracts đã test thật
|
|
81
|
+
- src/api-client.ts
|
|
82
|
+
- src/token-storage.ts
|
|
83
|
+
- src/error-envelope.ts
|
|
84
|
+
- src/mf-bootstrap.ts
|
|
85
|
+
- package.json#mfToolkit
|
|
86
|
+
ui-kit:
|
|
87
|
+
path: app/ui-kit
|
|
88
|
+
scope: "@wakii/ui-kit"
|
|
89
|
+
role: DESIGN SYSTEM (tokens + base css + primitives + Storybook 9 dev-only) — consumed QUA SOURCE; KHÔNG read-locked (đổi qua story thường, evidence = build-storybook) — ADR-0009
|
|
90
|
+
shell:
|
|
91
|
+
path: app/shell
|
|
92
|
+
port: 3000
|
|
93
|
+
role: MF host (Rspack) — nav + login + RemoteSlot (error boundary + retry)
|
|
94
|
+
commands: {dev: pnpm dev, build: pnpm build, test: pnpm test, typecheck: pnpm typecheck}
|
|
95
|
+
remotes:
|
|
96
|
+
tasks: {path: app/remotes/tasks, port: 4001, gateway: /remotes/tasks/}
|
|
97
|
+
activity: {path: app/remotes/activity, port: 4002, gateway: /remotes/activity/}
|
|
98
|
+
note: standalone dev vẫn tự mang tokens (import tokens trong entry — quyết định epic VU-53 #5)
|
|
99
|
+
pins: # catalog: (pnpm-workspace.yaml) + mfToolkit — NÂNG CẤP PHẢI RE-SPIKE (app/spike)
|
|
100
|
+
react: 19.3.0
|
|
101
|
+
react-dom: 19.3.0
|
|
102
|
+
rspack: 1.7.12
|
|
103
|
+
module-federation-enhanced: 0.21.6
|
|
104
|
+
|
|
105
|
+
run:
|
|
106
|
+
compose: # đường A — khuyến nghị, full saga + DLQ
|
|
107
|
+
prep: |
|
|
108
|
+
cd platform && cp -n .env.example .env # điền JWT_SECRET + passwords
|
|
109
|
+
docker compose --env-file .env up -d postgres kafka
|
|
110
|
+
# đợi kafka healthy rồi tạo topic TRƯỚC khi boot services (race empty-assignment):
|
|
111
|
+
for topic in task-events task-events.dlq; do
|
|
112
|
+
docker compose --env-file .env exec -T kafka /opt/kafka/bin/kafka-topics.sh \
|
|
113
|
+
--bootstrap-server localhost:9092 --create --if-not-exists --topic "$topic" \
|
|
114
|
+
--partitions 1 --replication-factor 1
|
|
115
|
+
done
|
|
116
|
+
docker compose --env-file .env up -d --build # 10 services, health-gated chain
|
|
117
|
+
verify: bash scripts/smoke/e2e.sh # 2 chiều — happy + saga + DLQ assert
|
|
118
|
+
url: http://localhost:8080
|
|
119
|
+
native: docs/walkthrough.md # đường B — từng service, SMOKE_SAGA=0 cho smoke
|
|
120
|
+
demo_login: {user: alice@demo.local, password: demo-password}
|
|
121
|
+
saga_fail_user: fail@demo.local # assign cho user này → go fail ×3 → assignment_failed → DLQ
|
|
122
|
+
|
|
123
|
+
test_all: # full suite local — PASS hết trước khi claim done
|
|
124
|
+
- pnpm --filter shell test && pnpm --filter shell typecheck
|
|
125
|
+
- pnpm --filter node-svc test
|
|
126
|
+
- pnpm --filter auth-svc test
|
|
127
|
+
- cd services/go-svc && go test ./...
|
|
128
|
+
- cd services/spring-svc && ./mvnw test
|
|
129
|
+
|
|
130
|
+
docs:
|
|
131
|
+
start_here: docs/walkthrough.md # fresh-clone → demo chạy được
|
|
132
|
+
conventions: platform/conventions/ # 01–09 — BẮT BUỘC, không đúng = review fail
|
|
133
|
+
adr: docs/adr/ # 0001–0009 — quyết định kiến trúc đã chốt
|
|
134
|
+
toolchain: docs/toolchain.md
|
|
135
|
+
ci: .github/workflows/ # 10 workflows (HIỆN DISABLE — xem gotchas) — bảng mô tả ở CLAUDE.md
|
|
136
|
+
evidence: docs/superpowers/evidence/ # test-run + screenshots theo story
|
|
137
|
+
|
|
138
|
+
gotchas:
|
|
139
|
+
- "CI GitHub Actions ĐANG DISABLE (billing, 2026-10) — gate khi push là .husky/pre-push (branch rule + FE checks theo path); workflows trong .github/ chỉ còn giá trị tham khảo khi bật lại"
|
|
140
|
+
- "Vitest test ranh giới ngày: TZ pin qua test.env trong vitest.config — môi trường dev +07 che bug, đừng bỏ pin"
|
|
141
|
+
- "node-svc + auth-svc: standalone lockfile — pnpm install PHẢI --ignore-workspace, chạy TRONG thư mục service, không phải workspace root"
|
|
142
|
+
- "fe-shared standalone: khai catalog: → cần mini workspace (sed catalog block từ root pnpm-workspace.yaml) — mẫu ở .github/workflows/convergence.yml step copy-dir"
|
|
143
|
+
- "pgdata volume từ bản cũ thiếu user svc-fail/svc-activity (Flyway V2) + role auth_svc/schema auth (init script chỉ chạy volume mới — auth-real SF-5) → docker compose down -v 1 lần rồi up lại; .env bản cũ thêm AUTH_SVC_DB_PASSWORD từ .env.example"
|
|
144
|
+
- "assignment_failed là system-owned: re-assign KHÔNG tự reset status — PATCH tường minh {assigneeId, status:'todo'} (status writable: todo/in_progress/done)"
|
|
145
|
+
- "Inter-service call QUA TÊN COMPOSE (http://node-svc:3001), không localhost; .env không bao giờ commit"
|
|
146
|
+
- "Sửa port = 4 chỗ cùng commit: conventions/05-ports.md + .env.example + docker-compose.yml + README"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__STACK_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Boilerplate microservice + micro-frontend — template nội bộ copy-able (epic FI-62)",
|
|
6
|
+
"packageManager": "pnpm@9.15.9",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22",
|
|
9
|
+
"pnpm": ">=9"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"lint:contracts": "spectral lint contracts/openapi/*.yaml",
|
|
13
|
+
"prepare": "test -e .git && husky || true"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@stoplight/spectral-cli": "^6.17.0",
|
|
17
|
+
"husky": "^9.1.0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# Env inventory ĐẦY ĐỦ — nguồn sự duy nhất về cấu hình compose + services.
|
|
3
|
+
# Cách dùng: cp .env.example .env rồi điền giá trị thật. .env KHÔNG commit.
|
|
4
|
+
# Quy tắc: thêm env var mới = thêm vào đây cùng commit (platform/conventions/06).
|
|
5
|
+
# ============================================================================
|
|
6
|
+
|
|
7
|
+
# --- Shared ---
|
|
8
|
+
# Secret ký + verify JWT HS256 (contracts/auth/token-contract.md). BẮT BUỘC đổi khi dùng.
|
|
9
|
+
# Sinh: openssl rand -base64 48
|
|
10
|
+
JWT_SECRET=change-me-openssl-rand-base64-48
|
|
11
|
+
|
|
12
|
+
# Log level mọi service: debug | info | warn | error
|
|
13
|
+
LOG_LEVEL=info
|
|
14
|
+
|
|
15
|
+
# --- Ports (platform/conventions/05-ports.md) ---
|
|
16
|
+
# ⚠️ Các biến *_PORT chỉ đổi port side HOST (truy cập từ máy dev); port TRONG
|
|
17
|
+
# mạng compose cố định theo bảng — container port hardcode trong compose.
|
|
18
|
+
GATEWAY_PORT=8080
|
|
19
|
+
SHELL_PORT=3000
|
|
20
|
+
REMOTE_TASKS_PORT=4001
|
|
21
|
+
REMOTE_ACTIVITY_PORT=4002
|
|
22
|
+
NODE_SVC_PORT=3001
|
|
23
|
+
SPRING_SVC_PORT=8081
|
|
24
|
+
GO_SVC_PORT=8082
|
|
25
|
+
AUTH_PORT=8090
|
|
26
|
+
POSTGRES_PORT=5432
|
|
27
|
+
|
|
28
|
+
# --- Postgres ---
|
|
29
|
+
POSTGRES_USER=boilerplate
|
|
30
|
+
POSTGRES_PASSWORD=change-me-postgres
|
|
31
|
+
POSTGRES_DB=boilerplate
|
|
32
|
+
|
|
33
|
+
# Password per-service DB role (tạo bởi platform/postgres/init/01-init.sh)
|
|
34
|
+
NODE_SVC_DB_PASSWORD=change-me-node
|
|
35
|
+
SPRING_SVC_DB_PASSWORD=change-me-spring
|
|
36
|
+
GO_SVC_DB_PASSWORD=change-me-go
|
|
37
|
+
GO_READONLY_DB_PASSWORD=change-me-goreadonly
|
|
38
|
+
AUTH_SVC_DB_PASSWORD=change-me-auth
|
|
39
|
+
|
|
40
|
+
# Password service user `svc-activity` (fixture users.json) — go-svc login
|
|
41
|
+
# auth lấy service token cho resolver (conventions/09). BẮT BUỘC khớp
|
|
42
|
+
# AUTH_DEV_PASSWORD (auth-svc so password hash của seeded users — token-contract.md §5).
|
|
43
|
+
SVC_ACTIVITY_PASSWORD=demo-password
|
|
44
|
+
|
|
45
|
+
# --- Kafka (conventions/09, ADR-0008) ---
|
|
46
|
+
# Bootstrap servers. Trong mạng compose = tên service `kafka:9092` (9092 KHÔNG
|
|
47
|
+
# expose ra host). Native dev ngoài compose override thành localhost:9092.
|
|
48
|
+
KAFKA_BROKERS=kafka:9092
|
|
49
|
+
|
|
50
|
+
# --- URLs inter-service (trong mạng compose dùng tên service) ---
|
|
51
|
+
NODE_SVC_URL=http://node-svc:3001
|
|
52
|
+
SPRING_SVC_URL=http://spring-svc:8081
|
|
53
|
+
GO_SVC_URL=http://go-svc:8082
|
|
54
|
+
# KEY giữ AUTH_MOCK_URL (go-svc đọc theo tên env này — gap-answer ④ epic VU-59);
|
|
55
|
+
# VALUE trỏ auth-svc (đổi KEY = follow-up cụm iss-rename).
|
|
56
|
+
AUTH_MOCK_URL=http://auth-svc:8090
|
|
57
|
+
SHELL_URL=http://shell:3000
|
|
58
|
+
REMOTE_TASKS_URL=http://remote-tasks:4001
|
|
59
|
+
REMOTE_ACTIVITY_URL=http://remote-activity:4002
|
|
60
|
+
|
|
61
|
+
# --- FE (dev, ngoài compose) ---
|
|
62
|
+
# Origin được phép CORS khi chạy native dev (platform/conventions/07-cors.md)
|
|
63
|
+
CORS_DEV_ORIGIN=http://localhost:3000,http://localhost:4001,http://localhost:4002
|
|
64
|
+
|
|
65
|
+
# --- auth (rename AUTH_MOCK_* → AUTH_* hoàn tất SF-5 VU-64 — compose đã swap) ---
|
|
66
|
+
# Dev password cho SEEDED fixture users (users.json — token-contract.md §5).
|
|
67
|
+
# Default demo-password KHÔNG ĐỔI: e2e + svc-activity + seed cùng một nguồn.
|
|
68
|
+
AUTH_DEV_PASSWORD=demo-password
|
|
69
|
+
# TTL access token JWT (auth-svc — token-contract.md §1)
|
|
70
|
+
ACCESS_TOKEN_TTL=30m
|
|
71
|
+
# Đường dẫn users fixture trong container
|
|
72
|
+
USERS_FIXTURE_PATH=/app/users.json
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 01 — Dockerfile multi-stage pattern
|
|
2
|
+
|
|
3
|
+
Mọi service dùng **2 stage**: `deps` (cài dependency, cache được) → `runtime` (copy artifact + prod deps, image mỏng). Không chạy build tool trong runtime image.
|
|
4
|
+
|
|
5
|
+
## Node (Fastify/TS — node-svc, auth-svc)
|
|
6
|
+
|
|
7
|
+
```dockerfile
|
|
8
|
+
# deps stage
|
|
9
|
+
FROM node:22-alpine AS deps
|
|
10
|
+
WORKDIR /app
|
|
11
|
+
COPY package.json pnpm-lock.yaml ./
|
|
12
|
+
RUN corepack enable && pnpm install --frozen-lockfile
|
|
13
|
+
|
|
14
|
+
# runtime stage
|
|
15
|
+
FROM node:22-alpine AS runtime
|
|
16
|
+
WORKDIR /app
|
|
17
|
+
ENV NODE_ENV=production
|
|
18
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
19
|
+
COPY dist ./dist
|
|
20
|
+
USER node
|
|
21
|
+
EXPOSE 3001
|
|
22
|
+
CMD ["node", "dist/server.js"]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Spring Boot (spring-svc)
|
|
26
|
+
|
|
27
|
+
```dockerfile
|
|
28
|
+
# deps stage — mvnw tải dependency vào layer cache riêng
|
|
29
|
+
FROM eclipse-temurin:21-jdk-alpine AS deps
|
|
30
|
+
WORKDIR /app
|
|
31
|
+
COPY .mvn .mvn
|
|
32
|
+
COPY mvnw pom.xml ./
|
|
33
|
+
RUN ./mvnw -B dependency:go-offline
|
|
34
|
+
|
|
35
|
+
# build stage
|
|
36
|
+
FROM deps AS build
|
|
37
|
+
COPY src src
|
|
38
|
+
RUN ./mvnw -B package -DskipTests
|
|
39
|
+
|
|
40
|
+
# runtime stage — JRE-only, jar fat
|
|
41
|
+
FROM eclipse-temurin:21-jre-alpine AS runtime
|
|
42
|
+
WORKDIR /app
|
|
43
|
+
COPY --from=build /app/target/*.jar app.jar
|
|
44
|
+
USER 1001
|
|
45
|
+
EXPOSE 8081
|
|
46
|
+
ENTRYPOINT ["java", "-jar", "app.jar"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Go (go-svc)
|
|
50
|
+
|
|
51
|
+
```dockerfile
|
|
52
|
+
# build stage
|
|
53
|
+
FROM golang:1.24-alpine AS build
|
|
54
|
+
WORKDIR /src
|
|
55
|
+
COPY go.mod go.sum ./
|
|
56
|
+
RUN go mod download
|
|
57
|
+
COPY . .
|
|
58
|
+
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /out/go-svc ./cmd/server
|
|
59
|
+
|
|
60
|
+
# runtime stage — static binary trên distroless
|
|
61
|
+
FROM gcr.io/distroless/static-debian12:nonroot AS runtime
|
|
62
|
+
COPY --from=build /out/go-svc /go-svc
|
|
63
|
+
EXPOSE 8082
|
|
64
|
+
ENTRYPOINT ["/go-svc"]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Quy tắc
|
|
68
|
+
|
|
69
|
+
1. **Pin base image theo digest hoặc minor tag cụ thể** — không `:latest`. SF-7 rà lại lần cuối.
|
|
70
|
+
2. Image chạy **non-root** (`USER node` / `USER 1001` / distroless nonroot).
|
|
71
|
+
3. `EXPOSE` = port của service theo [05-ports.md](05-ports.md).
|
|
72
|
+
4. Healthcheck KHÔNG khai trong Dockerfile — khai trong `platform/docker-compose.yml` (một nguồn duy nhất).
|
|
73
|
+
5. Thứ tự `COPY` tối ưu cache: lockfile/manifest trước, source sau.
|
|
74
|
+
6. CI boot-smoke build đúng Dockerfile này — nếu build local pass mà CI fail, check `.dockerignore` trước (node_modules/target/bin không được vào context).
|
|
75
|
+
7. **Lockfile variant cho workspace member (SF-7 sync — học từ SF-2, improvements-log):** service là member của pnpm workspace nhưng compose build context = **thư mục con** → root `pnpm-lock.yaml` KHÔNG vào được context. Hai cách chuẩn:
|
|
76
|
+
- **Local standalone lockfile** (precedent node-svc, auth-svc): commit `pnpm-lock.yaml` trong thư mục service (sinh bằng `pnpm install --ignore-workspace`), Dockerfile `COPY package.json pnpm-lock.yaml` + `pnpm install --frozen-lockfile`.
|
|
77
|
+
- **Repo-root build context** (precedent shell/remotes): Dockerfile khai `context: ..` + `dockerfile: app/<app>/Dockerfile` để root workspace lockfile + `app/shared` vào được context.
|
|
78
|
+
Đừng trộn: COPY root lockfile trong context thư mục con = build fail lúc deps stage.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# 02 — Healthcheck: `/healthz` + `/readyz`
|
|
2
|
+
|
|
3
|
+
Mọi HTTP service expose 2 endpoint không-auth (gateway không chặn, service không verify JWT trên 2 path này):
|
|
4
|
+
|
|
5
|
+
| Endpoint | Ý nghĩa | Trả về khi ổn | Trả về khi chưa ổn |
|
|
6
|
+
|----------|---------|---------------|--------------------|
|
|
7
|
+
| `/healthz` | **Liveness** — process sống | `200 {"status":"ok"}` | process chết → không response |
|
|
8
|
+
| `/readyz` | **Readiness** — nhận traffic được (deps xong) | `200 {"status":"ok"}` | `503` error envelope |
|
|
9
|
+
|
|
10
|
+
## Điều kiện ready per service
|
|
11
|
+
|
|
12
|
+
| Service | `/readyz` = 200 khi |
|
|
13
|
+
|---------|---------------------|
|
|
14
|
+
| node-svc | DB migration chạy xong + spring-svc reachable (kiểm lúc boot, không ping liên tục) |
|
|
15
|
+
| spring-svc | Flyway migration xong + DataSource healthy |
|
|
16
|
+
| go-svc | Migration schema `activity` xong + SELECT thử được schema `tasks` (readonly role) |
|
|
17
|
+
| auth-svc | migration schema auth + seed fixture xong (/readyz kiểm DB thật — rule 2) |
|
|
18
|
+
|
|
19
|
+
## Quy tắc
|
|
20
|
+
|
|
21
|
+
1. Body JSON: `{"status":"ok"}` — không thêm trường (CI boot-smoke grep đúng shape này).
|
|
22
|
+
2. `/readyz` phải kiểm tra **thật** (query DB thật), không hardcode 200.
|
|
23
|
+
3. Compose `healthcheck` khai ở `platform/docker-compose.yml` probe **`/readyz`** (health-gated — SF-7). Ngoại lệ có chủ đích: **go-svc KHÔNG có healthcheck trong compose** — runtime distroless không có shell/wget, Dockerfile read-only với convergence (SF-7); readiness của go-svc được chứng minh bằng `scripts/smoke/e2e.sh` poll `/api/activity/stats` (compose `depends_on` go-svc ở mức `service_started`). Gateway cũng KHÔNG có healthcheck (nginx proxy thuần, không route `/readyz` — probe sẽ 404).
|
|
24
|
+
4. CI boot-smoke job: container up → curl `/healthz` → curl `/readyz` → cả hai 200 mới pass.
|
|
25
|
+
5. Path mounting: service mount **prefix `/api/<svc>`** cho business routes; `/healthz` + `/readyz` nằm **ngoài prefix** (naked path, ví dụ node-svc serve `/healthz` chứ không phải `/api/tasks/healthz`). Xem [08-gateway-and-remotes.md](08-gateway-and-remotes.md).
|
|
26
|
+
6. **Mirror rule (SF-7, học từ SF-4 — improvements-log finding schemathesis 404):** service expose `/healthz` + `/readyz` **cả hai dạng** — naked path (cho compose healthcheck + CI boot-smoke) VÀ mirror dưới prefix `/api/<svc>/healthz` + `/api/<svc>/readyz` (cho OpenAPI spec khai dưới `servers.url` + schemathesis contract test). Áp cho MỌI service mới; auth-svc là precedent mới nhất (auth-mock cũ đã decommission — epic auth-real SF-5). Service không expose mirror = contract test fail 404 khi chạy qua base-url có prefix.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 03 — JSON log shape chung
|
|
2
|
+
|
|
3
|
+
Mọi service log JSON một dòng mỗi entry ra **stdout** (12-factor; compose/CI collect). Không log ra file.
|
|
4
|
+
|
|
5
|
+
## Shape
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"ts": "2026-10-12T05:00:00.123Z",
|
|
10
|
+
"level": "info",
|
|
11
|
+
"service": "node-svc",
|
|
12
|
+
"msg": "task created",
|
|
13
|
+
"requestId": "b1c2...",
|
|
14
|
+
"taskId": "9f0e...",
|
|
15
|
+
"durationMs": 12
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Trường | Bắt buộc | Ghi chú |
|
|
20
|
+
|--------|----------|---------|
|
|
21
|
+
| `ts` | ✓ | ISO 8601 UTC, độ chính xác ms |
|
|
22
|
+
| `level` | ✓ | `debug` \| `info` \| `warn` \| `error` |
|
|
23
|
+
| `service` | ✓ | `node-svc` \| `spring-svc` \| `go-svc` \| `auth-svc` \| `gateway` |
|
|
24
|
+
| `msg` | ✓ | Câu ngắn, tiếng Anh, không nhạy cảm |
|
|
25
|
+
| `requestId` | khi xử lý request | Lấy từ header `X-Request-Id` (gateway sinh nếu thiếu) — trace xuyên gateway → service |
|
|
26
|
+
| còn lại | tuỳ | Case camelCase; KHÔNG log JWT/email/password toàn phần (mask email: `a***@demo.local`) |
|
|
27
|
+
|
|
28
|
+
## Stack mapping
|
|
29
|
+
|
|
30
|
+
| Stack | Thư viện |
|
|
31
|
+
|-------|----------|
|
|
32
|
+
| node-svc | `pino` (mặc định JSON) |
|
|
33
|
+
| spring-svc | Logback `LogstashEncoder` (`net.logstash.logback`) |
|
|
34
|
+
| go-svc | `log/slog` JSON handler |
|
|
35
|
+
| auth-svc | `pino` |
|
|
36
|
+
|
|
37
|
+
## Quy tắc
|
|
38
|
+
|
|
39
|
+
1. **Fire-and-forget event push** (node-svc → go-svc): fail = log `level:"warn"`, msg chứa `event push failed`, KHÔNG raise error cho caller, KHÔNG retry (ADR SF-7).
|
|
40
|
+
2. Unhandled error: `level:"error"` + stack trong trường `err` (string).
|
|
41
|
+
3. Không dùng `console.log` trong service Node — mọi log đi qua logger có shape trên.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 04 — Error envelope chung
|
|
2
|
+
|
|
3
|
+
Mọi HTTP response 4xx/5xx của mọi service dùng **một** shape — mirror trong `components.schemas.Error` của cả 4 OpenAPI specs (spectral rule `error-envelope-shape` warn nếu lệch).
|
|
4
|
+
|
|
5
|
+
## Shape
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"error": {
|
|
10
|
+
"code": "TASK_NOT_FOUND",
|
|
11
|
+
"message": "Task 9f0e... không tồn tại",
|
|
12
|
+
"requestId": "b1c2...",
|
|
13
|
+
"details": null
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Trường | Bắt buộc | Ghi chú |
|
|
19
|
+
|--------|----------|---------|
|
|
20
|
+
| `error.code` | ✓ | `SCREAMING_SNAKE` — máy đọc được |
|
|
21
|
+
| `error.message` | ✓ | Người đọc được; không chứa secret |
|
|
22
|
+
| `error.requestId` | ✓ (nullable) | Echo `X-Request-Id` |
|
|
23
|
+
| `error.details` | ✗ | Dữ liệu bổ sung có cấu trúc (vd validation field errors) |
|
|
24
|
+
|
|
25
|
+
## Code catalog tối thiểu
|
|
26
|
+
|
|
27
|
+
| Code | HTTP | Dùng khi |
|
|
28
|
+
|------|------|----------|
|
|
29
|
+
| `VALIDATION_ERROR` | 400 | Payload sai schema |
|
|
30
|
+
| `UNAUTHORIZED` | 401 | Thiếu/sai/hết hạn JWT (service tự verify) |
|
|
31
|
+
| `NOT_FOUND` | 404 | Resource không tồn tại |
|
|
32
|
+
| `CONFLICT` | 409 | Email đã tồn tại… |
|
|
33
|
+
| `UNPROCESSABLE` | 422 | Assignee không tồn tại (spring trả 404 khi node validate) |
|
|
34
|
+
| `DEPENDENCY_DOWN` | 503 | spring-svc down khi node validate user (fail-closed); go không đọc được schema tasks |
|
|
35
|
+
| `INTERNAL` | 500 | Unhandled — KHÔNG lộ stack trong message |
|
|
36
|
+
|
|
37
|
+
## Quy tắc
|
|
38
|
+
|
|
39
|
+
1. Fastify/spring/Go framework error mặc định (vd Fastify `FST_ERR_*`) phải được **map sang envelope** bằng error handler riêng.
|
|
40
|
+
2. Gateway (nginx) 401 presence-check trả envelope tương tự (`{"error":{"code":"UNAUTHORIZED",...}}`) qua `default.conf` inline response.
|
|
41
|
+
3. FE decode envelope bằng helper `decodeErrorEnvelope` trong `app/shared` — không tự parse message đáy.
|