create-fullstack-scaffold 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 +154 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +439 -0
- package/dist/cli/index.js.map +1 -0
- package/package.json +171 -0
- package/template/.agents/skills/writing-hookify-rules/SKILL.md +408 -0
- package/template/.ai-context.md +368 -0
- package/template/.claude/hookify.block-dangerous-commands.local.md +41 -0
- package/template/.claude/hookify.check-api-types.local.md +111 -0
- package/template/.claude/hookify.check-duplicate-types.local.md +287 -0
- package/template/.claude/hookify.check-test-assertions.local.md +93 -0
- package/template/.claude/hookify.remind-add-tests.local.md +209 -0
- package/template/.claude/hookify.remind-db-migration.local.md +58 -0
- package/template/.claude/hookify.remind-run-tests.local.md +52 -0
- package/template/.claude/hookify.warn-any-type.local.md +203 -0
- package/template/.claude/hookify.warn-console-log.local.md +73 -0
- package/template/.claude/rules/00-project-config.md +147 -0
- package/template/.claude/rules/01-file-types.md +127 -0
- package/template/.claude/rules/02-git-workflow.md +167 -0
- package/template/.claude/rules/10-api-type-inference.md +555 -0
- package/template/.claude/rules/20-server-api.md +349 -0
- package/template/.claude/rules/21-server-entrypoint.md +257 -0
- package/template/.claude/rules/30-client-components.md +314 -0
- package/template/.claude/rules/31-client-services.md +768 -0
- package/template/.claude/rules/32-client-state-zustand.md +324 -0
- package/template/.claude/rules/33-client-app-entry.md +276 -0
- package/template/.claude/rules/34-client-admin-module.md +445 -0
- package/template/.claude/rules/35-cli-module.md +259 -0
- package/template/.claude/rules/40-admin-module.md +495 -0
- package/template/.claude/rules/40-shared-types.md +450 -0
- package/template/.claude/rules/50-websocket.md +245 -0
- package/template/.claude/rules/51-sse.md +372 -0
- package/template/.claude/rules/52-cloudflare-realtime.md +384 -0
- package/template/.claude/rules/60-testing-standards.md +245 -0
- package/template/.claude/rules/61-hono-testing.md +200 -0
- package/template/.claude/scripts/README.md +187 -0
- package/template/.claude/scripts/check-duplicate-types.ts +188 -0
- package/template/.claude/scripts/post-edit-check-incremental.sh +61 -0
- package/template/.claude/scripts/post-edit-check.sh +22 -0
- package/template/.claude/scripts/pre-tool-use-check.sh +86 -0
- package/template/.claude/scripts/test-pre-tool-use.sh +73 -0
- package/template/.claude/scripts/validate-git-changes.sh +38 -0
- package/template/.claude/settings.json +32 -0
- package/template/.claude/skills/writing-hookify-rules/SKILL.md +408 -0
- package/template/.dev-context-compact.md +54 -0
- package/template/.dev-context.md +621 -0
- package/template/.dev-guide.md +243 -0
- package/template/.env.example +60 -0
- package/template/.eslintrc.routes.json +39 -0
- package/template/.husky/_/husky.sh +27 -0
- package/template/.husky/commit-msg +4 -0
- package/template/.husky/post-commit +4 -0
- package/template/.husky/pre-commit +19 -0
- package/template/.husky/pre-push +12 -0
- package/template/.prettierignore +22 -0
- package/template/.prettierrc +8 -0
- package/template/.sessions/3/2026-03-26T05-41-09-154Z_03bb597f-3898-4a2e-8c08-5746bbe8d95e.jsonl +18 -0
- package/template/.sessions/3/2026-03-26T05-48-30-052Z_12de4774-9cb3-494c-9852-bd1e6b0003c3.jsonl +6 -0
- package/template/.vscode/extensions.json +8 -0
- package/template/.vscode/settings.json +4 -0
- package/template/.workspaces/3/hello.py +1 -0
- package/template/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/803c2e37182b913f8857edf6d8776515cef4af6d48fcb25913e457f4b14ffa97.sqlite +0 -0
- package/template/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/803c2e37182b913f8857edf6d8776515cef4af6d48fcb25913e457f4b14ffa97.sqlite-shm +0 -0
- package/template/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/803c2e37182b913f8857edf6d8776515cef4af6d48fcb25913e457f4b14ffa97.sqlite-wal +0 -0
- package/template/CLAUDE.md +296 -0
- package/template/DESIGN.md +260 -0
- package/template/DEV_CONTEXT_GUIDE.md +366 -0
- package/template/DEV_TOOLS_README.md +396 -0
- package/template/FRAMEWORK_HISTORY.md +34 -0
- package/template/PROJECT_SUMMARY.md +325 -0
- package/template/QUICKSTART.md +305 -0
- package/template/README.md +154 -0
- package/template/STRUCTURE.txt +81 -0
- package/template/admin.html +13 -0
- package/template/auth-inject.html +33 -0
- package/template/commitlint.config.js +12 -0
- package/template/docs/PERMISSION_ARCHITECTURE.md +279 -0
- package/template/docs/PERMISSION_EXAMPLES.md +230 -0
- package/template/docs/PERMISSION_SYSTEM.md +301 -0
- package/template/docs/SMART_TEST.md +171 -0
- package/template/docs/runtime-abstract.md +253 -0
- package/template/drizzle/0000_rainy_boomer.sql +101 -0
- package/template/drizzle/0001_add_todo_attachments.sql +12 -0
- package/template/drizzle/0002_chilly_magneto.sql +89 -0
- package/template/drizzle/meta/0000_snapshot.json +652 -0
- package/template/drizzle/meta/0001_snapshot.json +735 -0
- package/template/drizzle/meta/0002_snapshot.json +1198 -0
- package/template/drizzle/meta/_journal.json +27 -0
- package/template/drizzle.config.ts +13 -0
- package/template/eslint-rules/README-no-middleware-in-routes.md +154 -0
- package/template/eslint-rules/__tests__/enforce-valid-method.test.ts +251 -0
- package/template/eslint-rules/__tests__/layer-boundary.test.ts +102 -0
- package/template/eslint-rules/__tests__/module-boundary.test.ts +77 -0
- package/template/eslint-rules/__tests__/no-direct-zod-import-in-file-routes.test.ts +45 -0
- package/template/eslint-rules/__tests__/no-new-old-service-naming.test.ts +76 -0
- package/template/eslint-rules/e2e-test-location.js +153 -0
- package/template/eslint-rules/enforce-valid-method.js +217 -0
- package/template/eslint-rules/flat-routes-services.js +69 -0
- package/template/eslint-rules/framework-protect.js +186 -0
- package/template/eslint-rules/layer-boundary.js +164 -0
- package/template/eslint-rules/limit-type-complexity.js +130 -0
- package/template/eslint-rules/middleware-location.js +162 -0
- package/template/eslint-rules/module-boundary.js +125 -0
- package/template/eslint-rules/no-ambiguous-file-paths.js +64 -0
- package/template/eslint-rules/no-any-on-apiclient.js +173 -0
- package/template/eslint-rules/no-boolean-success.js +43 -0
- package/template/eslint-rules/no-deep-relative-imports.js +69 -0
- package/template/eslint-rules/no-direct-fetch.js +122 -0
- package/template/eslint-rules/no-direct-ws-sse.js +57 -0
- package/template/eslint-rules/no-direct-zod-import-in-file-routes.js +54 -0
- package/template/eslint-rules/no-disable-direct-fetch.js +57 -0
- package/template/eslint-rules/no-disable-type-safe-client.js +58 -0
- package/template/eslint-rules/no-inline-schema.js +220 -0
- package/template/eslint-rules/no-middleware-in-routes.js +81 -0
- package/template/eslint-rules/no-new-old-service-naming.js +123 -0
- package/template/eslint-rules/no-type-assertion-in-rpc.js +99 -0
- package/template/eslint-rules/no-type-assertion-on-shared-types.js +109 -0
- package/template/eslint-rules/no-util-functions-in-service.js +128 -0
- package/template/eslint-rules/prefer-shared-types.js +352 -0
- package/template/eslint-rules/protect-ws-sse-interface.js +66 -0
- package/template/eslint-rules/require-antd-generic-types.js +73 -0
- package/template/eslint-rules/require-file-openapi-props.js +114 -0
- package/template/eslint-rules/require-hono-chain-syntax.js +129 -0
- package/template/eslint-rules/require-nullable-for-optional.js +99 -0
- package/template/eslint-rules/require-response-helpers.js +140 -0
- package/template/eslint-rules/require-type-safe-test-client.js +106 -0
- package/template/eslint-rules/route-location.js +72 -0
- package/template/eslint.config.js +231 -0
- package/template/index.html +17 -0
- package/template/lint-scripts/DIRECTORY_RULES.md +335 -0
- package/template/lint-scripts/README.md +299 -0
- package/template/lint-scripts/TESTING.md +273 -0
- package/template/lint-scripts/ai-context-generator.ts +159 -0
- package/template/lint-scripts/check-framework-modify.sh +8 -0
- package/template/lint-scripts/check-menu-permissions.js +242 -0
- package/template/lint-scripts/check-refs.ts +165 -0
- package/template/lint-scripts/check-route-auth-complete.js +260 -0
- package/template/lint-scripts/check-route-auth.js +212 -0
- package/template/lint-scripts/check-route-permissions.js +210 -0
- package/template/lint-scripts/config/project.config.ts +358 -0
- package/template/lint-scripts/dev-context-analyzer.ts +707 -0
- package/template/lint-scripts/dev-guide-generator.ts +830 -0
- package/template/lint-scripts/dev-server.ts +58 -0
- package/template/lint-scripts/eslint-route-auth.js +158 -0
- package/template/lint-scripts/eslint-routes-permission.js +147 -0
- package/template/lint-scripts/fix-route-auth.js +245 -0
- package/template/lint-scripts/framework/check-modify.ts +152 -0
- package/template/lint-scripts/framework/hash-utils.ts +180 -0
- package/template/lint-scripts/framework/init-baseline.ts +84 -0
- package/template/lint-scripts/framework/update-baseline.ts +148 -0
- package/template/lint-scripts/post-commit-track.ts +66 -0
- package/template/lint-scripts/quick-test.sh +27 -0
- package/template/lint-scripts/smart-test.ts +268 -0
- package/template/lint-scripts/test-history.ts +360 -0
- package/template/lint-scripts/test-tracker.ts +350 -0
- package/template/lint-scripts/validate-all.ts +250 -0
- package/template/lint-scripts/validators/api-coverage.validator.ts +355 -0
- package/template/lint-scripts/validators/client-rpc.validator.ts +190 -0
- package/template/lint-scripts/validators/client-tests.validator.ts +155 -0
- package/template/lint-scripts/validators/console-log.validator.ts +122 -0
- package/template/lint-scripts/validators/directory-structure.validator.ts +181 -0
- package/template/lint-scripts/validators/imports.validator.ts +180 -0
- package/template/lint-scripts/validators/index.ts +271 -0
- package/template/lint-scripts/validators/md-refs.validator.ts +165 -0
- package/template/lint-scripts/validators/module-tests.validator.ts +112 -0
- package/template/lint-scripts/validators/sensitive.validator.ts +185 -0
- package/template/lint-scripts/validators/server-rpc.validator.ts +141 -0
- package/template/lint-scripts/validators/test-quality.validator.ts +257 -0
- package/template/lint-scripts/validators/todos.validator.ts +126 -0
- package/template/lint-scripts/watch-validator.ts +131 -0
- package/template/modules.config.ts +71 -0
- package/template/package-lock.json +14554 -0
- package/template/package.json +158 -0
- package/template/patches/@hono+zod-openapi+1.2.2.patch +67 -0
- package/template/patches/@hono+zod-validator+0.7.6.patch +13 -0
- package/template/patches/hono+4.12.16.patch +246 -0
- package/template/patches/typescript+5.8.3.patch +26 -0
- package/template/playwright.config.ts +60 -0
- package/template/pnpm-lock.yaml +7137 -0
- package/template/postcss.config.js +6 -0
- package/template/scripts/create-template.ts +1724 -0
- package/template/src/admin/App.tsx +59 -0
- package/template/src/admin/components/AccountSwitcher.tsx +104 -0
- package/template/src/admin/components/CaptchaModal.tsx +150 -0
- package/template/src/admin/components/NotificationDrawer.tsx +213 -0
- package/template/src/admin/components/PageHeader.tsx +45 -0
- package/template/src/admin/components/PermissionConfigEditor.tsx +237 -0
- package/template/src/admin/components/PermissionGuard.tsx +108 -0
- package/template/src/admin/components/PermissionTree.tsx +193 -0
- package/template/src/admin/components/ProtectedRoute.tsx +33 -0
- package/template/src/admin/components/StatsCard.tsx +44 -0
- package/template/src/admin/components/UserFormModal.tsx +67 -0
- package/template/src/admin/components/UserTable.tsx +72 -0
- package/template/src/admin/components/__tests__/PageHeader.test.tsx +48 -0
- package/template/src/admin/components/__tests__/PermissionConfigEditor.test.tsx +147 -0
- package/template/src/admin/components/__tests__/PermissionGuard.test.tsx +221 -0
- package/template/src/admin/components/__tests__/PermissionTree.test.tsx +187 -0
- package/template/src/admin/components/__tests__/ProtectedRoute.test.tsx +129 -0
- package/template/src/admin/components/__tests__/StatsCard.test.tsx +44 -0
- package/template/src/admin/components/__tests__/UserFormModal.test.tsx +125 -0
- package/template/src/admin/components/__tests__/UserTable.test.tsx +89 -0
- package/template/src/admin/components/index.ts +7 -0
- package/template/src/admin/hooks/__tests__/useAuditLogs.test.ts +109 -0
- package/template/src/admin/hooks/__tests__/usePermissions.test.tsx +327 -0
- package/template/src/admin/hooks/__tests__/usePermissionsBranches.test.ts +198 -0
- package/template/src/admin/hooks/__tests__/useRoles.test.ts +261 -0
- package/template/src/admin/hooks/useAdminNotifications.ts +156 -0
- package/template/src/admin/hooks/useAuditLogs.ts +44 -0
- package/template/src/admin/hooks/useConfig.ts +168 -0
- package/template/src/admin/hooks/usePermissions.ts +156 -0
- package/template/src/admin/hooks/useRoles.ts +120 -0
- package/template/src/admin/layouts/Header.tsx +93 -0
- package/template/src/admin/layouts/Layout.tsx +23 -0
- package/template/src/admin/layouts/Sidebar.tsx +120 -0
- package/template/src/admin/main.tsx +18 -0
- package/template/src/admin/pages/ContentPage.tsx +252 -0
- package/template/src/admin/pages/DashboardPage.tsx +141 -0
- package/template/src/admin/pages/DisputesPage.tsx +261 -0
- package/template/src/admin/pages/LoginPage.tsx +121 -0
- package/template/src/admin/pages/MediaTestPage.tsx +524 -0
- package/template/src/admin/pages/OrdersPage.tsx +302 -0
- package/template/src/admin/pages/PermissionsPage.tsx +95 -0
- package/template/src/admin/pages/RegisterPage.tsx +103 -0
- package/template/src/admin/pages/RolesPage.tsx +330 -0
- package/template/src/admin/pages/SettingsPage.tsx +73 -0
- package/template/src/admin/pages/SystemLogsPage.tsx +218 -0
- package/template/src/admin/pages/TestCaptchaPage.tsx +120 -0
- package/template/src/admin/pages/TicketsPage.tsx +292 -0
- package/template/src/admin/pages/UsersPage.tsx +282 -0
- package/template/src/admin/pages/__tests__/ContentPage.test.tsx +213 -0
- package/template/src/admin/pages/__tests__/DashboardPage.test.tsx +153 -0
- package/template/src/admin/pages/__tests__/DisputesPage.test.tsx +196 -0
- package/template/src/admin/pages/__tests__/LoginPage.test.tsx +112 -0
- package/template/src/admin/pages/__tests__/OrdersPage.test.tsx +217 -0
- package/template/src/admin/pages/__tests__/PermissionsPage.test.tsx +119 -0
- package/template/src/admin/pages/__tests__/RegisterPage.test.tsx +179 -0
- package/template/src/admin/pages/__tests__/RolesPage.test.tsx +256 -0
- package/template/src/admin/pages/__tests__/SettingsPage.test.tsx +66 -0
- package/template/src/admin/pages/__tests__/SystemLogsPage.test.tsx +125 -0
- package/template/src/admin/pages/__tests__/TicketsPage.test.tsx +202 -0
- package/template/src/admin/pages/__tests__/UsersPage.test.tsx +229 -0
- package/template/src/admin/services/README.md +263 -0
- package/template/src/admin/services/TESTING.md +323 -0
- package/template/src/admin/services/__tests__/skipLoading.test.ts +146 -0
- package/template/src/admin/services/apiClient.ts +66 -0
- package/template/src/admin/services/requestInterceptor.ts +127 -0
- package/template/src/admin/services/types.ts +5 -0
- package/template/src/admin/stores/__tests__/adminStore.test.ts +184 -0
- package/template/src/admin/stores/__tests__/adminStoreBranches.test.ts +148 -0
- package/template/src/admin/stores/__tests__/captchaStore.test.ts +75 -0
- package/template/src/admin/stores/__tests__/captchaStoreBranches.test.ts +37 -0
- package/template/src/admin/stores/__tests__/loadingStore.test.ts +68 -0
- package/template/src/admin/stores/adminStore.ts +88 -0
- package/template/src/admin/stores/captchaStore.ts +47 -0
- package/template/src/admin/stores/loadingStore.ts +27 -0
- package/template/src/cli/index.ts +22 -0
- package/template/src/cli/modules/config/index.ts +132 -0
- package/template/src/cli/modules/index.ts +12 -0
- package/template/src/cli/modules/notification/index.ts +86 -0
- package/template/src/cli/modules/todo/index.ts +60 -0
- package/template/src/cli/rpc/client.ts +23 -0
- package/template/src/cli/rpc/index.ts +1 -0
- package/template/src/cli/utils/api.ts +17 -0
- package/template/src/cli/utils/auto-command.ts +229 -0
- package/template/src/cli/utils/index.ts +8 -0
- package/template/src/cli/utils/logger.ts +79 -0
- package/template/src/client/App.tsx +24 -0
- package/template/src/client/Layout.tsx +27 -0
- package/template/src/client/components/AuthButton.tsx +41 -0
- package/template/src/client/components/ConnectionStatus.tsx +75 -0
- package/template/src/client/components/EmptyState.tsx +26 -0
- package/template/src/client/components/Footer.tsx +17 -0
- package/template/src/client/components/LoadingSpinner.tsx +26 -0
- package/template/src/client/components/MessageCard.tsx +61 -0
- package/template/src/client/components/Navigation.tsx +65 -0
- package/template/src/client/components/StatusBadge.tsx +50 -0
- package/template/src/client/components/__tests__/App.test.tsx +79 -0
- package/template/src/client/components/__tests__/AuthButton.test.tsx +119 -0
- package/template/src/client/components/__tests__/ConnectionStatus.test.tsx +188 -0
- package/template/src/client/components/__tests__/EmptyState.test.tsx +70 -0
- package/template/src/client/components/__tests__/Footer.test.tsx +22 -0
- package/template/src/client/components/__tests__/LoadingSpinner.test.tsx +75 -0
- package/template/src/client/components/__tests__/MessageCard.test.tsx +142 -0
- package/template/src/client/components/__tests__/Navigation.test.tsx +40 -0
- package/template/src/client/components/__tests__/StatusBadge.test.tsx +107 -0
- package/template/src/client/components/index.ts +6 -0
- package/template/src/client/index.css +27 -0
- package/template/src/client/main.tsx +25 -0
- package/template/src/client/pages/ContentDetailPage.tsx +142 -0
- package/template/src/client/pages/ContentListPage.tsx +169 -0
- package/template/src/client/pages/NotificationPage.tsx +288 -0
- package/template/src/client/pages/TodoPage.tsx +389 -0
- package/template/src/client/pages/WebSocketPage.tsx +239 -0
- package/template/src/client/pages/__tests__/ContentDetailPage.test.tsx +176 -0
- package/template/src/client/pages/__tests__/ContentListPage.test.tsx +202 -0
- package/template/src/client/pages/__tests__/NotificationPage.test.tsx +246 -0
- package/template/src/client/pages/__tests__/TodoPage.test.tsx +433 -0
- package/template/src/client/pages/__tests__/WebSocketPage.test.tsx +378 -0
- package/template/src/client/services/apiClient.ts +66 -0
- package/template/src/client/stores/__tests__/authStore.test.ts +139 -0
- package/template/src/client/stores/__tests__/chatWSStore.test.ts +416 -0
- package/template/src/client/stores/__tests__/notificationStore.test.ts +453 -0
- package/template/src/client/stores/__tests__/todoStore.test.ts +509 -0
- package/template/src/client/stores/authStore.ts +51 -0
- package/template/src/client/stores/chatWSStore.ts +122 -0
- package/template/src/client/stores/notificationStore.ts +199 -0
- package/template/src/client/stores/todoStore.ts +207 -0
- package/template/src/server/__tests__/integration/todos-api.test.ts +138 -0
- package/template/src/server/app.ts +105 -0
- package/template/src/server/config.ts +86 -0
- package/template/src/server/core/__tests__/realtime-core.test.ts +329 -0
- package/template/src/server/core/__tests__/realtime-scanner.test.ts +210 -0
- package/template/src/server/core/__tests__/runtime-node.test.ts +330 -0
- package/template/src/server/core/__tests__/runtime.test.ts +219 -0
- package/template/src/server/core/__tests__/typed-runtime.test.ts +178 -0
- package/template/src/server/core/durable-objects/RealtimeDO.ts +206 -0
- package/template/src/server/core/index.ts +83 -0
- package/template/src/server/core/module-loader.ts +281 -0
- package/template/src/server/core/realtime-core.ts +152 -0
- package/template/src/server/core/realtime-scanner.ts +99 -0
- package/template/src/server/core/runtime-cloudflare.ts +207 -0
- package/template/src/server/core/runtime-node.ts +170 -0
- package/template/src/server/core/runtime.ts +129 -0
- package/template/src/server/core/typed-runtime.ts +80 -0
- package/template/src/server/db/__tests__/driver.test.ts +203 -0
- package/template/src/server/db/config.ts +1 -0
- package/template/src/server/db/driver-cloudflare.ts +50 -0
- package/template/src/server/db/driver.ts +116 -0
- package/template/src/server/db/index.ts +3 -0
- package/template/src/server/db/init.ts +412 -0
- package/template/src/server/db/schema/api-endpoints.ts +23 -0
- package/template/src/server/db/schema/contents.ts +31 -0
- package/template/src/server/db/schema/disputes.ts +39 -0
- package/template/src/server/db/schema/index.ts +14 -0
- package/template/src/server/db/schema/notifications.ts +16 -0
- package/template/src/server/db/schema/orders.ts +30 -0
- package/template/src/server/db/schema/permission-audit-logs.ts +17 -0
- package/template/src/server/db/schema/permission-route-mappings.ts +22 -0
- package/template/src/server/db/schema/permissions.ts +17 -0
- package/template/src/server/db/schema/role-permissions.ts +22 -0
- package/template/src/server/db/schema/roles.ts +17 -0
- package/template/src/server/db/schema/tickets.ts +62 -0
- package/template/src/server/db/schema/todo-attachments.ts +22 -0
- package/template/src/server/db/schema/todos.ts +21 -0
- package/template/src/server/db/schema/user-roles.ts +17 -0
- package/template/src/server/db/seeds/index.ts +1 -0
- package/template/src/server/db/seeds/permission-data.ts +354 -0
- package/template/src/server/db/test-setup.ts +647 -0
- package/template/src/server/entries/cloudflare.ts +71 -0
- package/template/src/server/entries/node.ts +190 -0
- package/template/src/server/index.ts +62 -0
- package/template/src/server/middleware/__tests__/auth-simple.test.ts +147 -0
- package/template/src/server/middleware/__tests__/auth.test.ts +276 -0
- package/template/src/server/middleware/__tests__/captcha.test.ts +258 -0
- package/template/src/server/middleware/__tests__/error-handler.test.ts +364 -0
- package/template/src/server/middleware/__tests__/error-response-format.test.ts +80 -0
- package/template/src/server/middleware/__tests__/permission.test.ts +312 -0
- package/template/src/server/middleware/audit-log.ts +101 -0
- package/template/src/server/middleware/auth.ts +235 -0
- package/template/src/server/middleware/captcha.ts +166 -0
- package/template/src/server/middleware/cors.ts +30 -0
- package/template/src/server/middleware/error-handler.ts +135 -0
- package/template/src/server/middleware/index.ts +24 -0
- package/template/src/server/middleware/logger.ts +73 -0
- package/template/src/server/middleware/permission.ts +127 -0
- package/template/src/server/middleware/rate-limit.ts +69 -0
- package/template/src/server/middleware/realtime-env.ts +12 -0
- package/template/src/server/module-admin/__tests__/admin-routes.test.ts +360 -0
- package/template/src/server/module-admin/__tests__/admin-service.test.ts +222 -0
- package/template/src/server/module-admin/__tests__/audit-log-routes.test.ts +261 -0
- package/template/src/server/module-admin/__tests__/export-routes.test.ts +160 -0
- package/template/src/server/module-admin/__tests__/media-routes.test.ts +122 -0
- package/template/src/server/module-admin/module.ts +40 -0
- package/template/src/server/module-admin/routes/admin-notification-routes.ts +197 -0
- package/template/src/server/module-admin/routes/admin-routes.ts +20 -0
- package/template/src/server/module-admin/routes/auth-routes.ts +86 -0
- package/template/src/server/module-admin/routes/export-routes.ts +207 -0
- package/template/src/server/module-admin/routes/media-routes.ts +78 -0
- package/template/src/server/module-admin/routes/system-routes.ts +89 -0
- package/template/src/server/module-admin/routes/user-management-routes.ts +143 -0
- package/template/src/server/module-admin/services/admin-service.ts +268 -0
- package/template/src/server/module-captcha/__tests__/captcha-route.test.ts +35 -0
- package/template/src/server/module-captcha/__tests__/captcha-service.test.ts +53 -0
- package/template/src/server/module-captcha/module.ts +35 -0
- package/template/src/server/module-captcha/routes/captcha-routes.ts +68 -0
- package/template/src/server/module-captcha/services/captcha-service.ts +3 -0
- package/template/src/server/module-chat/__tests__/chat-routes.test.ts +39 -0
- package/template/src/server/module-chat/__tests__/chat-rpc.test.ts +185 -0
- package/template/src/server/module-chat/__tests__/chat-service.test.ts +64 -0
- package/template/src/server/module-chat/module.ts +27 -0
- package/template/src/server/module-chat/routes/chat-routes.ts +46 -0
- package/template/src/server/module-chat/services/chat-service.ts +38 -0
- package/template/src/server/module-content/__tests__/content-route.test.ts +40 -0
- package/template/src/server/module-content/__tests__/content-service.test.ts +107 -0
- package/template/src/server/module-content/module.ts +39 -0
- package/template/src/server/module-content/routes/content-routes.ts +182 -0
- package/template/src/server/module-content/routes/public-content-routes.ts +58 -0
- package/template/src/server/module-content/services/content-service.ts +224 -0
- package/template/src/server/module-dispute/__tests__/dispute-route.test.ts +43 -0
- package/template/src/server/module-dispute/__tests__/dispute-service.test.ts +135 -0
- package/template/src/server/module-dispute/module.ts +30 -0
- package/template/src/server/module-dispute/routes/dispute-routes.ts +153 -0
- package/template/src/server/module-dispute/services/dispute-service.ts +255 -0
- package/template/src/server/module-file/__tests__/file-routes.test.ts +284 -0
- package/template/src/server/module-file/__tests__/file-storage-service.test.ts +323 -0
- package/template/src/server/module-file/module.ts +28 -0
- package/template/src/server/module-file/routes/file-routes.ts +288 -0
- package/template/src/server/module-notifications/__tests__/notification-route-rpc.test.ts +375 -0
- package/template/src/server/module-notifications/__tests__/notification-service.test.ts +241 -0
- package/template/src/server/module-notifications/__tests__/sse-rpc.test.ts +289 -0
- package/template/src/server/module-notifications/module.ts +32 -0
- package/template/src/server/module-notifications/routes/notification-routes.ts +190 -0
- package/template/src/server/module-notifications/services/notification-service.ts +104 -0
- package/template/src/server/module-order/__tests__/order-route.test.ts +258 -0
- package/template/src/server/module-order/__tests__/order-service.test.ts +222 -0
- package/template/src/server/module-order/module.ts +30 -0
- package/template/src/server/module-order/routes/order-routes.ts +202 -0
- package/template/src/server/module-order/services/order-service.ts +268 -0
- package/template/src/server/module-permission/__tests__/permission-middleware.test.ts +90 -0
- package/template/src/server/module-permission/__tests__/permission-routes.test.ts +330 -0
- package/template/src/server/module-permission/__tests__/permission-service-impl.test.ts +388 -0
- package/template/src/server/module-permission/__tests__/permission-service.test.ts +190 -0
- package/template/src/server/module-permission/__tests__/role-routes.test.ts +215 -0
- package/template/src/server/module-permission/module.ts +68 -0
- package/template/src/server/module-permission/routes/audit-log-routes.ts +76 -0
- package/template/src/server/module-permission/routes/permission-routes.ts +184 -0
- package/template/src/server/module-permission/routes/role-routes.ts +263 -0
- package/template/src/server/module-permission/services/audit-log-service.ts +108 -0
- package/template/src/server/module-permission/services/permission-service-impl.ts +233 -0
- package/template/src/server/module-permission/services/permission-service.ts +256 -0
- package/template/src/server/module-permission/services/role-service.ts +122 -0
- package/template/src/server/module-ticket/__tests__/ticket-route.test.ts +173 -0
- package/template/src/server/module-ticket/__tests__/ticket-service.test.ts +201 -0
- package/template/src/server/module-ticket/module.ts +30 -0
- package/template/src/server/module-ticket/routes/ticket-routes.ts +210 -0
- package/template/src/server/module-ticket/services/ticket-service.ts +297 -0
- package/template/src/server/module-todos/__tests__/todo-service.test.ts +196 -0
- package/template/src/server/module-todos/__tests__/todos-file-upload.test.ts +439 -0
- package/template/src/server/module-todos/__tests__/todos-route-rpc.test.ts +575 -0
- package/template/src/server/module-todos/module.ts +30 -0
- package/template/src/server/module-todos/routes/todos-routes.ts +260 -0
- package/template/src/server/module-todos/services/todo-service.ts +202 -0
- package/template/src/server/route-registry.ts +47 -0
- package/template/src/server/test-utils/test-client.ts +66 -0
- package/template/src/server/test-utils/test-server.ts +131 -0
- package/template/src/server/types/bindings.ts +10 -0
- package/template/src/server/utils/__tests__/app-error.test.ts +374 -0
- package/template/src/server/utils/__tests__/auth.test.ts +76 -0
- package/template/src/server/utils/__tests__/captcha.test.ts +80 -0
- package/template/src/server/utils/__tests__/file-storage.test.ts +472 -0
- package/template/src/server/utils/__tests__/logger.test.ts +221 -0
- package/template/src/server/utils/__tests__/route-helpers.test.ts +264 -0
- package/template/src/server/utils/app-error.ts +355 -0
- package/template/src/server/utils/auth.ts +65 -0
- package/template/src/server/utils/captcha.ts +119 -0
- package/template/src/server/utils/date.ts +50 -0
- package/template/src/server/utils/env.ts +4 -0
- package/template/src/server/utils/file-storage.ts +462 -0
- package/template/src/server/utils/generate.ts +26 -0
- package/template/src/server/utils/id-helpers.ts +5 -0
- package/template/src/server/utils/logger.ts +139 -0
- package/template/src/server/utils/permission-utils.ts +6 -0
- package/template/src/server/utils/response.ts +40 -0
- package/template/src/server/utils/route-helpers.ts +200 -0
- package/template/src/server/utils/uuid.ts +8 -0
- package/template/src/server/utils/ws-helper.ts +30 -0
- package/template/src/shared/constants/index.ts +1 -0
- package/template/src/shared/constants/resource-types.ts +72 -0
- package/template/src/shared/core/__tests__/sse-client.test.ts +376 -0
- package/template/src/shared/core/__tests__/ws-client.test.ts +468 -0
- package/template/src/shared/core/api-request.ts +192 -0
- package/template/src/shared/core/api-schemas.ts +41 -0
- package/template/src/shared/core/index.ts +37 -0
- package/template/src/shared/core/module-manifest.ts +120 -0
- package/template/src/shared/core/protocol-types.ts +26 -0
- package/template/src/shared/core/sse-client.ts +185 -0
- package/template/src/shared/core/ws-client.ts +236 -0
- package/template/src/shared/hooks/index.ts +2 -0
- package/template/src/shared/hooks/useSSE.ts +57 -0
- package/template/src/shared/hooks/useWebSocket.ts +66 -0
- package/template/src/shared/index.ts +5 -0
- package/template/src/shared/modules/admin/index.ts +1 -0
- package/template/src/shared/modules/admin/schemas.ts +100 -0
- package/template/src/shared/modules/audit/index.ts +1 -0
- package/template/src/shared/modules/audit/schemas.ts +24 -0
- package/template/src/shared/modules/captcha/index.ts +1 -0
- package/template/src/shared/modules/captcha/schemas.ts +19 -0
- package/template/src/shared/modules/chat/index.ts +38 -0
- package/template/src/shared/modules/content/index.ts +1 -0
- package/template/src/shared/modules/content/schemas.ts +53 -0
- package/template/src/shared/modules/dispute/index.ts +1 -0
- package/template/src/shared/modules/dispute/schemas.ts +62 -0
- package/template/src/shared/modules/files/index.ts +11 -0
- package/template/src/shared/modules/files/schemas.ts +44 -0
- package/template/src/shared/modules/index.ts +70 -0
- package/template/src/shared/modules/notifications/index.ts +26 -0
- package/template/src/shared/modules/notifications/schemas.ts +73 -0
- package/template/src/shared/modules/order/index.ts +1 -0
- package/template/src/shared/modules/order/schemas.ts +63 -0
- package/template/src/shared/modules/permission/index.ts +42 -0
- package/template/src/shared/modules/permission/permission-dependencies.ts +50 -0
- package/template/src/shared/modules/permission/permissions.ts +275 -0
- package/template/src/shared/modules/permission/schemas.ts +92 -0
- package/template/src/shared/modules/permission/types.ts +23 -0
- package/template/src/shared/modules/role/index.ts +1 -0
- package/template/src/shared/modules/role/schemas.ts +46 -0
- package/template/src/shared/modules/ticket/index.ts +1 -0
- package/template/src/shared/modules/ticket/schemas.ts +77 -0
- package/template/src/shared/modules/todos/index.ts +20 -0
- package/template/src/shared/modules/todos/schemas.ts +65 -0
- package/template/src/shared/schemas/index.ts +79 -0
- package/template/src/types/global.d.ts +14 -0
- package/template/src/vite-env.d.ts +21 -0
- package/template/tailwind.config.js +11 -0
- package/template/tests/e2e/admin-crud.spec.ts +81 -0
- package/template/tests/e2e/case-o1.spec.ts +108 -0
- package/template/tests/e2e/global-setup.ts +73 -0
- package/template/tests/e2e/global-teardown.ts +28 -0
- package/template/tests/e2e/notification.spec.ts +458 -0
- package/template/tests/e2e/todo.spec.ts +623 -0
- package/template/tests/e2e/websocket.spec.ts +254 -0
- package/template/tsconfig.json +35 -0
- package/template/tsup.config.ts +95 -0
- package/template/vite-plugins.ts +113 -0
- package/template/vite.config.ts +96 -0
- package/template/vitest.config.ts +53 -0
- package/template/vitest.integration.config.ts +24 -0
- package/template/vitest.integration.setup.ts +22 -0
- package/template/vitest.setup.ts +74 -0
- package/template/wrangler.toml +33 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project
|
|
6
|
+
|
|
7
|
+
Todo Application Template - A full-stack React + Hono application demonstrating best practices for monorepo-style architecture with single-port development.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm run dev # Start Vite dev server on port 3010 with Hono backend
|
|
13
|
+
npm run build # Production build
|
|
14
|
+
npm run preview # Preview production build
|
|
15
|
+
npm run test # Run all Vitest tests
|
|
16
|
+
npm run test:unit # Run unit tests only
|
|
17
|
+
npm run test:integration # Run integration tests only
|
|
18
|
+
npm run lint # Run ESLint
|
|
19
|
+
npm run format # Run Prettier format
|
|
20
|
+
npm run typecheck # Run TypeScript type check
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Architecture Overview
|
|
24
|
+
|
|
25
|
+
**Monorepo-style structure** with client/server separation and shared types:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
src/
|
|
29
|
+
├── client/ # React frontend
|
|
30
|
+
│ ├── components/ # UI components
|
|
31
|
+
│ ├── stores/ # Zustand state management
|
|
32
|
+
│ ├── services/ # API clients (apiClient)
|
|
33
|
+
│ ├── hooks/ # Custom hooks
|
|
34
|
+
│ ├── pages/ # Page components
|
|
35
|
+
│ └── App.tsx
|
|
36
|
+
├── server/ # Hono backend
|
|
37
|
+
│ ├── module-todos/ # Todo module
|
|
38
|
+
│ ├── module-chat/ # WebSocket chat module
|
|
39
|
+
│ ├── module-notifications/ # SSE notifications module
|
|
40
|
+
│ ├── core/ # Core services (runtime, realtime)
|
|
41
|
+
│ ├── middleware/ # Express middleware
|
|
42
|
+
│ ├── test-utils/ # Test utilities
|
|
43
|
+
│ └── entries/ # Entry points (node.ts, cloudflare.ts)
|
|
44
|
+
└── shared/ # Shared types
|
|
45
|
+
├── core/ # Framework layer (ws-client, sse-client, api-schemas)
|
|
46
|
+
├── modules/ # Business layer (chat, todos, notifications schemas)
|
|
47
|
+
└── schemas/ # Unified exports
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Path Aliases** (configured in vite.config.ts and tsconfig.json):
|
|
51
|
+
|
|
52
|
+
- `@shared/*` → src/shared/\*
|
|
53
|
+
- `@client/*` → src/client/\*
|
|
54
|
+
- `@server/*` → src/server/\*
|
|
55
|
+
|
|
56
|
+
## Key Technical Concepts
|
|
57
|
+
|
|
58
|
+
### Single-Port Development
|
|
59
|
+
|
|
60
|
+
Uses "@hono/vite-dev-server" to run both frontend and backend on port 3010:
|
|
61
|
+
|
|
62
|
+
- No CORS issues in development
|
|
63
|
+
- Type safety across the boundary
|
|
64
|
+
- Simplified developer experience
|
|
65
|
+
|
|
66
|
+
### Hono RPC
|
|
67
|
+
|
|
68
|
+
Type-safe API calls from frontend to backend:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { apiClient } from '@client/services/apiClient'
|
|
72
|
+
|
|
73
|
+
// HTTP API
|
|
74
|
+
const response = await apiClient.api.todos.$get()
|
|
75
|
+
const result = await response.json()
|
|
76
|
+
|
|
77
|
+
// WebSocket
|
|
78
|
+
const ws = apiClient.api.chat.ws.$ws()
|
|
79
|
+
const result = await ws.call('echo', { message: 'hello' })
|
|
80
|
+
|
|
81
|
+
// SSE
|
|
82
|
+
const conn = await apiClient.api.notifications.stream.$sse()
|
|
83
|
+
conn.on('notification', n => console.log(n))
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Real-time Features
|
|
87
|
+
|
|
88
|
+
| Feature | Method | Type Safety | Testing |
|
|
89
|
+
| --------- | ------------------- | ----------- | ---------------- |
|
|
90
|
+
| HTTP API | `$get()`, `$post()` | ✅ | No server needed |
|
|
91
|
+
| WebSocket | `$ws()` | ✅ | Requires server |
|
|
92
|
+
| SSE | `$sse()` | ✅ | No server needed |
|
|
93
|
+
|
|
94
|
+
### Module Pattern
|
|
95
|
+
|
|
96
|
+
Backend organized by feature modules:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
module-{feature}/
|
|
100
|
+
├── routes/ # API endpoints (Hono RPC)
|
|
101
|
+
├── services/ # Business logic
|
|
102
|
+
└── __tests__/ # Unit tests
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Framework Layer vs Business Layer
|
|
106
|
+
|
|
107
|
+
The project has clear separation between framework and business layers:
|
|
108
|
+
|
|
109
|
+
**Framework Layer** (`src/shared/core/`):
|
|
110
|
+
|
|
111
|
+
- Generic, reusable infrastructure code
|
|
112
|
+
- Examples: `ws-client.ts`, `sse-client.ts`, `api-schemas.ts`
|
|
113
|
+
- Should not be modified by business code directly
|
|
114
|
+
|
|
115
|
+
**Business Layer** (`src/shared/modules/`):
|
|
116
|
+
|
|
117
|
+
- Business-specific schemas and protocols
|
|
118
|
+
- Examples: `chat/`, `todos/`, `notifications/`
|
|
119
|
+
- Organized by feature modules
|
|
120
|
+
|
|
121
|
+
### Layer Boundary Rules (ESLint)
|
|
122
|
+
|
|
123
|
+
The project enforces layer boundaries with `layer-boundary` rule:
|
|
124
|
+
|
|
125
|
+
- Business code cannot directly modify framework layer code
|
|
126
|
+
- Business code importing framework code needs `@framework-import` comment
|
|
127
|
+
- Framework code modification needs `@framework-allow-modification` comment
|
|
128
|
+
|
|
129
|
+
### State Management with Zustand
|
|
130
|
+
|
|
131
|
+
Global application state in `src/client/stores/`:
|
|
132
|
+
|
|
133
|
+
- **Minimal Re-renders**: Use precise selector hooks
|
|
134
|
+
- **Selector Pattern**: `const todos = useTodoStore((state) => state.todos)`
|
|
135
|
+
- **Action Selectors**: Stable function references
|
|
136
|
+
|
|
137
|
+
### Testing Strategy
|
|
138
|
+
|
|
139
|
+
- **Unit Tests**: `__tests__/*.test.ts` (jsdom for client, node for server)
|
|
140
|
+
- **Integration Tests**: `src/server/__tests__/integration/*.test.ts`
|
|
141
|
+
- **E2E Tests**: `tests/e2e/*.spec.ts` (Playwright)
|
|
142
|
+
- **WebSocket Tests**: Require real server (`createTestServer`)
|
|
143
|
+
- **SSE Tests**: No server needed (`$sse()` works with `app.fetch()`)
|
|
144
|
+
|
|
145
|
+
## Important Conventions
|
|
146
|
+
|
|
147
|
+
### Import Path Aliases
|
|
148
|
+
|
|
149
|
+
Always use path aliases instead of relative imports:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { Todo } from '@shared/schemas'
|
|
153
|
+
import { useTodoStore } from '@client/stores/todoStore'
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Environment Variables
|
|
157
|
+
|
|
158
|
+
Required variables (see `.env.example`):
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
API_BASE_URL=http://localhost:3010
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Module Manifest System
|
|
165
|
+
|
|
166
|
+
Each module under `src/server/module-*/` has a `module.ts` manifest declaring:
|
|
167
|
+
|
|
168
|
+
- Dependencies on other modules
|
|
169
|
+
- Route registrations (client, admin, standalone)
|
|
170
|
+
- Shared schemas, DB schemas, client/admin pages
|
|
171
|
+
- Middleware it provides
|
|
172
|
+
- Whether it has SSE or WebSocket
|
|
173
|
+
|
|
174
|
+
#### Module Categories
|
|
175
|
+
|
|
176
|
+
| Category | Modules |
|
|
177
|
+
| ------------- | -------------------------------- |
|
|
178
|
+
| core | todos |
|
|
179
|
+
| communication | chat, notifications |
|
|
180
|
+
| business | order, ticket, dispute, content |
|
|
181
|
+
| system | permission, admin, captcha, file |
|
|
182
|
+
|
|
183
|
+
#### Dependency Graph
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
todos ──── (standalone)
|
|
187
|
+
chat ──── (standalone)
|
|
188
|
+
notifications ── (standalone)
|
|
189
|
+
file ──── (standalone)
|
|
190
|
+
captcha ── (standalone)
|
|
191
|
+
permission ── (standalone, foundational)
|
|
192
|
+
admin ──→ permission + notifications
|
|
193
|
+
order ──→ permission
|
|
194
|
+
ticket ──→ permission
|
|
195
|
+
dispute ──→ permission
|
|
196
|
+
content ──→ permission
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### Validation
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
npm run validate:modules
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### Template Presets
|
|
206
|
+
|
|
207
|
+
Defined in `modules.config.ts`:
|
|
208
|
+
|
|
209
|
+
- `fullstack-admin` — All modules (default)
|
|
210
|
+
- `todo-app` — todos + chat + notifications
|
|
211
|
+
- `minimal` — todos only
|
|
212
|
+
|
|
213
|
+
### Module Creation
|
|
214
|
+
|
|
215
|
+
To add a new feature module:
|
|
216
|
+
|
|
217
|
+
1. Create `src/server/module-{feature}/` with routes, services, tests
|
|
218
|
+
2. Create shared schemas in `src/shared/modules/{feature}/`
|
|
219
|
+
3. Add `module.ts` manifest in the module directory
|
|
220
|
+
4. Register routes in `route-registry.ts`
|
|
221
|
+
5. Add DB schemas to `server/db/schema/`
|
|
222
|
+
6. Add client store if needed
|
|
223
|
+
7. Add integration tests
|
|
224
|
+
8. Run `npm run validate:modules` to verify
|
|
225
|
+
|
|
226
|
+
### API Route Pattern
|
|
227
|
+
|
|
228
|
+
Use Hono RPC with chain syntax:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
app.openapi(listRoute, async c => {
|
|
232
|
+
const todos = await todoService.listTodos()
|
|
233
|
+
return c.json({ success: true, data: todos })
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### WebSocket Pattern
|
|
238
|
+
|
|
239
|
+
Use `$ws()` method for type-safe WebSocket:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// Server: Define protocol in src/shared/modules/chat/
|
|
243
|
+
import { ChatProtocolSchema } from '@shared/modules/chat'
|
|
244
|
+
|
|
245
|
+
// Client: Use $ws()
|
|
246
|
+
const ws = apiClient.api.chat.ws.$ws()
|
|
247
|
+
const result = await ws.call('echo', { message: 'hello' })
|
|
248
|
+
ws.on('notification', n => console.log(n))
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### SSE Pattern
|
|
252
|
+
|
|
253
|
+
Use `$sse()` method for type-safe SSE:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Server: Define protocol in src/shared/modules/notifications/
|
|
257
|
+
import { AppSSEProtocolSchema } from '@shared/schemas'
|
|
258
|
+
|
|
259
|
+
// Client: Use $sse()
|
|
260
|
+
const conn = await apiClient.api.notifications.stream.$sse()
|
|
261
|
+
conn.on('notification', n => console.log(n))
|
|
262
|
+
conn.on('ping', p => console.log(p.timestamp))
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### SSE Broadcast Pattern
|
|
266
|
+
|
|
267
|
+
When creating notifications, broadcast to all connected SSE clients:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// In service layer - use createNotificationAndBroadcast
|
|
271
|
+
import { createNotificationAndBroadcast } from '@server/module-notifications/services/notification-service'
|
|
272
|
+
|
|
273
|
+
// The service automatically handles broadcasting via realtime middleware
|
|
274
|
+
const notification = await createNotificationAndBroadcast(input)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Project Rules
|
|
278
|
+
|
|
279
|
+
See `.claude/rules/` for detailed development constraints:
|
|
280
|
+
|
|
281
|
+
- `project-rules.md` - Environment & constants management
|
|
282
|
+
- `client-component-rules.md` - React component patterns
|
|
283
|
+
- `client-service-rules.md` - Service layer patterns
|
|
284
|
+
- `zustand-rules.md` - Zustand store patterns
|
|
285
|
+
- `websocket-rules.md` - WebSocket development patterns
|
|
286
|
+
- `sse-rules.md` - SSE development patterns
|
|
287
|
+
- `shared-types-rules.md` - Shared types organization
|
|
288
|
+
- `layer-boundary-rules.md` - Framework/Business layer separation
|
|
289
|
+
- `testing-standards.md` - Testing conventions
|
|
290
|
+
- `hono-testing-best-practices.md` - Hono testing patterns
|
|
291
|
+
|
|
292
|
+
## Documentation
|
|
293
|
+
|
|
294
|
+
- `README.md` - User-facing feature overview
|
|
295
|
+
- `DESIGN.md` - Technical architecture
|
|
296
|
+
- `QUICKSTART.md` - Quick start guide
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Design Document
|
|
2
|
+
|
|
3
|
+
## Architecture Overview
|
|
4
|
+
|
|
5
|
+
This template implements a **monorepo-style architecture** with client/server separation while maintaining a single development port.
|
|
6
|
+
|
|
7
|
+
### Key Design Decisions
|
|
8
|
+
|
|
9
|
+
#### 1. Single-Port Development
|
|
10
|
+
|
|
11
|
+
- **Why**: Simplifies local development, no CORS issues
|
|
12
|
+
- **How**: `@hono/vite-dev-server` serves both React and Hono
|
|
13
|
+
- **Benefit**: Developer experience, type safety across boundary
|
|
14
|
+
|
|
15
|
+
#### 2. Hono RPC
|
|
16
|
+
|
|
17
|
+
- **Why**: End-to-end type safety between frontend and backend
|
|
18
|
+
- **How**: Shared types exported from `src/server/index.ts`
|
|
19
|
+
- **Benefit**: Compile-time error detection, better DX
|
|
20
|
+
|
|
21
|
+
#### 3. Modular Backend
|
|
22
|
+
|
|
23
|
+
- **Why**: Scalability, clear separation of concerns
|
|
24
|
+
- **How**: Feature-based modules (`module-todos/`, `module-chat/`, etc.)
|
|
25
|
+
- **Benefit**: Easy to add new features, maintainable codebase
|
|
26
|
+
|
|
27
|
+
#### 4. Zustand for State
|
|
28
|
+
|
|
29
|
+
- **Why**: Minimal boilerplate, no context provider hell
|
|
30
|
+
- **How**: Global store with selector hooks
|
|
31
|
+
- **Benefit**: Performance (minimal re-renders), simplicity
|
|
32
|
+
|
|
33
|
+
#### 5. Real-time Support
|
|
34
|
+
|
|
35
|
+
- **Why**: Modern apps need real-time features
|
|
36
|
+
- **How**: WebSocket (`$ws()`) and SSE (`$sse()`) with type safety
|
|
37
|
+
- **Benefit**: Type-safe real-time communication
|
|
38
|
+
|
|
39
|
+
## Module Pattern
|
|
40
|
+
|
|
41
|
+
Each backend module follows this structure:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
module-{feature}/
|
|
45
|
+
├── routes/ # API endpoints (Hono RPC)
|
|
46
|
+
├── services/ # Business logic
|
|
47
|
+
└── __tests__/ # Unit tests
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Example: Adding a New Module
|
|
51
|
+
|
|
52
|
+
1. Create directory: `src/server/module-features/`
|
|
53
|
+
2. Add routes: `src/server/module-features/routes/features-routes.ts`
|
|
54
|
+
3. Add service: `src/server/module-features/services/feature-service.ts`
|
|
55
|
+
4. Add tests: `src/server/module-features/__tests__/feature-service.test.ts`
|
|
56
|
+
5. Register in `src/server/app.ts`:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { featureRoutes } from './module-features/routes/features-routes'
|
|
60
|
+
app.route('/api', featureRoutes)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**参考现有模块**:
|
|
64
|
+
|
|
65
|
+
- `src/server/module-todos/` - Todo 模块
|
|
66
|
+
- `src/server/module-admin/` - Admin 模块
|
|
67
|
+
|
|
68
|
+
## Real-time Architecture
|
|
69
|
+
|
|
70
|
+
### WebSocket (`$ws()`)
|
|
71
|
+
|
|
72
|
+
**Type Safety Flow**:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
Server: WSProtocol Schema
|
|
76
|
+
↓
|
|
77
|
+
@hono/zod-openapi: TypedResponse
|
|
78
|
+
↓
|
|
79
|
+
Hono: ToSchemaOutput
|
|
80
|
+
↓
|
|
81
|
+
Client: $ws() → WSClient<Protocol>
|
|
82
|
+
↓
|
|
83
|
+
Developer: ws.call('method', params) // Type-safe!
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Testing**: Requires real server (`createTestServer`)
|
|
87
|
+
|
|
88
|
+
### SSE (`$sse()`)
|
|
89
|
+
|
|
90
|
+
**Type Safety Flow**:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
Server: SSEProtocol Schema
|
|
94
|
+
↓
|
|
95
|
+
@hono/zod-openapi: TypedResponse
|
|
96
|
+
↓
|
|
97
|
+
Hono: ToSchemaOutput
|
|
98
|
+
↓
|
|
99
|
+
Client: $sse() → SSEClient<Protocol>
|
|
100
|
+
↓
|
|
101
|
+
Developer: conn.on('event', handler) // Type-safe!
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Testing**: No server needed, works with `app.fetch()`
|
|
105
|
+
|
|
106
|
+
### Comparison
|
|
107
|
+
|
|
108
|
+
| Feature | WebSocket | SSE |
|
|
109
|
+
| --------- | -------------------------- | -------------------------------- |
|
|
110
|
+
| Direction | Bidirectional | Unidirectional (server → client) |
|
|
111
|
+
| Methods | `call()`, `emit()`, `on()` | `on()`, `onStatusChange()` |
|
|
112
|
+
| Protocol | `WSProtocol` | `SSEProtocol` |
|
|
113
|
+
| Testing | Requires server | No server needed |
|
|
114
|
+
| Use Case | Chat, gaming | Notifications, feeds |
|
|
115
|
+
|
|
116
|
+
## Testing Strategy
|
|
117
|
+
|
|
118
|
+
### Unit Tests
|
|
119
|
+
|
|
120
|
+
- Location: `src/**/__tests__/*.test.ts`
|
|
121
|
+
- Framework: Vitest
|
|
122
|
+
- Environment: `jsdom` (client), `node` (server)
|
|
123
|
+
- Coverage: Services, stores, utilities
|
|
124
|
+
|
|
125
|
+
### Integration Tests
|
|
126
|
+
|
|
127
|
+
- Location: `src/server/integration/*.test.ts`
|
|
128
|
+
- Framework: Vitest
|
|
129
|
+
- Environment: `node`
|
|
130
|
+
- Coverage: API endpoints
|
|
131
|
+
|
|
132
|
+
### WebSocket Tests
|
|
133
|
+
|
|
134
|
+
- Location: `src/server/module-chat/__tests__/*.test.ts`
|
|
135
|
+
- Framework: Vitest
|
|
136
|
+
- Environment: `node`
|
|
137
|
+
- Requires: `createTestServer()`
|
|
138
|
+
|
|
139
|
+
### SSE Tests
|
|
140
|
+
|
|
141
|
+
- Location: `src/server/module-notifications/__tests__/*.test.ts`
|
|
142
|
+
- Framework: Vitest
|
|
143
|
+
- Environment: `node`
|
|
144
|
+
- Requires: No server needed
|
|
145
|
+
|
|
146
|
+
### E2E Tests
|
|
147
|
+
|
|
148
|
+
- Location: `tests/e2e/*.spec.ts`
|
|
149
|
+
- Framework: Playwright
|
|
150
|
+
- Environment: Browser
|
|
151
|
+
- Coverage: User workflows
|
|
152
|
+
|
|
153
|
+
## Type Safety Flow
|
|
154
|
+
|
|
155
|
+
### HTTP API
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
┌─────────────────┐
|
|
159
|
+
│ Server Routes │ ──export──> AppType
|
|
160
|
+
└─────────────────┘ │
|
|
161
|
+
│
|
|
162
|
+
┌─────────────────┐ ▼
|
|
163
|
+
│ RPC Client │ <──import── AppType
|
|
164
|
+
│ (Frontend) │
|
|
165
|
+
└─────────────────┘
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### WebSocket
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
┌─────────────────┐
|
|
172
|
+
│ WSProtocol │ ──schema──> TypedResponse
|
|
173
|
+
└─────────────────┘ │
|
|
174
|
+
│
|
|
175
|
+
┌─────────────────┐ ▼
|
|
176
|
+
│ $ws() Method │ <──type inference──
|
|
177
|
+
│ (Frontend) │
|
|
178
|
+
└─────────────────┘
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### SSE
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
┌─────────────────┐
|
|
185
|
+
│ SSEProtocol │ ──schema──> TypedResponse
|
|
186
|
+
└─────────────────┘ │
|
|
187
|
+
│
|
|
188
|
+
┌─────────────────┐ ▼
|
|
189
|
+
│ $sse() Method │ <──type inference──
|
|
190
|
+
│ (Frontend) │
|
|
191
|
+
└─────────────────┘
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Database Schema
|
|
195
|
+
|
|
196
|
+
Using Drizzle ORM with SQLite:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
export const todos = sqliteTable('todos', {
|
|
200
|
+
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
201
|
+
title: text('title').notNull(),
|
|
202
|
+
description: text('description'),
|
|
203
|
+
status: text('status').notNull().default('pending'),
|
|
204
|
+
createdAt: integer('created_at', { mode: 'timestamp' }),
|
|
205
|
+
updatedAt: integer('updated_at', { mode: 'timestamp' }),
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Performance Considerations
|
|
210
|
+
|
|
211
|
+
### Frontend
|
|
212
|
+
|
|
213
|
+
- **Selector Hooks**: Use precise selectors to minimize re-renders
|
|
214
|
+
- **Code Splitting**: Lazy load routes/components
|
|
215
|
+
- **Bundle Size**: Tree-shaking with Vite
|
|
216
|
+
|
|
217
|
+
### Backend
|
|
218
|
+
|
|
219
|
+
- **Connection Pooling**: Reuse database connections
|
|
220
|
+
- **Query Optimization**: Index frequently queried columns
|
|
221
|
+
- **Caching**: Consider Redis for production
|
|
222
|
+
|
|
223
|
+
### Real-time
|
|
224
|
+
|
|
225
|
+
- **WebSocket**: Connection pooling, message batching
|
|
226
|
+
- **SSE**: Automatic reconnection, event buffering
|
|
227
|
+
|
|
228
|
+
## Security Best Practices
|
|
229
|
+
|
|
230
|
+
1. **Input Validation**: Zod schemas on all endpoints
|
|
231
|
+
2. **SQL Injection**: Drizzle ORM parameterized queries
|
|
232
|
+
3. **CORS**: Whitelist origins in production
|
|
233
|
+
4. **Environment Variables**: Never commit `.env` files
|
|
234
|
+
5. **Error Messages**: Don't leak sensitive info
|
|
235
|
+
6. **WebSocket**: Validate all incoming messages
|
|
236
|
+
7. **SSE**: Rate limiting on event streams
|
|
237
|
+
|
|
238
|
+
## Migration Path
|
|
239
|
+
|
|
240
|
+
### From Mock to Real Backend
|
|
241
|
+
|
|
242
|
+
1. Set `USE_MOCK_SERVER = false` in `apiClient.ts`
|
|
243
|
+
2. Configure production API base URL
|
|
244
|
+
3. Deploy backend separately
|
|
245
|
+
4. Update CORS configuration
|
|
246
|
+
|
|
247
|
+
### From SQLite to PostgreSQL
|
|
248
|
+
|
|
249
|
+
1. Update `drizzle.config.ts`
|
|
250
|
+
2. Change `sqliteTable` to `pgTable`
|
|
251
|
+
3. Update column types
|
|
252
|
+
4. Run `drizzle-kit push`
|
|
253
|
+
|
|
254
|
+
### Adding Real-time Features
|
|
255
|
+
|
|
256
|
+
1. Define protocol schema (`WSProtocol` or `SSEProtocol`)
|
|
257
|
+
2. Create route with schema
|
|
258
|
+
3. Implement server-side logic
|
|
259
|
+
4. Use `$ws()` or `$sse()` on client
|
|
260
|
+
5. Add tests (with or without server)
|