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,38 @@
|
|
|
1
|
+
# 05 — PORT TABLE (nguồn sự thật duy nhất)
|
|
2
|
+
|
|
3
|
+
Port cố định, giá trị dev = giá trị compose (override được qua `.env`, xem [06-configuration.md](06-configuration.md)). Không service nào tự chọn port khác.
|
|
4
|
+
|
|
5
|
+
## Bảng
|
|
6
|
+
|
|
7
|
+
| Thành phần | Port | Ghi chú |
|
|
8
|
+
|------------|------|---------|
|
|
9
|
+
| **nginx gateway** | **8080** | CỔNG DUY NHẤT browser/FE chạm vào |
|
|
10
|
+
| shell (MF host) | 3000 | dev server; compose static qua gateway `/` |
|
|
11
|
+
| remote `tasks` (FE) | 4001 | dev server; gateway `/remotes/tasks/` |
|
|
12
|
+
| remote `activity` (FE) | 4002 | dev server; gateway `/remotes/activity/` |
|
|
13
|
+
| node-svc | 3001 | Fastify + TS |
|
|
14
|
+
| spring-svc | 8081 | Spring Boot 3 |
|
|
15
|
+
| go-svc | 8082 | Go chi |
|
|
16
|
+
| auth-svc | 8090 | Fastify + TS (auth thật — epic auth-real) |
|
|
17
|
+
| postgres | 5432 | Postgres 16 |
|
|
18
|
+
|
|
19
|
+
## Env var tương ứng (khai trong `platform/.env.example`)
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
GATEWAY_PORT=8080
|
|
23
|
+
SHELL_PORT=3000
|
|
24
|
+
REMOTE_TASKS_PORT=4001
|
|
25
|
+
REMOTE_ACTIVITY_PORT=4002
|
|
26
|
+
NODE_SVC_PORT=3001
|
|
27
|
+
SPRING_SVC_PORT=8081
|
|
28
|
+
GO_SVC_PORT=8082
|
|
29
|
+
AUTH_PORT=8090
|
|
30
|
+
POSTGRES_PORT=5432
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quy tắc
|
|
34
|
+
|
|
35
|
+
1. Service **listen** theo env `PORT`/`SERVER_PORT` riêng của nó, default = bảng trên.
|
|
36
|
+
2. Inter-service call ĐI QUA TÊN COMPOSE (`http://node-svc:3001`), không qua gateway, không qua `localhost` — trong mạng docker `localhost` = container mình.
|
|
37
|
+
3. Native mode (không docker, dev local): gọi thẳng `http://localhost:<port>` — CORS rule xem [07-cors.md](07-cors.md).
|
|
38
|
+
4. Đổi port = sửa file này + `.env.example` + compose + README **trong cùng commit** (4 chỗ phải khớp).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 06 — Configuration: 100% qua env-var
|
|
2
|
+
|
|
3
|
+
Không config file riêng cho service. Không hardcode secret. 12-factor.
|
|
4
|
+
|
|
5
|
+
## Quy tắc
|
|
6
|
+
|
|
7
|
+
1. **Mọi cấu hình theo môi trường đi qua env-var** — DB URL, JWT secret, port, URL service láng giềng, level log.
|
|
8
|
+
2. `platform/.env.example` là **inventory ĐẦY ĐỦ** — thêm env var mới cho service nào phải thêm vào đó cùng commit, kèm comment 1 dòng giải thích. `.env` gitignored.
|
|
9
|
+
3. Compose đọc `.env` tự động (file cùng thư mục `platform/`); CI dùng `--env-file platform/.env.example` cho job chỉ validate.
|
|
10
|
+
4. Secret (`JWT_SECRET`, `POSTGRES_PASSWORD`, DB passwords): `.env.example` chứa **placeholder** rõ ràng (`change-me-...`), giá trị thật chỉ trong `.env` local / CI secret.
|
|
11
|
+
5. Tên env var: `SCREAMING_SNAKE_CASE`, prefix theo service (`NODE_SVC_*`, `SPRING_SVC_*`, `GO_SVC_*`, `AUTH_MOCK_*`) trừ shared (`JWT_SECRET`, `POSTGRES_*`, `GATEWAY_PORT`).
|
|
12
|
+
6. Service fail-fast khi thiếu env bắt buộc lúc boot (không fallback im lặng giá trị mặc định cho secret).
|
|
13
|
+
|
|
14
|
+
## Nhóm env chính (chi tiết đầy đủ trong `.env.example`)
|
|
15
|
+
|
|
16
|
+
| Nhóm | Biến |
|
|
17
|
+
|------|------|
|
|
18
|
+
| Shared secret | `JWT_SECRET` |
|
|
19
|
+
| Postgres | `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, `POSTGRES_PORT` |
|
|
20
|
+
| Per-service DB creds | `NODE_SVC_DB_PASSWORD`, `SPRING_SVC_DB_PASSWORD`, `GO_SVC_DB_PASSWORD`, `GO_READONLY_DB_PASSWORD` |
|
|
21
|
+
| Ports | xem [05-ports.md](05-ports.md) |
|
|
22
|
+
| URLs inter-service | `SPRING_SVC_URL`, `AUTH_MOCK_URL`, `SHELL_URL`, `REMOTE_TASKS_URL`, `REMOTE_ACTIVITY_URL` |
|
|
23
|
+
| CORS | `CORS_DEV_ORIGIN` |
|
|
24
|
+
| Log | `LOG_LEVEL` |
|
|
25
|
+
| Mock auth | `AUTH_MOCK_DEV_PASSWORD`, `USERS_FIXTURE_PATH` |
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 07 — CORS dev-profile rule
|
|
2
|
+
|
|
3
|
+
## Quy tắc cốt lõi
|
|
4
|
+
|
|
5
|
+
**Prod (qua gateway): KHÔNG cần CORS** — browser chỉ nói chuyện với một origin (gateway :8080); FE không bao giờ gọi service port trực tiếp.
|
|
6
|
+
|
|
7
|
+
**Dev native (không docker): CÓ CORS** — FE dev server :3000/:4001/:4002 gọi thẳng `localhost:3001/8081/8082/8090` → mở CORS cho đúng các origin dev, không mở đại `*` kèm credentials.
|
|
8
|
+
|
|
9
|
+
## Cụ thể
|
|
10
|
+
|
|
11
|
+
| Service | Mechanism | Scope |
|
|
12
|
+
|---------|-----------|-------|
|
|
13
|
+
| node-svc | `@fastify/cors` | origin = `CORS_DEV_ORIGIN` (env, ví dụ `http://localhost:3000,http://localhost:4001,http://localhost:4002`); methods GET/POST/PATCH/DELETE; headers `Authorization, Content-Type, X-Request-Id` |
|
|
14
|
+
| spring-svc | `WebMvcConfigurer#addCorsMappings`, bean chỉ active với profile `dev` (`@Profile("dev")`) | cùng scope ở trên, đọc `cors.dev-origins` từ env |
|
|
15
|
+
| go-svc | middleware `github.com/rs/cors` | cùng scope, đọc `CORS_DEV_ORIGIN` |
|
|
16
|
+
| auth-svc | `@fastify/cors` | mở cho dev origin (FE dev gọi trực tiếp :8090) |
|
|
17
|
+
|
|
18
|
+
## Quy tắc
|
|
19
|
+
|
|
20
|
+
1. Origin KHÔNG hardcode — đọc `CORS_DEV_ORIGIN` (danh sách phân tách phẩy).
|
|
21
|
+
2. Không bao giờ `origin: *` kết hợp `credentials: true`.
|
|
22
|
+
3. Prod profile (compose): CORS middleware vẫn mount nhưng origin list rỗng → không header ACAO nào được emit (deny-by-default).
|
|
23
|
+
4. Native FE dev mà thiếu CORS → lỗi network ngay trong console — check env trước khi debug service.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 08 — Gateway routing table + MF remote registry
|
|
2
|
+
|
|
3
|
+
## Routing table (nginx — `platform/gateway/nginx/nginx.conf`)
|
|
4
|
+
|
|
5
|
+
| Path | Upstream | Auth presence check | Ghi chú |
|
|
6
|
+
|------|----------|--------------------|---------|
|
|
7
|
+
| `/api/tasks/*` | `node-svc:3001` | ✓ thiếu `Authorization` → 401 | pass-through, KHÔNG rewrite — service mount `/api/tasks` prefix |
|
|
8
|
+
| `/api/users/*` | `spring-svc:8081` | ✓ 401 | |
|
|
9
|
+
| `/api/activity/*` | `go-svc:8082` | ✓ 401 | |
|
|
10
|
+
| `/api/auth/*` | `auth-svc:8090` | ✗ mở | entry login + register + refresh (auth.yaml v2) |
|
|
11
|
+
| `/` | `shell:3000` | ✗ | MF host (SF-5) — 502 đến khi shell tồn tại |
|
|
12
|
+
| `/remotes/<name>/*` | remote `<name>` | ✗ | remote static (SF-6) — 502 đến khi tồn tại |
|
|
13
|
+
|
|
14
|
+
Quy tắc kỹ thuật:
|
|
15
|
+
1. **Pass-through**: `proxy_pass` không có URI part → original path giữ nguyên. OpenAPI `servers.url` = `/api/<svc>` khớp chính xác.
|
|
16
|
+
2. **Lazy DNS**: mọi upstream set qua biến + `resolver 127.0.0.11` (Docker DNS) — gateway KHÔNG crash-loop khi một upstream chưa tồn tại (stage đầu chỉ có postgres + auth-svc + gateway chạy được; shell/services vào sau).
|
|
17
|
+
3. Gateway sinh `X-Request-Id` nếu client thiếu (mirror vào response) — trace xuyên service, xem [03-logging.md](03-logging.md).
|
|
18
|
+
4. Gateway chỉ làm **presence check** JWT — KHÔNG verify signature (không giữ secret). Verify thật ở từng service, xem `contracts/auth/token-contract.md` §4.
|
|
19
|
+
|
|
20
|
+
## MF remote registry
|
|
21
|
+
|
|
22
|
+
Nguồn sự thật cho FE shell (SF-5) biết load remote nào ở đâu. Env-configurable — dev trỏ dev server, prod trỏ static qua gateway.
|
|
23
|
+
|
|
24
|
+
| Remote name | Module expose | Dev URL (env `REMOTE_TASKS_URL` / `REMOTE_ACTIVITY_URL`) | Prod URL |
|
|
25
|
+
|-------------|---------------|------------------|----------|
|
|
26
|
+
| `tasks` | `./TasksPage` | `http://localhost:4001/remoteEntry.js` | `/remotes/tasks/remoteEntry.js` (relative qua gateway) |
|
|
27
|
+
| `activity` | `./ActivityPage` | `http://localhost:4002/remoteEntry.js` | `/remotes/activity/remoteEntry.js` |
|
|
28
|
+
|
|
29
|
+
Quy tắc:
|
|
30
|
+
1. Shell đọc registry từ env (`REMOTE_TASKS_URL`, `REMOTE_ACTIVITY_URL`) lúc build/bootstrap — KHÔNG hardcode URL.
|
|
31
|
+
2. Remote name (`tasks`, `activity`) là khoá module federation — đổi tên = breaking, phải đồng bộ shell + remote + file này.
|
|
32
|
+
3. Shared singletons (react, react-dom): quản qua pnpm catalog — chi tiết trong `app/shared/package.json` (trường `mfToolkit.pinned`, kết quả spike SF-1).
|
|
33
|
+
4. **Singleton remote khai `requiredVersion: false` tường minh (SF-7 sync — học từ SF-6):** giá trị `catalog:` là literal pnpm-workspace, bundler MF không hiểu — `@module-federation/enhanced` infer thành `requiredVersion: "catalog:"` sai và match fail lúc runtime. Remote dùng shared singleton từ host phải khai `requiredVersion: false` trong share config (precedent: `app/remotes/{tasks,activity}/rspack.config.js`).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# 09 — Async messaging qua Kafka (outbox + consumer + DLQ)
|
|
2
|
+
|
|
3
|
+
Hợp đồng envelope/payload/topics là nguồn sự thật riêng:
|
|
4
|
+
[`contracts/events/task-events.md`](../../contracts/events/task-events.md) — file này
|
|
5
|
+
chỉ quy tắc VẬN HÀNH. Quyết định kiến trúc: [ADR-0008](../../docs/adr/0008-kafka-outbox-saga.md).
|
|
6
|
+
|
|
7
|
+
## Quy tắc
|
|
8
|
+
|
|
9
|
+
1. **Lazy-connect**: Kafka KHÔNG vào `/readyz` và KHÔNG có service nào
|
|
10
|
+
`depends_on: kafka` — health-gated chain 9 service không bị kafka chặn. Service
|
|
11
|
+
boot được cả khi broker chưa lên: producer/consumer connect retry backoff lúc
|
|
12
|
+
boot, connect fail = log warn, KHÔNG crash, KHÔNG fallback im lặng sang chế độ
|
|
13
|
+
bỏ-event.
|
|
14
|
+
2. **Producer qua transactional outbox**: mutation DB và INSERT outbox (envelope
|
|
15
|
+
`id` = UUIDv4 sinh trong repo) trong CÙNG 1 tx. Relay worker poll (~500ms)
|
|
16
|
+
publish rồi mark `published_at`. KHÔNG publish broker trực tiếp trong request
|
|
17
|
+
path — publish fail giữa chừng = mất event (đúng điều ADR-0006 đã loại).
|
|
18
|
+
3. **Envelope bắt buộc**: mọi message JSON đúng envelope `{schemaVersion, id, type,
|
|
19
|
+
occurredAt, payload}` (task-events.md). `schemaVersion` integer cố định `1`;
|
|
20
|
+
payload chỉ thêm field không breaking — consumer BỎ QUA field lạ, không chết.
|
|
21
|
+
4. **Consumer idempotent**: at-least-once là mặc định — dedupe bằng envelope `id`
|
|
22
|
+
(`ON CONFLICT DO NOTHING`), KHÔNG dùng taskId (re-assign = nhiều event hợp lệ
|
|
23
|
+
cùng taskId).
|
|
24
|
+
5. **Manual commit sau DB tx**: offset commit CHỈ sau khi DB tx commit thành công.
|
|
25
|
+
Commit trước tx = crash mất event; at-least-once + idempotency lo phần còn lại.
|
|
26
|
+
6. **Filter-by-type theo group**: mọi consumer khai group của mình ở
|
|
27
|
+
task-events.md và lọc theo `type` — group mới phải thêm vào bảng group trước.
|
|
28
|
+
7. **Retry ×3 in-memory rồi DLQ**: lỗi xử lý retry backoff ×3 in-memory; hết lượt
|
|
29
|
+
→ message gốc + metadata lỗi vào `task-events.dlq`, KHÔNG requeue vô hạn,
|
|
30
|
+
KHÔNG block partition. Copy production: thêm alert + replay tool cho DLQ.
|
|
31
|
+
8. **Kafka compose-internal**: PLAINTEXT, 9092 không expose host, single-node
|
|
32
|
+
KRaft heap 512m. Copy production: SASL/SSL + multi-broker (viền thay đổi nằm
|
|
33
|
+
ở entry kafka compose + client config).
|
|
34
|
+
9. **Không secret trong payload** — envelope đi qua broker PLAINTEXT; payload là
|
|
35
|
+
dữ liệu demo (users fixture, task title).
|
|
36
|
+
|
|
37
|
+
## Env liên quan (chi tiết trong `.env.example`)
|
|
38
|
+
|
|
39
|
+
| Biến | Dùng bởi |
|
|
40
|
+
|------|----------|
|
|
41
|
+
| `KAFKA_BROKERS` | node-svc (relay + compensation consumer), go-svc (consumer) |
|
|
42
|
+
| `SVC_ACTIVITY_PASSWORD` | go-svc — login fixture user `svc-activity` lấy service token (khớp `AUTH_MOCK_DEV_PASSWORD`) |
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Platform Conventions — index
|
|
2
|
+
|
|
3
|
+
SF-1 (FI-64) sở hữu. **Mọi service/repo-con trong boilerplate PHẢI theo các conventions này** — SF-2..7 đọc trước khi code. Không đúng convention = review fail.
|
|
4
|
+
|
|
5
|
+
| File | Nội dung |
|
|
6
|
+
|------|----------|
|
|
7
|
+
| [01-dockerfile-pattern.md](01-dockerfile-pattern.md) | Dockerfile multi-stage pattern chuẩn cho cả 3 stack |
|
|
8
|
+
| [02-healthcheck.md](02-healthcheck.md) | `/healthz` (liveness) + `/readyz` (readiness) — contract cho compose + CI boot-smoke |
|
|
9
|
+
| [03-logging.md](03-logging.md) | JSON log shape chung |
|
|
10
|
+
| [04-error-envelope.md](04-error-envelope.md) | Error envelope chung (mirror trong 4 OpenAPI specs) |
|
|
11
|
+
| [05-ports.md](05-ports.md) | PORT TABLE — nguồn sự thật duy nhất về port |
|
|
12
|
+
| [06-configuration.md](06-configuration.md) | Config qua env-var — quy tắc + .env workflow |
|
|
13
|
+
| [07-cors.md](07-cors.md) | CORS dev-profile rule |
|
|
14
|
+
| [08-gateway-and-remotes.md](08-gateway-and-remotes.md) | Gateway routing table + MF remote registry |
|
|
15
|
+
| [09-async-messaging.md](09-async-messaging.md) | Kafka lazy-connect + outbox + consumer idempotent + retry/DLQ (hợp đồng envelope: contracts/events/task-events.md) |
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# Boilerplate Microservice + Micro-frontend — compose
|
|
3
|
+
#
|
|
4
|
+
# ⚠️ Shared file — sửa QUA cơ chế gap-answer soạn trước + coordinator APPROVED
|
|
5
|
+
# (pattern story auth-real VU-59), KHÔNG tự sửa giữa story.
|
|
6
|
+
#
|
|
7
|
+
# Lịch sử sở hữu (người sửa cuối = auth-real SF-5 VU-64):
|
|
8
|
+
# FI-64 SF-1: khung 9 services health-gated + postgres init + auth-mock
|
|
9
|
+
# + 2 entry remotes (FE điền impl vào khung).
|
|
10
|
+
# FI-75 SF-7: health-gated depends_on (healthcheck /readyz node-svc +
|
|
11
|
+
# spring-svc; gateway gate auth/node/spring service_healthy + go-svc
|
|
12
|
+
# service_started — distroless không có shell/wget, conventions/02 rule 3;
|
|
13
|
+
# gateway KHÔNG có healthcheck).
|
|
14
|
+
# FI-77 SF-1: + entry kafka (apache/kafka KRaft single-node, KHÔNG zookeeper;
|
|
15
|
+
# heap 512m cho CI 7GB; healthcheck full-path /opt/kafka/bin/... — image
|
|
16
|
+
# không có script trên PATH; KHÔNG expose 9092 ra host; KHÔNG service nào
|
|
17
|
+
# depends_on kafka — lazy-connect, conventions/09).
|
|
18
|
+
# VU-59 SF-5: decommission auth-mock → entry auth-svc (services/auth-svc,
|
|
19
|
+
# auth thật — register/refresh/RBAC; healthcheck /readyz kiểm DB thật;
|
|
20
|
+
# mount users.json; role auth_svc + schema auth; go-svc AUTH_MOCK_URL
|
|
21
|
+
# đổi VALUE giữ KEY — gap-answer epic VU-59 mục ①②④⑤⑥⑦, coordinator
|
|
22
|
+
# APPROVED).
|
|
23
|
+
# 2026-10-23: go-svc env roles đã đúng ở entry (đã fix từ trước) — xoá services/go-svc/ci.compose.override.yml (redundant) — coordinator duyệt.
|
|
24
|
+
# ============================================================================
|
|
25
|
+
|
|
26
|
+
name: __STACK_NAME__
|
|
27
|
+
|
|
28
|
+
services:
|
|
29
|
+
postgres:
|
|
30
|
+
image: postgres:16-alpine
|
|
31
|
+
environment:
|
|
32
|
+
POSTGRES_USER: ${POSTGRES_USER:?set in .env}
|
|
33
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set in .env}
|
|
34
|
+
POSTGRES_DB: ${POSTGRES_DB:?set in .env}
|
|
35
|
+
# password cho per-service roles — init script (01-init.sh) dùng
|
|
36
|
+
NODE_SVC_DB_PASSWORD: ${NODE_SVC_DB_PASSWORD:?set in .env}
|
|
37
|
+
SPRING_SVC_DB_PASSWORD: ${SPRING_SVC_DB_PASSWORD:?set in .env}
|
|
38
|
+
GO_SVC_DB_PASSWORD: ${GO_SVC_DB_PASSWORD:?set in .env}
|
|
39
|
+
GO_READONLY_DB_PASSWORD: ${GO_READONLY_DB_PASSWORD:?set in .env}
|
|
40
|
+
AUTH_SVC_DB_PASSWORD: ${AUTH_SVC_DB_PASSWORD:?set in .env}
|
|
41
|
+
volumes:
|
|
42
|
+
- ./postgres/init:/docker-entrypoint-initdb.d:ro
|
|
43
|
+
- pgdata:/var/lib/postgresql/data
|
|
44
|
+
ports:
|
|
45
|
+
- "${POSTGRES_PORT:-5432}:5432"
|
|
46
|
+
healthcheck:
|
|
47
|
+
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
|
48
|
+
interval: 5s
|
|
49
|
+
timeout: 3s
|
|
50
|
+
retries: 12
|
|
51
|
+
|
|
52
|
+
kafka:
|
|
53
|
+
# Apache Kafka KRaft single-node (KHÔNG zookeeper) — ADR-0008.
|
|
54
|
+
# Compose-internal ONLY: không có `ports` = KHÔNG expose 9092 ra host.
|
|
55
|
+
# KHÔNG service nào depends_on kafka — connect lazy + retry lúc boot
|
|
56
|
+
# (conventions/09); healthcheck chỉ để `docker compose ps` quan sát.
|
|
57
|
+
image: apache/kafka:3.9.0
|
|
58
|
+
environment:
|
|
59
|
+
KAFKA_NODE_ID: 1
|
|
60
|
+
KAFKA_PROCESS_ROLES: broker,controller
|
|
61
|
+
KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
|
|
62
|
+
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 # hostname service trong mạng compose
|
|
63
|
+
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
|
|
64
|
+
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
|
|
65
|
+
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
|
|
66
|
+
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
|
|
67
|
+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 # single-node
|
|
68
|
+
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
|
|
69
|
+
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
|
|
70
|
+
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 # demo — consumer nhận event ngay
|
|
71
|
+
KAFKA_HEAP_OPTS: -Xmx512m -Xms256m # CI runner 7GB — heap nhỏ có chủ đích
|
|
72
|
+
healthcheck:
|
|
73
|
+
# full path BẮT BUỘC — image apache/kafka không đặt script kafka-* trên PATH
|
|
74
|
+
test: ["CMD-SHELL", "/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092"]
|
|
75
|
+
interval: 10s
|
|
76
|
+
timeout: 10s
|
|
77
|
+
retries: 12
|
|
78
|
+
start_period: 20s
|
|
79
|
+
|
|
80
|
+
auth-svc:
|
|
81
|
+
build: ../services/auth-svc # auth thật (VU-59) thay auth-mock — cùng surface :8090 /api/auth/*
|
|
82
|
+
environment:
|
|
83
|
+
PORT: 8090 # container port CỐ ĐỊNH (conventions/05) — ${AUTH_PORT} chỉ đổi side host
|
|
84
|
+
DATABASE_URL: postgres://auth_svc:${AUTH_SVC_DB_PASSWORD:?set in .env}@postgres:5432/${POSTGRES_DB:?set in .env}
|
|
85
|
+
JWT_SECRET: ${JWT_SECRET:?set in .env}
|
|
86
|
+
ACCESS_TOKEN_TTL: ${ACCESS_TOKEN_TTL:-30m} # token-contract.md §1 (30m — cũ 8h của mock)
|
|
87
|
+
# decision #10: default demo-password KHÔNG đổi — e2e + svc-activity + seed cùng một nguồn
|
|
88
|
+
AUTH_DEV_PASSWORD: ${AUTH_DEV_PASSWORD:-demo-password}
|
|
89
|
+
# fixture mount trực tiếp từ contracts/ — sửa fixture không cần rebuild image
|
|
90
|
+
# (seed idempotent ON CONFLICT (id) DO NOTHING — token-contract.md §5)
|
|
91
|
+
USERS_FIXTURE_PATH: /app/users.json
|
|
92
|
+
CORS_DEV_ORIGIN: ${CORS_DEV_ORIGIN:-}
|
|
93
|
+
LOG_LEVEL: ${LOG_LEVEL:-info}
|
|
94
|
+
volumes:
|
|
95
|
+
- ../contracts/auth/users.json:/app/users.json:ro
|
|
96
|
+
ports:
|
|
97
|
+
- "${AUTH_PORT:-8090}:8090" # host-side port — truy cập từ máy dev
|
|
98
|
+
depends_on:
|
|
99
|
+
postgres:
|
|
100
|
+
condition: service_healthy
|
|
101
|
+
healthcheck:
|
|
102
|
+
# probe TRONG container — hardcode 8090 (conventions/05); ${AUTH_PORT} chỉ host-side.
|
|
103
|
+
# /readyz (KHÔNG /healthz như auth-mock cũ) — kiểm DB thật: healthy = đã
|
|
104
|
+
# migrate schema auth + seed fixture xong → gateway chỉ nhận traffic khi service thật sự sẵn sàng.
|
|
105
|
+
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8090/readyz"]
|
|
106
|
+
interval: 5s
|
|
107
|
+
timeout: 3s
|
|
108
|
+
retries: 12
|
|
109
|
+
start_period: 20s # chờ migration + seed fixture lúc boot
|
|
110
|
+
|
|
111
|
+
gateway:
|
|
112
|
+
image: nginx:1.27-alpine
|
|
113
|
+
volumes:
|
|
114
|
+
- ./gateway/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
115
|
+
ports:
|
|
116
|
+
- "${GATEWAY_PORT:-8080}:8080"
|
|
117
|
+
depends_on:
|
|
118
|
+
auth-svc:
|
|
119
|
+
condition: service_healthy
|
|
120
|
+
node-svc:
|
|
121
|
+
condition: service_healthy
|
|
122
|
+
spring-svc:
|
|
123
|
+
condition: service_healthy
|
|
124
|
+
# go-svc: service_started — distroless không có shell/wget cho healthcheck
|
|
125
|
+
# (conventions/02 rule 3); readiness chứng minh bằng scripts/smoke/e2e.sh
|
|
126
|
+
# poll /api/activity/stats (SF-7, FI-75).
|
|
127
|
+
go-svc:
|
|
128
|
+
condition: service_started
|
|
129
|
+
# KHÔNG healthcheck cho gateway — nginx proxy thuần, không route /readyz
|
|
130
|
+
# (probe sẽ 404); wait do scripts/smoke/e2e.sh poll /api/auth/readyz đảm nhiệm.
|
|
131
|
+
|
|
132
|
+
# --- KHUNG services (SF-2/3/4 điền impl — KHÔNG sửa entry) ---
|
|
133
|
+
|
|
134
|
+
node-svc:
|
|
135
|
+
build: ../services/node-svc
|
|
136
|
+
environment:
|
|
137
|
+
PORT: 3001 # container port CỐ ĐỊNH (conventions/05)
|
|
138
|
+
DATABASE_URL: postgres://node_svc:${NODE_SVC_DB_PASSWORD:?set in .env}@postgres:5432/${POSTGRES_DB:?set in .env}
|
|
139
|
+
JWT_SECRET: ${JWT_SECRET:?set in .env}
|
|
140
|
+
SPRING_SVC_URL: http://spring-svc:8081
|
|
141
|
+
GO_SVC_URL: http://go-svc:8082
|
|
142
|
+
CORS_DEV_ORIGIN: ${CORS_DEV_ORIGIN:-}
|
|
143
|
+
LOG_LEVEL: ${LOG_LEVEL:-info}
|
|
144
|
+
# PRE-ADD (SF-1 FI-77) — outbox relay + compensation consumer (SF-2) đọc.
|
|
145
|
+
# Node KHÔNG phụ thuộc kafka lúc boot — lazy-connect (conventions/09).
|
|
146
|
+
KAFKA_BROKERS: ${KAFKA_BROKERS:-kafka:9092}
|
|
147
|
+
ports:
|
|
148
|
+
- "${NODE_SVC_PORT:-3001}:3001" # host-side
|
|
149
|
+
depends_on:
|
|
150
|
+
postgres:
|
|
151
|
+
condition: service_healthy
|
|
152
|
+
spring-svc:
|
|
153
|
+
condition: service_healthy # readyz node kiểm spring reachable lúc boot — gate ở đây (SF-7)
|
|
154
|
+
healthcheck: # SF-7: health-gated /readyz (conventions/02) — node:22-alpine có busybox wget
|
|
155
|
+
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3001/readyz"]
|
|
156
|
+
interval: 5s
|
|
157
|
+
timeout: 3s
|
|
158
|
+
retries: 12
|
|
159
|
+
start_period: 20s # chờ migration + spring reachability check lúc boot
|
|
160
|
+
|
|
161
|
+
spring-svc:
|
|
162
|
+
build: ../services/spring-svc
|
|
163
|
+
environment:
|
|
164
|
+
SERVER_PORT: 8081 # container port CỐ ĐỊNH (conventions/05)
|
|
165
|
+
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB:?set in .env}
|
|
166
|
+
SPRING_DATASOURCE_USERNAME: spring_svc
|
|
167
|
+
SPRING_DATASOURCE_PASSWORD: ${SPRING_SVC_DB_PASSWORD:?set in .env}
|
|
168
|
+
JWT_SECRET: ${JWT_SECRET:?set in .env}
|
|
169
|
+
USERS_FIXTURE_PATH: /app/contracts/auth/users.json
|
|
170
|
+
CORS_DEV_ORIGIN: ${CORS_DEV_ORIGIN:-}
|
|
171
|
+
LOG_LEVEL: ${LOG_LEVEL:-info}
|
|
172
|
+
volumes:
|
|
173
|
+
- ../contracts/auth/users.json:/app/contracts/auth/users.json:ro
|
|
174
|
+
ports:
|
|
175
|
+
- "${SPRING_SVC_PORT:-8081}:8081" # host-side
|
|
176
|
+
depends_on:
|
|
177
|
+
postgres:
|
|
178
|
+
condition: service_healthy
|
|
179
|
+
healthcheck: # SF-7: health-gated /readyz (conventions/02) — temurin alpine có busybox wget
|
|
180
|
+
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8081/readyz"]
|
|
181
|
+
interval: 5s
|
|
182
|
+
timeout: 3s
|
|
183
|
+
retries: 12
|
|
184
|
+
start_period: 30s # chờ Flyway migration + JVM boot
|
|
185
|
+
|
|
186
|
+
go-svc:
|
|
187
|
+
build: ../services/go-svc
|
|
188
|
+
environment:
|
|
189
|
+
PORT: 8082 # container port CỐ ĐỊNH (conventions/05)
|
|
190
|
+
DATABASE_URL: postgres://go_svc:${GO_SVC_DB_PASSWORD:?set in .env}@postgres:5432/${POSTGRES_DB:?set in .env}
|
|
191
|
+
DATABASE_READONLY_URL: postgres://go_readonly:${GO_READONLY_DB_PASSWORD:?set in .env}@postgres:5432/${POSTGRES_DB:?set in .env}
|
|
192
|
+
JWT_SECRET: ${JWT_SECRET:?set in .env}
|
|
193
|
+
SPRING_SVC_URL: http://spring-svc:8081
|
|
194
|
+
CORS_DEV_ORIGIN: ${CORS_DEV_ORIGIN:-}
|
|
195
|
+
LOG_LEVEL: ${LOG_LEVEL:-info}
|
|
196
|
+
# PRE-ADD (SF-1 FI-77) — task consumer + saga (SF-3) đọc:
|
|
197
|
+
KAFKA_BROKERS: ${KAFKA_BROKERS:-kafka:9092}
|
|
198
|
+
# service-token login fixture user svc-activity (resolver enrich userName;
|
|
199
|
+
# login backoff + lazy re-login — conventions/09). Giá trị .env phải khớp
|
|
200
|
+
# AUTH_DEV_PASSWORD (auth-svc so password hash của seeded users).
|
|
201
|
+
# KEY giữ AUTH_MOCK_URL (go-svc đọc theo tên env này — gap-answer ④);
|
|
202
|
+
# VALUE trỏ auth-svc sau decommission (đổi KEY = follow-up cụm iss-rename).
|
|
203
|
+
AUTH_MOCK_URL: http://auth-svc:8090
|
|
204
|
+
SVC_ACTIVITY_PASSWORD: ${SVC_ACTIVITY_PASSWORD:?set in .env}
|
|
205
|
+
ports:
|
|
206
|
+
- "${GO_SVC_PORT:-8082}:8082" # host-side
|
|
207
|
+
depends_on:
|
|
208
|
+
postgres:
|
|
209
|
+
condition: service_healthy
|
|
210
|
+
|
|
211
|
+
# --- FE entries: shell (SF-5 thêm — GAP-ANSWER coordinator trên epic FI-62 2026-10-12:
|
|
212
|
+
# "BẠN tự thêm theo port table, coordinator duyệt ở review"). remote-tasks /
|
|
213
|
+
# remote-activity do SF-6 thêm. ---
|
|
214
|
+
shell:
|
|
215
|
+
build:
|
|
216
|
+
context: .. # repo root — Dockerfile cần app/shared + workspace lockfile
|
|
217
|
+
dockerfile: app/shell/Dockerfile
|
|
218
|
+
ports:
|
|
219
|
+
- "${SHELL_PORT:-3000}:3000" # container port cố định 3000 (conventions/05)
|
|
220
|
+
healthcheck:
|
|
221
|
+
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/"]
|
|
222
|
+
interval: 5s
|
|
223
|
+
timeout: 3s
|
|
224
|
+
retries: 12
|
|
225
|
+
|
|
226
|
+
# --- remote-tasks / remote-activity: SF-6 (FI-74) điền impl vào khung pre-seed ---
|
|
227
|
+
# (gap-answer được BRIEF SF-6 ủy quyền 2026-10-12: "BẠN tự thêm 2 entry remotes — build
|
|
228
|
+
# ../app/remotes/*, port theo port table, healthcheck static; coordinator duyệt ở review".
|
|
229
|
+
# SF-6 KHÔNG sửa phần khác của file này.)
|
|
230
|
+
remote-tasks:
|
|
231
|
+
build:
|
|
232
|
+
context: .. # repo root — Dockerfile cần app/shared + workspace lockfile
|
|
233
|
+
dockerfile: app/remotes/tasks/Dockerfile
|
|
234
|
+
ports:
|
|
235
|
+
- "${REMOTE_TASKS_PORT:-4001}:4001" # container port cố định 4001 (conventions/05)
|
|
236
|
+
healthcheck:
|
|
237
|
+
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4001/remoteEntry.js"]
|
|
238
|
+
interval: 5s
|
|
239
|
+
timeout: 3s
|
|
240
|
+
retries: 12
|
|
241
|
+
|
|
242
|
+
remote-activity:
|
|
243
|
+
build:
|
|
244
|
+
context: .. # repo root — Dockerfile cần app/shared + workspace lockfile
|
|
245
|
+
dockerfile: app/remotes/activity/Dockerfile
|
|
246
|
+
ports:
|
|
247
|
+
- "${REMOTE_ACTIVITY_PORT:-4002}:4002" # container port cố định 4002 (conventions/05)
|
|
248
|
+
healthcheck:
|
|
249
|
+
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4002/remoteEntry.js"]
|
|
250
|
+
interval: 5s
|
|
251
|
+
timeout: 3s
|
|
252
|
+
retries: 12
|
|
253
|
+
|
|
254
|
+
volumes:
|
|
255
|
+
pgdata:
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# nginx gateway — routing theo platform/conventions/08-gateway-and-remotes.md
|
|
3
|
+
# SF-1 sở hữu (FI-64). Services chỉ đọc, KHÔNG sửa.
|
|
4
|
+
#
|
|
5
|
+
# Design decisions:
|
|
6
|
+
# - Pass-through: proxy_pass KHÔNG có URI part → path giữ nguyên; service mount
|
|
7
|
+
# đúng prefix /api/<svc> (khớp servers.url trong contracts/openapi/*.yaml).
|
|
8
|
+
# Ngoại lệ /remotes/<name>/*: strip prefix trước khi forward (static remote
|
|
9
|
+
# serve ở root — xem conventions/08).
|
|
10
|
+
# - Lazy DNS: upstream đặt qua biến + resolver 127.0.0.11 (Docker DNS) —
|
|
11
|
+
# gateway KHÔNG crash-loop khi upstream chưa tồn tại (stage đầu chỉ có
|
|
12
|
+
# postgres/auth/gateway sống; shell + 3 services vào sau).
|
|
13
|
+
# - JWT presence check CHỈ trên /api/tasks|users|activity — signature verify
|
|
14
|
+
# là việc của service (contracts/auth/token-contract.md §4).
|
|
15
|
+
# ============================================================================
|
|
16
|
+
|
|
17
|
+
worker_processes auto;
|
|
18
|
+
error_log /dev/stderr warn;
|
|
19
|
+
pid /tmp/nginx.pid;
|
|
20
|
+
|
|
21
|
+
events {
|
|
22
|
+
worker_connections 1024;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
http {
|
|
26
|
+
include /etc/nginx/mime.types;
|
|
27
|
+
default_type application/octet-stream;
|
|
28
|
+
sendfile on;
|
|
29
|
+
client_max_body_size 2m;
|
|
30
|
+
|
|
31
|
+
# Docker embedded DNS — resolve upstream lúc request (không lúc config load)
|
|
32
|
+
resolver 127.0.0.11 valid=10s ipv6=off;
|
|
33
|
+
|
|
34
|
+
# Request id: echo của client hoặc sinh mới ($request_id builtin) — conventions/03
|
|
35
|
+
map $http_x_request_id $req_id {
|
|
36
|
+
"" $request_id;
|
|
37
|
+
default $http_x_request_id;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Remote registry (prod mode): path /remotes/<name>/* → container remote.
|
|
41
|
+
# default rơi về shell — remote name lạ sẽ nhận 404 từ shell thay vì 500 gateway.
|
|
42
|
+
map $uri $remote_up {
|
|
43
|
+
~^/remotes/tasks/ "http://remote-tasks:4001";
|
|
44
|
+
~^/remotes/activity/ "http://remote-activity:4002";
|
|
45
|
+
default "http://shell:3000";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
server {
|
|
49
|
+
listen 8080;
|
|
50
|
+
server_name _;
|
|
51
|
+
|
|
52
|
+
# ---------- API: tasks → node-svc (presence check 401) ----------
|
|
53
|
+
location = /api/tasks {
|
|
54
|
+
if ($http_authorization = "") { return 401; }
|
|
55
|
+
set $up http://node-svc:3001;
|
|
56
|
+
proxy_pass $up;
|
|
57
|
+
proxy_set_header Host $host;
|
|
58
|
+
proxy_set_header X-Request-Id $req_id;
|
|
59
|
+
}
|
|
60
|
+
location /api/tasks/ {
|
|
61
|
+
if ($http_authorization = "") { return 401; }
|
|
62
|
+
set $up http://node-svc:3001;
|
|
63
|
+
proxy_pass $up;
|
|
64
|
+
proxy_set_header Host $host;
|
|
65
|
+
proxy_set_header X-Request-Id $req_id;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# ---------- API: users → spring-svc ----------
|
|
69
|
+
location = /api/users {
|
|
70
|
+
if ($http_authorization = "") { return 401; }
|
|
71
|
+
set $up http://spring-svc:8081;
|
|
72
|
+
proxy_pass $up;
|
|
73
|
+
proxy_set_header Host $host;
|
|
74
|
+
proxy_set_header X-Request-Id $req_id;
|
|
75
|
+
}
|
|
76
|
+
location /api/users/ {
|
|
77
|
+
if ($http_authorization = "") { return 401; }
|
|
78
|
+
set $up http://spring-svc:8081;
|
|
79
|
+
proxy_pass $up;
|
|
80
|
+
proxy_set_header Host $host;
|
|
81
|
+
proxy_set_header X-Request-Id $req_id;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# ---------- API: activity → go-svc ----------
|
|
85
|
+
location = /api/activity {
|
|
86
|
+
if ($http_authorization = "") { return 401; }
|
|
87
|
+
set $up http://go-svc:8082;
|
|
88
|
+
proxy_pass $up;
|
|
89
|
+
proxy_set_header Host $host;
|
|
90
|
+
proxy_set_header X-Request-Id $req_id;
|
|
91
|
+
}
|
|
92
|
+
location /api/activity/ {
|
|
93
|
+
if ($http_authorization = "") { return 401; }
|
|
94
|
+
set $up http://go-svc:8082;
|
|
95
|
+
proxy_pass $up;
|
|
96
|
+
proxy_set_header Host $host;
|
|
97
|
+
proxy_set_header X-Request-Id $req_id;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# ---------- API: auth → auth-svc (MỞ — entry login + register + refresh) ----------
|
|
101
|
+
location /api/auth {
|
|
102
|
+
set $up http://auth-svc:8090;
|
|
103
|
+
proxy_pass $up;
|
|
104
|
+
proxy_set_header Host $host;
|
|
105
|
+
proxy_set_header X-Request-Id $req_id;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# ---------- 401 body theo error envelope chung (conventions/04) ----------
|
|
109
|
+
error_page 401 = @unauthorized;
|
|
110
|
+
location @unauthorized {
|
|
111
|
+
default_type application/json;
|
|
112
|
+
add_header X-Request-Id $req_id always;
|
|
113
|
+
return 401 '{"error":{"code":"UNAUTHORIZED","message":"Missing Authorization header","requestId":null,"details":null}}';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# ---------- FE: remote static (SF-6) — strip prefix, forward root ----------
|
|
117
|
+
location /remotes/ {
|
|
118
|
+
# map $uri là LAZY-evaluated: phải nạp $remote_up vào $up TRƯỚC khi
|
|
119
|
+
# rewrite strip prefix. Tính map sau rewrite thì $uri đã thành
|
|
120
|
+
# "/remoteEntry.js" → mọi remote rơi default shell → nhận index.html
|
|
121
|
+
# của shell thay vì JS (MF load fail — bug gặp fresh-clone 2026-10-13).
|
|
122
|
+
set $up $remote_up;
|
|
123
|
+
rewrite ^/remotes/[a-z-]+(/.*)?$ $1 break;
|
|
124
|
+
proxy_pass $up;
|
|
125
|
+
proxy_set_header Host $host;
|
|
126
|
+
proxy_set_header X-Request-Id $req_id;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# ---------- FE: shell MF host (SF-5) — 502 đến khi shell tồn tại ----------
|
|
130
|
+
location / {
|
|
131
|
+
set $up http://shell:3000;
|
|
132
|
+
proxy_pass $up;
|
|
133
|
+
proxy_set_header Host $host;
|
|
134
|
+
proxy_set_header X-Request-Id $req_id;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# Postgres init — chạy MỘT LẦN trên volume mới (docker-entrypoint-initdb.d).
|
|
4
|
+
# Tạo: 4 schemas (tasks/users/activity/auth) + 1 LOGIN role per service + 1
|
|
5
|
+
# readonly role cho go-svc đọc schema `tasks`.
|
|
6
|
+
#
|
|
7
|
+
# ĐIỂM MÚT: ALTER DEFAULT PRIVILEGES FOR ROLE node_svc — grant SELECT hiệu lực
|
|
8
|
+
# cho BẢNG SINH SAU bởi migration của node-svc (SF-2). Không có default
|
|
9
|
+
# privileges thì go_readonly không thấy bảng mới → stats 503.
|
|
10
|
+
# ============================================================================
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<EOSQL
|
|
14
|
+
-- Schemas — mỗi service 1 schema (multi-repo convention trong 1 DB)
|
|
15
|
+
CREATE SCHEMA IF NOT EXISTS tasks;
|
|
16
|
+
CREATE SCHEMA IF NOT EXISTS users;
|
|
17
|
+
CREATE SCHEMA IF NOT EXISTS activity;
|
|
18
|
+
CREATE SCHEMA IF NOT EXISTS auth;
|
|
19
|
+
|
|
20
|
+
-- LOGIN role per service — mỗi service chỉ đụng schema của mình
|
|
21
|
+
-- Ràng buộc (P2 security-audit SF-5): password KHÔNG chứa dấu nháy đơn (')
|
|
22
|
+
-- — bash interpolate rồi bọc single-quote trong SQL; giá trị sai cú pháp làm
|
|
23
|
+
-- init fail-closed (ON_ERROR_STOP) chứ không bypass. Upgrade path: psql -v
|
|
24
|
+
-- binding (:'var') cho cả 5 role — follow-up, không phải instance mới alone.
|
|
25
|
+
CREATE ROLE node_svc LOGIN PASSWORD '${NODE_SVC_DB_PASSWORD}';
|
|
26
|
+
CREATE ROLE spring_svc LOGIN PASSWORD '${SPRING_SVC_DB_PASSWORD}';
|
|
27
|
+
CREATE ROLE go_svc LOGIN PASSWORD '${GO_SVC_DB_PASSWORD}';
|
|
28
|
+
CREATE ROLE auth_svc LOGIN PASSWORD '${AUTH_SVC_DB_PASSWORD}';
|
|
29
|
+
|
|
30
|
+
-- readonly role — go-svc đọc stats từ schema tasks (canonical DDL của SF-1)
|
|
31
|
+
CREATE ROLE go_readonly LOGIN PASSWORD '${GO_READONLY_DB_PASSWORD}';
|
|
32
|
+
|
|
33
|
+
-- Owners + quyền schema
|
|
34
|
+
GRANT USAGE, CREATE ON SCHEMA tasks TO node_svc;
|
|
35
|
+
GRANT USAGE, CREATE ON SCHEMA users TO spring_svc;
|
|
36
|
+
GRANT USAGE, CREATE ON SCHEMA activity TO go_svc;
|
|
37
|
+
GRANT USAGE, CREATE ON SCHEMA auth TO auth_svc;
|
|
38
|
+
ALTER ROLE node_svc SET search_path = tasks;
|
|
39
|
+
ALTER ROLE spring_svc SET search_path = users;
|
|
40
|
+
ALTER ROLE go_svc SET search_path = activity;
|
|
41
|
+
ALTER ROLE auth_svc SET search_path = auth;
|
|
42
|
+
|
|
43
|
+
-- Readonly read path
|
|
44
|
+
GRANT USAGE ON SCHEMA tasks TO go_readonly;
|
|
45
|
+
|
|
46
|
+
-- ⚠️ Default privileges: grant áp dụng cho bảng tạo SAU này bởi owner role.
|
|
47
|
+
-- (FOR ROLE node_svc = bảng do migration node-svc tạo ra.)
|
|
48
|
+
ALTER DEFAULT PRIVILEGES FOR ROLE node_svc IN SCHEMA tasks
|
|
49
|
+
GRANT SELECT ON TABLES TO go_readonly;
|
|
50
|
+
|
|
51
|
+
-- go-svc đọc display fields từ users schema? KHÔNG — userName resolve qua
|
|
52
|
+
-- spring-svc (contract activity.yaml), go_readonly CHỈ được schema tasks.
|
|
53
|
+
EOSQL
|
|
54
|
+
|
|
55
|
+
echo "[init] schemas + roles + default privileges created OK"
|