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,647 @@
|
|
|
1
|
+
import { getRawClient } from './index'
|
|
2
|
+
import type { Client } from '@libsql/client'
|
|
3
|
+
|
|
4
|
+
export async function setupTestDatabase(): Promise<void> {
|
|
5
|
+
const client = await getRawClient()
|
|
6
|
+
|
|
7
|
+
if (!client || !('execute' in client)) {
|
|
8
|
+
throw new Error('Test database client not available')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const migrationSQL = `
|
|
12
|
+
CREATE TABLE IF NOT EXISTS todos (
|
|
13
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
14
|
+
title TEXT NOT NULL,
|
|
15
|
+
description TEXT,
|
|
16
|
+
status TEXT DEFAULT 'pending' NOT NULL,
|
|
17
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
18
|
+
updated_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS todo_attachments (
|
|
22
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
23
|
+
todo_id INTEGER NOT NULL,
|
|
24
|
+
file_name TEXT NOT NULL,
|
|
25
|
+
original_name TEXT NOT NULL,
|
|
26
|
+
mime_type TEXT NOT NULL,
|
|
27
|
+
size INTEGER NOT NULL,
|
|
28
|
+
path TEXT NOT NULL,
|
|
29
|
+
uploaded_by TEXT,
|
|
30
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
31
|
+
FOREIGN KEY (todo_id) REFERENCES todos(id) ON DELETE CASCADE
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE TABLE IF NOT EXISTS notifications (
|
|
35
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
36
|
+
type TEXT NOT NULL,
|
|
37
|
+
title TEXT NOT NULL,
|
|
38
|
+
message TEXT NOT NULL,
|
|
39
|
+
read INTEGER DEFAULT false NOT NULL,
|
|
40
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS permissions (
|
|
44
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
45
|
+
code TEXT NOT NULL UNIQUE,
|
|
46
|
+
name TEXT NOT NULL,
|
|
47
|
+
label TEXT NOT NULL,
|
|
48
|
+
category TEXT NOT NULL,
|
|
49
|
+
description TEXT,
|
|
50
|
+
sort_order INTEGER DEFAULT 0,
|
|
51
|
+
is_active INTEGER DEFAULT true,
|
|
52
|
+
created_at INTEGER,
|
|
53
|
+
updated_at INTEGER
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
CREATE TABLE IF NOT EXISTS roles (
|
|
57
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
58
|
+
code TEXT NOT NULL UNIQUE,
|
|
59
|
+
name TEXT NOT NULL,
|
|
60
|
+
label TEXT NOT NULL,
|
|
61
|
+
description TEXT,
|
|
62
|
+
is_system INTEGER DEFAULT false,
|
|
63
|
+
is_active INTEGER DEFAULT true,
|
|
64
|
+
sort_order INTEGER DEFAULT 0,
|
|
65
|
+
created_at INTEGER,
|
|
66
|
+
updated_at INTEGER
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
CREATE TABLE IF NOT EXISTS role_permissions (
|
|
70
|
+
role_id TEXT NOT NULL,
|
|
71
|
+
permission_id TEXT NOT NULL,
|
|
72
|
+
created_at INTEGER,
|
|
73
|
+
PRIMARY KEY(role_id, permission_id),
|
|
74
|
+
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
|
|
75
|
+
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
CREATE TABLE IF NOT EXISTS user_roles (
|
|
79
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
80
|
+
user_id TEXT NOT NULL,
|
|
81
|
+
role_id TEXT NOT NULL,
|
|
82
|
+
assigned_by TEXT,
|
|
83
|
+
assigned_at INTEGER,
|
|
84
|
+
expires_at INTEGER,
|
|
85
|
+
is_active INTEGER DEFAULT true,
|
|
86
|
+
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
CREATE TABLE IF NOT EXISTS routes (
|
|
90
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
91
|
+
path TEXT NOT NULL,
|
|
92
|
+
method TEXT NOT NULL,
|
|
93
|
+
name TEXT,
|
|
94
|
+
description TEXT,
|
|
95
|
+
module TEXT,
|
|
96
|
+
is_public INTEGER DEFAULT false,
|
|
97
|
+
is_active INTEGER DEFAULT true,
|
|
98
|
+
created_at INTEGER,
|
|
99
|
+
updated_at INTEGER
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
CREATE TABLE IF NOT EXISTS permission_routes (
|
|
103
|
+
permission_id TEXT NOT NULL,
|
|
104
|
+
route_id TEXT NOT NULL,
|
|
105
|
+
created_at INTEGER,
|
|
106
|
+
PRIMARY KEY(permission_id, route_id),
|
|
107
|
+
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
|
|
108
|
+
FOREIGN KEY (route_id) REFERENCES routes(id) ON DELETE CASCADE
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
CREATE TABLE IF NOT EXISTS permission_audit_logs (
|
|
112
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
113
|
+
user_id TEXT NOT NULL,
|
|
114
|
+
action TEXT NOT NULL,
|
|
115
|
+
resource_type TEXT NOT NULL,
|
|
116
|
+
resource_id TEXT,
|
|
117
|
+
old_value TEXT,
|
|
118
|
+
new_value TEXT,
|
|
119
|
+
ip_address TEXT,
|
|
120
|
+
user_agent TEXT,
|
|
121
|
+
created_at INTEGER
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
CREATE TABLE IF NOT EXISTS orders (
|
|
125
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
126
|
+
order_no TEXT NOT NULL,
|
|
127
|
+
customer_name TEXT NOT NULL,
|
|
128
|
+
customer_email TEXT NOT NULL,
|
|
129
|
+
product_name TEXT NOT NULL,
|
|
130
|
+
amount INTEGER NOT NULL,
|
|
131
|
+
status TEXT DEFAULT 'pending' NOT NULL,
|
|
132
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
133
|
+
updated_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
CREATE TABLE IF NOT EXISTS tickets (
|
|
137
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
138
|
+
ticket_no TEXT NOT NULL,
|
|
139
|
+
customer_name TEXT NOT NULL,
|
|
140
|
+
customer_email TEXT NOT NULL,
|
|
141
|
+
subject TEXT NOT NULL,
|
|
142
|
+
description TEXT NOT NULL,
|
|
143
|
+
status TEXT DEFAULT 'open' NOT NULL,
|
|
144
|
+
priority TEXT DEFAULT 'medium' NOT NULL,
|
|
145
|
+
category TEXT NOT NULL,
|
|
146
|
+
assigned_to TEXT,
|
|
147
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
148
|
+
updated_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
CREATE TABLE IF NOT EXISTS ticket_replies (
|
|
152
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
153
|
+
ticket_id INTEGER NOT NULL,
|
|
154
|
+
content TEXT NOT NULL,
|
|
155
|
+
author TEXT NOT NULL,
|
|
156
|
+
is_customer INTEGER DEFAULT 0 NOT NULL,
|
|
157
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
158
|
+
FOREIGN KEY (ticket_id) REFERENCES tickets(id) ON DELETE CASCADE
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
CREATE TABLE IF NOT EXISTS disputes (
|
|
162
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
163
|
+
dispute_no TEXT NOT NULL,
|
|
164
|
+
order_id TEXT NOT NULL,
|
|
165
|
+
order_no TEXT NOT NULL,
|
|
166
|
+
customer_name TEXT NOT NULL,
|
|
167
|
+
customer_email TEXT NOT NULL,
|
|
168
|
+
type TEXT NOT NULL,
|
|
169
|
+
status TEXT DEFAULT 'pending' NOT NULL,
|
|
170
|
+
description TEXT NOT NULL,
|
|
171
|
+
resolution TEXT,
|
|
172
|
+
amount INTEGER NOT NULL,
|
|
173
|
+
resolved_at INTEGER,
|
|
174
|
+
resolved_by TEXT,
|
|
175
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
176
|
+
updated_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
CREATE TABLE IF NOT EXISTS contents (
|
|
180
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
181
|
+
title TEXT NOT NULL,
|
|
182
|
+
body TEXT NOT NULL,
|
|
183
|
+
excerpt TEXT,
|
|
184
|
+
category TEXT NOT NULL,
|
|
185
|
+
tags TEXT,
|
|
186
|
+
status TEXT DEFAULT 'draft' NOT NULL,
|
|
187
|
+
author TEXT NOT NULL,
|
|
188
|
+
view_count INTEGER DEFAULT 0 NOT NULL,
|
|
189
|
+
like_count INTEGER DEFAULT 0 NOT NULL,
|
|
190
|
+
published_at INTEGER,
|
|
191
|
+
created_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL,
|
|
192
|
+
updated_at INTEGER DEFAULT (unixepoch() * 1000) NOT NULL
|
|
193
|
+
);
|
|
194
|
+
`
|
|
195
|
+
|
|
196
|
+
const statements = migrationSQL.split(';').filter(s => s.trim())
|
|
197
|
+
|
|
198
|
+
for (const statement of statements) {
|
|
199
|
+
if (statement.trim()) {
|
|
200
|
+
try {
|
|
201
|
+
await client.execute(statement)
|
|
202
|
+
} catch {
|
|
203
|
+
// Ignore errors for existing tables/indexes
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Insert default roles and permissions
|
|
209
|
+
await seedTestData(client)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function seedTestData(client: Client): Promise<void> {
|
|
213
|
+
// Insert default roles - names must match test expectations
|
|
214
|
+
const roles = [
|
|
215
|
+
{
|
|
216
|
+
id: 'role_super_admin',
|
|
217
|
+
code: 'super_admin',
|
|
218
|
+
name: '超级管理员',
|
|
219
|
+
label: '超级管理员',
|
|
220
|
+
is_system: 1,
|
|
221
|
+
sort_order: 1,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: 'role_admin',
|
|
225
|
+
code: 'admin',
|
|
226
|
+
name: '管理员',
|
|
227
|
+
label: '管理员',
|
|
228
|
+
is_system: 1,
|
|
229
|
+
sort_order: 2,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
id: 'role_user',
|
|
233
|
+
code: 'user',
|
|
234
|
+
name: '普通用户',
|
|
235
|
+
label: '普通用户',
|
|
236
|
+
is_system: 0,
|
|
237
|
+
sort_order: 3,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: 'role_customer_service',
|
|
241
|
+
code: 'customer_service',
|
|
242
|
+
name: '客服人员',
|
|
243
|
+
label: '客服',
|
|
244
|
+
is_system: 0,
|
|
245
|
+
sort_order: 4,
|
|
246
|
+
},
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
for (const role of roles) {
|
|
250
|
+
try {
|
|
251
|
+
await client.execute({
|
|
252
|
+
sql: `INSERT OR IGNORE INTO roles (id, code, name, label, is_system, is_active, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
253
|
+
args: [
|
|
254
|
+
role.id,
|
|
255
|
+
role.code,
|
|
256
|
+
role.name,
|
|
257
|
+
role.label,
|
|
258
|
+
role.is_system,
|
|
259
|
+
1,
|
|
260
|
+
role.sort_order,
|
|
261
|
+
Date.now(),
|
|
262
|
+
Date.now(),
|
|
263
|
+
],
|
|
264
|
+
})
|
|
265
|
+
} catch {
|
|
266
|
+
// Ignore duplicate errors
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Insert default permissions - user category (4 permissions)
|
|
271
|
+
const userPermissions = [
|
|
272
|
+
{
|
|
273
|
+
id: 'perm_user_view',
|
|
274
|
+
code: 'user:view',
|
|
275
|
+
name: '查看用户',
|
|
276
|
+
label: '查看用户',
|
|
277
|
+
category: 'user',
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: 'perm_user_create',
|
|
281
|
+
code: 'user:create',
|
|
282
|
+
name: '创建用户',
|
|
283
|
+
label: '创建用户',
|
|
284
|
+
category: 'user',
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
id: 'perm_user_update',
|
|
288
|
+
code: 'user:update',
|
|
289
|
+
name: '更新用户',
|
|
290
|
+
label: '更新用户',
|
|
291
|
+
category: 'user',
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: 'perm_user_delete',
|
|
295
|
+
code: 'user:delete',
|
|
296
|
+
name: '删除用户',
|
|
297
|
+
label: '删除用户',
|
|
298
|
+
category: 'user',
|
|
299
|
+
},
|
|
300
|
+
]
|
|
301
|
+
|
|
302
|
+
// content category (4 permissions)
|
|
303
|
+
const contentPermissions = [
|
|
304
|
+
{
|
|
305
|
+
id: 'perm_content_view',
|
|
306
|
+
code: 'content:view',
|
|
307
|
+
name: '查看内容',
|
|
308
|
+
label: '查看内容',
|
|
309
|
+
category: 'content',
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
id: 'perm_content_create',
|
|
313
|
+
code: 'content:create',
|
|
314
|
+
name: '创建内容',
|
|
315
|
+
label: '创建内容',
|
|
316
|
+
category: 'content',
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
id: 'perm_content_update',
|
|
320
|
+
code: 'content:update',
|
|
321
|
+
name: '更新内容',
|
|
322
|
+
label: '更新内容',
|
|
323
|
+
category: 'content',
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: 'perm_content_delete',
|
|
327
|
+
code: 'content:delete',
|
|
328
|
+
name: '删除内容',
|
|
329
|
+
label: '删除内容',
|
|
330
|
+
category: 'content',
|
|
331
|
+
},
|
|
332
|
+
]
|
|
333
|
+
|
|
334
|
+
// system category (3 permissions)
|
|
335
|
+
const systemPermissions = [
|
|
336
|
+
{
|
|
337
|
+
id: 'perm_system_settings',
|
|
338
|
+
code: 'system:settings',
|
|
339
|
+
name: '系统设置',
|
|
340
|
+
label: '系统设置',
|
|
341
|
+
category: 'system',
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: 'perm_system_logs',
|
|
345
|
+
code: 'system:logs',
|
|
346
|
+
name: '查看日志',
|
|
347
|
+
label: '查看日志',
|
|
348
|
+
category: 'system',
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
id: 'perm_system_backup',
|
|
352
|
+
code: 'system:backup',
|
|
353
|
+
name: '系统备份',
|
|
354
|
+
label: '系统备份',
|
|
355
|
+
category: 'system',
|
|
356
|
+
},
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
// order category (5 permissions)
|
|
360
|
+
const orderPermissions = [
|
|
361
|
+
{
|
|
362
|
+
id: 'perm_order_view',
|
|
363
|
+
code: 'order:view',
|
|
364
|
+
name: '查看订单',
|
|
365
|
+
label: '查看订单',
|
|
366
|
+
category: 'order',
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
id: 'perm_order_create',
|
|
370
|
+
code: 'order:create',
|
|
371
|
+
name: '创建订单',
|
|
372
|
+
label: '创建订单',
|
|
373
|
+
category: 'order',
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
id: 'perm_order_edit',
|
|
377
|
+
code: 'order:edit',
|
|
378
|
+
name: '编辑订单',
|
|
379
|
+
label: '编辑订单',
|
|
380
|
+
category: 'order',
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
id: 'perm_order_delete',
|
|
384
|
+
code: 'order:delete',
|
|
385
|
+
name: '删除订单',
|
|
386
|
+
label: '删除订单',
|
|
387
|
+
category: 'order',
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
id: 'perm_order_process',
|
|
391
|
+
code: 'order:process',
|
|
392
|
+
name: '处理订单',
|
|
393
|
+
label: '处理订单',
|
|
394
|
+
category: 'order',
|
|
395
|
+
},
|
|
396
|
+
]
|
|
397
|
+
|
|
398
|
+
// ticket category (6 permissions)
|
|
399
|
+
const ticketPermissions = [
|
|
400
|
+
{
|
|
401
|
+
id: 'perm_ticket_view',
|
|
402
|
+
code: 'ticket:view',
|
|
403
|
+
name: '查看工单',
|
|
404
|
+
label: '查看工单',
|
|
405
|
+
category: 'ticket',
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
id: 'perm_ticket_create',
|
|
409
|
+
code: 'ticket:create',
|
|
410
|
+
name: '创建工单',
|
|
411
|
+
label: '创建工单',
|
|
412
|
+
category: 'ticket',
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
id: 'perm_ticket_edit',
|
|
416
|
+
code: 'ticket:edit',
|
|
417
|
+
name: '编辑工单',
|
|
418
|
+
label: '编辑工单',
|
|
419
|
+
category: 'ticket',
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
id: 'perm_ticket_delete',
|
|
423
|
+
code: 'ticket:delete',
|
|
424
|
+
name: '删除工单',
|
|
425
|
+
label: '删除工单',
|
|
426
|
+
category: 'ticket',
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
id: 'perm_ticket_reply',
|
|
430
|
+
code: 'ticket:reply',
|
|
431
|
+
name: '回复工单',
|
|
432
|
+
label: '回复工单',
|
|
433
|
+
category: 'ticket',
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
id: 'perm_ticket_close',
|
|
437
|
+
code: 'ticket:close',
|
|
438
|
+
name: '关闭工单',
|
|
439
|
+
label: '关闭工单',
|
|
440
|
+
category: 'ticket',
|
|
441
|
+
},
|
|
442
|
+
]
|
|
443
|
+
|
|
444
|
+
// data category (2 permissions)
|
|
445
|
+
const dataPermissions = [
|
|
446
|
+
{
|
|
447
|
+
id: 'perm_data_export',
|
|
448
|
+
code: 'data:export',
|
|
449
|
+
name: '导出数据',
|
|
450
|
+
label: '导出数据',
|
|
451
|
+
category: 'data',
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
id: 'perm_data_import',
|
|
455
|
+
code: 'data:import',
|
|
456
|
+
name: '导入数据',
|
|
457
|
+
label: '导入数据',
|
|
458
|
+
category: 'data',
|
|
459
|
+
},
|
|
460
|
+
]
|
|
461
|
+
|
|
462
|
+
// dispute category (5 permissions)
|
|
463
|
+
const disputePermissions = [
|
|
464
|
+
{
|
|
465
|
+
id: 'perm_dispute_view',
|
|
466
|
+
code: 'dispute:view',
|
|
467
|
+
name: '查看争议',
|
|
468
|
+
label: '查看争议',
|
|
469
|
+
category: 'dispute',
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
id: 'perm_dispute_create',
|
|
473
|
+
code: 'dispute:create',
|
|
474
|
+
name: '创建争议',
|
|
475
|
+
label: '创建争议',
|
|
476
|
+
category: 'dispute',
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
id: 'perm_dispute_edit',
|
|
480
|
+
code: 'dispute:edit',
|
|
481
|
+
name: '编辑争议',
|
|
482
|
+
label: '编辑争议',
|
|
483
|
+
category: 'dispute',
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
id: 'perm_dispute_delete',
|
|
487
|
+
code: 'dispute:delete',
|
|
488
|
+
name: '删除争议',
|
|
489
|
+
label: '删除争议',
|
|
490
|
+
category: 'dispute',
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
id: 'perm_dispute_resolve',
|
|
494
|
+
code: 'dispute:resolve',
|
|
495
|
+
name: '解决争议',
|
|
496
|
+
label: '解决争议',
|
|
497
|
+
category: 'dispute',
|
|
498
|
+
},
|
|
499
|
+
]
|
|
500
|
+
|
|
501
|
+
// Combine all permissions
|
|
502
|
+
const allPermissions = [
|
|
503
|
+
...userPermissions,
|
|
504
|
+
...contentPermissions,
|
|
505
|
+
...systemPermissions,
|
|
506
|
+
...orderPermissions,
|
|
507
|
+
...ticketPermissions,
|
|
508
|
+
...dataPermissions,
|
|
509
|
+
...disputePermissions,
|
|
510
|
+
]
|
|
511
|
+
|
|
512
|
+
for (const perm of allPermissions) {
|
|
513
|
+
try {
|
|
514
|
+
await client.execute({
|
|
515
|
+
sql: `INSERT OR IGNORE INTO permissions (id, code, name, label, category, is_active, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
516
|
+
args: [
|
|
517
|
+
perm.id,
|
|
518
|
+
perm.code,
|
|
519
|
+
perm.name,
|
|
520
|
+
perm.label,
|
|
521
|
+
perm.category,
|
|
522
|
+
1,
|
|
523
|
+
0,
|
|
524
|
+
Date.now(),
|
|
525
|
+
Date.now(),
|
|
526
|
+
],
|
|
527
|
+
})
|
|
528
|
+
} catch {
|
|
529
|
+
// Ignore duplicate errors
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Assign permissions to roles
|
|
534
|
+
// Super admin gets all permissions
|
|
535
|
+
for (const perm of allPermissions) {
|
|
536
|
+
try {
|
|
537
|
+
await client.execute({
|
|
538
|
+
sql: `INSERT OR IGNORE INTO role_permissions (role_id, permission_id, created_at) VALUES (?, ?, ?)`,
|
|
539
|
+
args: ['role_super_admin', perm.id, Date.now()],
|
|
540
|
+
})
|
|
541
|
+
} catch {
|
|
542
|
+
// Ignore duplicate errors
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Admin gets most permissions except system settings
|
|
547
|
+
for (const perm of allPermissions) {
|
|
548
|
+
if (perm.code !== 'system:settings') {
|
|
549
|
+
try {
|
|
550
|
+
await client.execute({
|
|
551
|
+
sql: `INSERT OR IGNORE INTO role_permissions (role_id, permission_id, created_at) VALUES (?, ?, ?)`,
|
|
552
|
+
args: ['role_admin', perm.id, Date.now()],
|
|
553
|
+
})
|
|
554
|
+
} catch {
|
|
555
|
+
// Ignore duplicate errors
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Customer service gets view permissions for user, content, order, ticket + reply and close for ticket
|
|
561
|
+
const customerServicePermissions = [
|
|
562
|
+
'perm_user_view',
|
|
563
|
+
'perm_content_view',
|
|
564
|
+
'perm_order_view',
|
|
565
|
+
'perm_order_create',
|
|
566
|
+
'perm_order_edit',
|
|
567
|
+
'perm_order_delete',
|
|
568
|
+
'perm_order_process',
|
|
569
|
+
'perm_ticket_view',
|
|
570
|
+
'perm_ticket_create',
|
|
571
|
+
'perm_ticket_edit',
|
|
572
|
+
'perm_ticket_delete',
|
|
573
|
+
'perm_ticket_reply',
|
|
574
|
+
'perm_ticket_close',
|
|
575
|
+
'perm_dispute_view',
|
|
576
|
+
'perm_dispute_create',
|
|
577
|
+
'perm_dispute_edit',
|
|
578
|
+
'perm_dispute_delete',
|
|
579
|
+
'perm_dispute_resolve',
|
|
580
|
+
]
|
|
581
|
+
for (const permId of customerServicePermissions) {
|
|
582
|
+
try {
|
|
583
|
+
await client.execute({
|
|
584
|
+
sql: `INSERT OR IGNORE INTO role_permissions (role_id, permission_id, created_at) VALUES (?, ?, ?)`,
|
|
585
|
+
args: ['role_customer_service', permId, Date.now()],
|
|
586
|
+
})
|
|
587
|
+
} catch {
|
|
588
|
+
// Ignore duplicate errors
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Assign test user-role mappings for dev token users
|
|
593
|
+
const testUserRoles = [
|
|
594
|
+
{ userId: 'super-admin-1', roleId: 'role_super_admin' },
|
|
595
|
+
{ userId: 'customer-service-1', roleId: 'role_customer_service' },
|
|
596
|
+
{ userId: 'user-1', roleId: 'role_user' },
|
|
597
|
+
]
|
|
598
|
+
for (const mapping of testUserRoles) {
|
|
599
|
+
try {
|
|
600
|
+
await client.execute({
|
|
601
|
+
sql: `INSERT OR IGNORE INTO user_roles (id, user_id, role_id, is_active, assigned_at) VALUES (?, ?, ?, ?, ?)`,
|
|
602
|
+
args: [`ur_${mapping.userId}`, mapping.userId, mapping.roleId, 1, Date.now()],
|
|
603
|
+
})
|
|
604
|
+
} catch {
|
|
605
|
+
// Ignore duplicate errors
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// User gets limited permissions - view content and order
|
|
610
|
+
const userPermissionsList = ['perm_content_view', 'perm_order_view']
|
|
611
|
+
for (const permId of userPermissionsList) {
|
|
612
|
+
try {
|
|
613
|
+
await client.execute({
|
|
614
|
+
sql: `INSERT OR IGNORE INTO role_permissions (role_id, permission_id, created_at) VALUES (?, ?, ?)`,
|
|
615
|
+
args: ['role_user', permId, Date.now()],
|
|
616
|
+
})
|
|
617
|
+
} catch {
|
|
618
|
+
// Ignore duplicate errors
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export async function cleanupTestDatabase(): Promise<void> {
|
|
624
|
+
const client = await getRawClient()
|
|
625
|
+
|
|
626
|
+
if (client && 'execute' in client) {
|
|
627
|
+
try {
|
|
628
|
+
await client.execute('DELETE FROM todo_attachments')
|
|
629
|
+
} catch {
|
|
630
|
+
// Table may not exist in some test environments
|
|
631
|
+
}
|
|
632
|
+
await client.execute('DELETE FROM todos')
|
|
633
|
+
await client.execute('DELETE FROM notifications')
|
|
634
|
+
await client.execute('DELETE FROM permission_routes')
|
|
635
|
+
await client.execute('DELETE FROM permission_audit_logs')
|
|
636
|
+
await client.execute('DELETE FROM role_permissions')
|
|
637
|
+
await client.execute('DELETE FROM user_roles')
|
|
638
|
+
await client.execute('DELETE FROM permissions')
|
|
639
|
+
await client.execute('DELETE FROM roles')
|
|
640
|
+
await client.execute('DELETE FROM routes')
|
|
641
|
+
await client.execute('DELETE FROM ticket_replies')
|
|
642
|
+
await client.execute('DELETE FROM tickets')
|
|
643
|
+
await client.execute('DELETE FROM orders')
|
|
644
|
+
await client.execute('DELETE FROM disputes')
|
|
645
|
+
await client.execute('DELETE FROM contents')
|
|
646
|
+
}
|
|
647
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @framework-baseline e350401421193896
|
|
3
|
+
* @framework-modify
|
|
4
|
+
* @reason 统一错误响应格式为 JSON,确保所有错误都返回结构化数据;移除冗余的 globalThis 设置
|
|
5
|
+
* @impact 影响 Cloudflare Workers 环境的错误响应格式
|
|
6
|
+
*
|
|
7
|
+
* Note: In Cloudflare Workers, each request runs in its own isolate,
|
|
8
|
+
* so globalThis is request-scoped and there's no race condition risk.
|
|
9
|
+
* The middleware sets the DB binding for each request.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createApp } from '../app'
|
|
13
|
+
import type { AppBindings } from '../types/bindings'
|
|
14
|
+
import { getDb } from '../db/driver-cloudflare'
|
|
15
|
+
import { RealtimeDurableObject } from '@server/core'
|
|
16
|
+
import { setRuntimeAdapter } from '@server/core/runtime'
|
|
17
|
+
import { getCloudflareRuntimeAdapter } from '@server/core/runtime-cloudflare'
|
|
18
|
+
|
|
19
|
+
export interface CloudflareBindings extends AppBindings {
|
|
20
|
+
DB: D1Database
|
|
21
|
+
REALTIME_DO: DurableObjectNamespace
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const runtimeAdapter = getCloudflareRuntimeAdapter()
|
|
25
|
+
setRuntimeAdapter(runtimeAdapter)
|
|
26
|
+
|
|
27
|
+
const app = createApp<CloudflareBindings>()
|
|
28
|
+
|
|
29
|
+
const wrappedApp = app
|
|
30
|
+
.use('*', async (c, next) => {
|
|
31
|
+
;(globalThis as unknown as { DB: D1Database }).DB = c.env.DB
|
|
32
|
+
await next()
|
|
33
|
+
})
|
|
34
|
+
.get('/', c =>
|
|
35
|
+
c.json({
|
|
36
|
+
name: 'Biomimic Todo App',
|
|
37
|
+
version: '0.1.0',
|
|
38
|
+
environment: 'cloudflare-workers',
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
.onError((err, c) => {
|
|
42
|
+
console.error('Server error:', err)
|
|
43
|
+
c.res.headers.set('Content-Type', 'application/json')
|
|
44
|
+
const statusCode =
|
|
45
|
+
err instanceof Error && 'status' in err ? (err as { status: number }).status : 500
|
|
46
|
+
const message = err.message || 'Internal server error'
|
|
47
|
+
const responseStatus = statusCode || 500
|
|
48
|
+
return c.json({ success: false as const, error: message, status: responseStatus }, responseStatus as 500)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export default {
|
|
52
|
+
fetch: async (request: Request, env: CloudflareBindings, ctx: ExecutionContext) => {
|
|
53
|
+
const url = new URL(request.url)
|
|
54
|
+
|
|
55
|
+
if (url.pathname.startsWith('/api/') || url.pathname === '/health') {
|
|
56
|
+
return wrappedApp.fetch(request, env, ctx)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (env.ASSETS) {
|
|
60
|
+
const assetResponse = await env.ASSETS.fetch(request)
|
|
61
|
+
if (assetResponse.status !== 404) {
|
|
62
|
+
return assetResponse
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return wrappedApp.fetch(request, env, ctx)
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { RealtimeDurableObject, getDb }
|
|
71
|
+
export type AppType = typeof wrappedApp
|