@etus/bhono-app 0.1.5 → 0.1.7
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/dist/index.js +0 -0
- package/package.json +7 -2
- package/templates/base/.claude/commands/check-skill-rules.md +112 -29
- package/templates/base/.claude/commands/linear/implement-issue.md +383 -55
- package/templates/base/.claude/commands/ship.md +77 -13
- package/templates/base/.claude/hooks/package-lock.json +0 -419
- package/templates/base/.claude/hooks/skill-activation-prompt.ts +185 -113
- package/templates/base/.claude/hooks/skill-tool-guard.sh +6 -0
- package/templates/base/.claude/hooks/skill-tool-guard.ts +198 -0
- package/templates/base/.claude/scripts/validate-skill-rules.sh +55 -32
- package/templates/base/.claude/settings.json +18 -11
- package/templates/base/.claude/skills/skill-rules.json +326 -173
- package/templates/base/.env.example +3 -0
- package/templates/base/CLAUDE.md +5 -5
- package/templates/base/README.md +40 -27
- package/templates/base/config/eslint.config.js +1 -0
- package/templates/base/config/wrangler.json +16 -17
- package/templates/base/docs/SETUP-GUIDE.md +566 -0
- package/templates/base/docs/app_spec.txt +13 -10
- package/templates/base/docs/architecture/README.md +162 -5
- package/templates/base/docs/architecture/api-catalog.md +575 -0
- package/templates/base/docs/architecture/c4-component.md +309 -0
- package/templates/base/docs/architecture/c4-container.md +183 -0
- package/templates/base/docs/architecture/c4-context.md +106 -0
- package/templates/base/docs/architecture/data-requirements.md +4 -3
- package/templates/base/docs/architecture/db-bootstrap.md +39 -0
- package/templates/base/docs/architecture/dependencies.md +327 -0
- package/templates/base/docs/architecture/drizzle-migration-plan.md +125 -0
- package/templates/base/docs/architecture/erd.md +1 -1
- package/templates/base/docs/architecture/sql-standards.md +100 -0
- package/templates/base/docs/architecture/tech-debt.md +184 -0
- package/templates/base/docs/testing.md +36 -29
- package/templates/base/package.json +26 -20
- package/templates/base/schema.sql +84 -0
- package/templates/base/scripts/capture-prod-session.ts +2 -2
- package/templates/base/scripts/init.sh +244 -59
- package/templates/base/scripts/sync-template.sh +104 -0
- package/templates/base/src/client/hooks/use-auth.ts +5 -0
- package/templates/base/src/client/routes/_authenticated/dashboard.tsx +1 -1
- package/templates/base/src/client/routes/index.tsx +1 -1
- package/templates/base/src/server/db/client.ts +3 -5
- package/templates/base/src/server/db/records.ts +81 -0
- package/templates/base/src/server/db/seed.ts +3 -2
- package/templates/base/src/server/db/sql.ts +116 -0
- package/templates/base/src/server/index.ts +17 -2
- package/templates/base/src/server/lib/audit.ts +74 -26
- package/templates/base/src/server/lib/audited-db.ts +219 -109
- package/templates/base/src/server/lib/transaction.ts +10 -16
- package/templates/base/src/server/middleware/account.ts +9 -16
- package/templates/base/src/server/middleware/auth.ts +102 -38
- package/templates/base/src/server/middleware/rate-limit.ts +8 -6
- package/templates/base/src/server/routes/accounts/handlers.ts +18 -6
- package/templates/base/src/server/routes/audits/handlers.ts +3 -1
- package/templates/base/src/server/routes/auth/handlers.ts +15 -10
- package/templates/base/src/server/routes/auth/test-login.ts +99 -45
- package/templates/base/src/server/routes/health/handlers.ts +4 -4
- package/templates/base/src/server/routes/index.ts +9 -0
- package/templates/base/src/server/routes/invitations/handlers.ts +9 -6
- package/templates/base/src/server/routes/openapi.ts +1 -1
- package/templates/base/src/server/routes/users/handlers.ts +21 -14
- package/templates/base/src/server/services/accounts.ts +242 -217
- package/templates/base/src/server/services/audits.ts +114 -61
- package/templates/base/src/server/services/auth.ts +310 -180
- package/templates/base/src/server/services/invitations.ts +282 -222
- package/templates/base/src/server/services/users.ts +383 -293
- package/templates/base/src/server/types/index.ts +1 -2
- package/templates/base/src/shared/types/api.ts +66 -198
- package/templates/base/tests/e2e/auth.setup.ts +1 -1
- package/templates/base/{src/server/__tests__/fixtures.ts → tests/fixtures/server.ts} +3 -3
- package/templates/base/{src/client/__tests__/setup-browser.ts → tests/helpers/client-setup-browser.ts} +2 -2
- package/templates/base/{src/client/__tests__/setup.ts → tests/helpers/client-setup.ts} +1 -1
- package/templates/base/{src/client/__tests__/test-utils.tsx → tests/helpers/client-test-utils.tsx} +2 -2
- package/templates/base/{src/server/__tests__/setup.ts → tests/helpers/server.ts} +9 -9
- package/templates/base/tests/integration/accounts/crud.test.ts +2 -11
- package/templates/base/tests/integration/audits/list.test.ts +2 -11
- package/templates/base/tests/integration/auth/auth-service.test.ts +1 -10
- package/templates/base/tests/integration/auth/invitation-token.test.ts +2 -11
- package/templates/base/tests/integration/auth/logout.test.ts +2 -11
- package/templates/base/tests/integration/auth/oauth.test.ts +23 -42
- package/templates/base/tests/integration/auth/refresh-token.test.ts +1 -9
- package/templates/base/tests/integration/auth/session-expiry.test.ts +1 -9
- package/templates/base/tests/integration/auth/session.test.ts +2 -11
- package/templates/base/tests/integration/auth/super-admin.test.ts +1 -9
- package/templates/base/tests/integration/authorization/analytics-role.test.ts +2 -11
- package/templates/base/tests/integration/authorization/billing-role.test.ts +2 -11
- package/templates/base/tests/integration/authorization/guards-roles.test.ts +1 -9
- package/templates/base/tests/integration/authorization/multi-tenancy.test.ts +2 -11
- package/templates/base/tests/integration/authorization/roles.test.ts +2 -11
- package/templates/base/tests/integration/config/production-behavior.test.ts +2 -11
- package/templates/base/tests/integration/health/health.test.ts +25 -44
- package/templates/base/tests/integration/invitations/crud.test.ts +2 -11
- package/templates/base/tests/integration/invitations/email.test.ts +1 -9
- package/templates/base/tests/integration/middleware/auth.test.ts +3 -12
- package/templates/base/tests/integration/middleware/request-logger.test.ts +1 -9
- package/templates/base/tests/integration/performance/response-times.test.ts +1 -9
- package/templates/base/tests/integration/security/cookie-security.test.ts +2 -11
- package/templates/base/tests/integration/security/csrf-protection.test.ts +2 -11
- package/templates/base/tests/integration/security/log-sanitization.test.ts +1 -9
- package/templates/base/tests/integration/security/rate-limiting.test.ts +1 -9
- package/templates/base/tests/integration/security/sql-injection.test.ts +7 -18
- package/templates/base/tests/integration/security/xss-prevention.test.ts +2 -11
- package/templates/base/tests/integration/setup.ts +13 -90
- package/templates/base/tests/integration/smoke.test.ts +3 -2
- package/templates/base/tests/integration/storage/upload.test.ts +2 -11
- package/templates/base/tests/integration/storage/validation.test.ts +2 -11
- package/templates/base/tests/integration/users/crud.test.ts +2 -11
- package/templates/base/tests/integration/users/list.test.ts +2 -11
- package/templates/base/tests/integration/vitest.config.ts +2 -9
- package/templates/base/{src/server/__tests__ → tests}/mocks/db.ts +1 -1
- package/templates/base/{src/server/__tests__ → tests}/mocks/index.ts +1 -1
- package/templates/base/{src/server/__tests__ → tests}/mocks/kv.ts +1 -1
- package/templates/base/{src/server/__tests__ → tests}/mocks/r2.ts +1 -1
- package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/sidebar.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/avatar.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client/components/ui}/button.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/card.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/dialog.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/input.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/loading-skeleton.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/skeleton.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/sonner.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/tabs.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/account.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/integrations.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/settings.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/team.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/authenticated-layout.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/dashboard.test.tsx +1 -1
- package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/invite.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/login.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/navigation.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/root-layout.test.tsx +1 -1
- package/templates/base/{src/server/auth/__tests__ → tests/unit/server/auth}/guards.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/auth/permissions.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/auth/roles.test.ts +1 -1
- package/templates/base/tests/unit/server/db/sql.test.ts +68 -0
- package/templates/base/{src → tests/unit}/server/env.test.ts +1 -1
- package/templates/base/tests/unit/server/lib/audited-db.test.ts +78 -0
- package/templates/base/{src → tests/unit}/server/lib/email.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/errors.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/oauth.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/pagination.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/password.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/providers.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/r2-storage.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/lib/session.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/lib/tokens.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/transaction.test.ts +5 -14
- package/templates/base/{src → tests/unit}/server/middleware/account.test.ts +16 -24
- package/templates/base/tests/unit/server/middleware/auth.test.ts +647 -0
- package/templates/base/{src → tests/unit}/server/middleware/cors.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/middleware/error-handler.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/middleware/rate-limit.test.ts +3 -2
- package/templates/base/{src → tests/unit}/server/middleware/request-context.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/middleware/request-logger.test.ts +1 -1
- package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/db.test.ts +1 -1
- package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/kv.test.ts +1 -1
- package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/r2.test.ts +1 -1
- package/templates/base/{src/server/routes/accounts/__tests__ → tests/unit/server/routes/accounts}/handlers.test.ts +12 -12
- package/templates/base/{src/server/routes/audits/__tests__ → tests/unit/server/routes/audits}/handlers.test.ts +11 -11
- package/templates/base/{src/server/routes/auth/__tests__ → tests/unit/server/routes/auth}/handlers.test.ts +124 -13
- package/templates/base/{src/server/routes/health/__tests__ → tests/unit/server/routes/health}/handlers.test.ts +27 -23
- package/templates/base/{src/server/routes/invitations/__tests__ → tests/unit/server/routes/invitations}/handlers.test.ts +14 -17
- package/templates/base/{src/server/routes/storage/__tests__ → tests/unit/server/routes/storage}/handlers.test.ts +6 -6
- package/templates/base/{src/server/routes/users/__tests__ → tests/unit/server/routes/users}/handlers.test.ts +81 -17
- package/templates/base/tests/unit/server/services/accounts.test.ts +406 -0
- package/templates/base/tests/unit/server/services/audits.test.ts +360 -0
- package/templates/base/tests/unit/server/services/auth.test.ts +656 -0
- package/templates/base/tests/unit/server/services/invitations.test.ts +343 -0
- package/templates/base/tests/unit/server/services/users.test.ts +706 -0
- package/templates/base/{src/shared/schemas/__tests__ → tests/unit/shared}/schemas.test.ts +1 -1
- package/templates/base/tsconfig.json +2 -1
- package/templates/base/vite.config.ts +3 -1
- package/templates/base/vitest.config.browser.ts +3 -2
- package/templates/base/vitest.config.frontend.ts +3 -2
- package/templates/base/vitest.config.ts +7 -14
- package/templates/base/.claude/settings.local.json +0 -11
- package/templates/base/.github/workflows/test.yml +0 -127
- package/templates/base/auth-setup-error.png +0 -0
- package/templates/base/config/drizzle.config.ts +0 -10
- package/templates/base/pnpm-lock.yaml +0 -8175
- package/templates/base/src/server/db/schema/accounts.ts +0 -20
- package/templates/base/src/server/db/schema/audit-logs.ts +0 -26
- package/templates/base/src/server/db/schema/index.ts +0 -7
- package/templates/base/src/server/db/schema/invitations.ts +0 -30
- package/templates/base/src/server/db/schema/refresh-tokens.ts +0 -22
- package/templates/base/src/server/db/schema/user-accounts.ts +0 -25
- package/templates/base/src/server/db/schema/users.ts +0 -33
- package/templates/base/src/server/lib/audited-db.test.ts +0 -107
- package/templates/base/src/server/lib/schema-helpers.ts +0 -16
- package/templates/base/src/server/middleware/auth.test.ts +0 -345
- package/templates/base/src/server/services/__tests__/accounts.test.ts +0 -764
- package/templates/base/src/server/services/__tests__/audits.test.ts +0 -235
- package/templates/base/src/server/services/__tests__/auth.test.ts +0 -765
- package/templates/base/src/server/services/__tests__/invitations.test.ts +0 -704
- package/templates/base/src/server/services/__tests__/users.test.ts +0 -755
- package/templates/base/tests/e2e/_auth/.gitkeep +0 -0
- package/templates/base/tests/integration/lib/schema-helpers.test.ts +0 -129
- package/templates/base/tsconfig.tsbuildinfo +0 -1
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-can-be-collapsed-by-default-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-expands-when-collapsed-and-expand-button-is-clicked-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-logout-button-click-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-navigation-clicks-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-hides-navigation-labels-when-collapsed-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-highlights-active-route-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-renders-sidebar-navigation-items-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-shows-keyboard-shortcut-hint-when-expanded-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-info-when-authenticated-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-initials-in-avatar-fallback-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/error-boundary.test.tsx +0 -0
- /package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/error-fallback.test.tsx +0 -0
- /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-auth.test.tsx +0 -0
- /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-theme.test.tsx +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-dashboard-stats-cards-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-quick-action-cards-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-recent-activity-section-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-first-name-in-welcome-message-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-information-in-sidebar-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-render-dashboard-when-authenticated-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-show-navigation-sidebar-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-unauthenticated-should-redirect-to-login-when-not-authenticated-1.png +0 -0
- /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-accept-invitation-button-1.png +0 -0
- /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-decline-button-linking-to-homepage-1.png +0 -0
- /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-invitation-details--email--workspace--role--1.png +0 -0
- /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-have-a-logo-link-to-homepage-1.png +0 -0
- /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-render-invitation-page-with-inviter-name-and-workspace-1.png +0 -0
- /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-show-terms-of-service-and-privacy-policy-links-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-display-Google-OAuth-login-button-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-have-a-link-back-to-home-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-content-without-waiting-for-authentication-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-page-at--login-route-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-show-Terms-of-Service-and-Privacy-Policy-links-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-trigger-OAuth-flow-when-clicking-login-button-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-display-404-text-on-not-found-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-have-navigation-options-on-404-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-render-404-page-for-unknown-routes-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-account-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-integrations-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-settings-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-team-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-display-navigation-links-on-home-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-have-correct-link-destinations-on-home-page-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-home-page-without-authentication-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-login-page-without-authentication-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-dashboard-to-login-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-settings-to-login-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-team-to-login-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-render-Active-Sessions-section-with-session-cards-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-render-page-with-correct-title--Account--1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-API-Access-section-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-Connected-Accounts-section-with-Google-connected-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-Danger-Zone-section-with-delete-button-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-Security-section-with-Two-Factor-Authentication-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-API-documentation-section-should-display-API-documentation-link-section-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-Create-Webhook-Dialog-should-have-Add-Webhook-trigger-button-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-category-filters-should-display-all-category-buttons-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-all-integration-cards-with-names-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-category-badges-on-cards-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Configure-button-for-connected-integrations-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connect-button-for-not-connected-integrations-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connected-badge-for-connected-integrations-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Available-Integrations-section-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Webhooks-section-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-connected-count-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-page-description-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-search-input-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-render-with-correct-title--Integrations--1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-filter-integrations-based-on-search-query-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-search-by-description-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-show-no-results-message-when-search-has-no-matches-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-existing-webhook-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-events-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-last-delivery-info-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-success-status-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-have-Add-Webhook-button-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-connected-accounts-section-with-Google-provider-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-sessions-and-danger-zone-sections-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-all-notification-toggle-options-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-email-notifications-section-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-toggle-switches-for-notification-options-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-have-toggles-checked-by-default-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display--Save-Changes--button-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-personal-information-form-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-profile-picture-section-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-email-in-disabled-email-input-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-initials-in-avatar-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-name-in-the-name-input-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-all-three-tabs-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-page-description-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-render-with-correct-title--Settings--1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-show-Profile-tab-as-default-active-tab-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Account-tab-when-clicked-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Notifications-tab-when-clicked-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-display-Active-Members-section-with-member-count-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-display-Pending-Invitations-section-with-invitation-details-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-have-invite-member-button-that-can-be-clicked-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-render-page-with-correct-title-and-description-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-render-search-input-that-filters-team-members-1.png +0 -0
- /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-show-current-user-with---you---indicator-and-role-badge-1.png +0 -0
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/error-components.test.tsx +0 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# C4 Model - Level 3: Component Diagrams
|
|
2
|
+
|
|
3
|
+
> Shows how containers are made up of components and their relationships.
|
|
4
|
+
|
|
5
|
+
## Backend Components (Hono API)
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
C4Component
|
|
9
|
+
title Component Diagram - Hono API
|
|
10
|
+
|
|
11
|
+
Container_Boundary(api, "Hono API") {
|
|
12
|
+
Component(middleware, "Middleware Stack", "Hono Middleware", "Request processing pipeline")
|
|
13
|
+
Component(routes, "Route Handlers", "OpenAPI Routes", "HTTP endpoint handlers")
|
|
14
|
+
Component(services, "Service Layer", "TypeScript", "Business logic")
|
|
15
|
+
Component(auth, "Auth Module", "Guards + RBAC", "Authorization checks")
|
|
16
|
+
Component(db, "Database Layer", "SQL Helpers", "D1 data access")
|
|
17
|
+
Component(lib, "Utilities", "TypeScript", "Shared utilities")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
ContainerDb(d1, "D1", "SQLite")
|
|
21
|
+
ContainerDb(kv, "KV", "Sessions")
|
|
22
|
+
ContainerDb(r2, "R2", "Files")
|
|
23
|
+
|
|
24
|
+
Rel(middleware, routes, "Passes request")
|
|
25
|
+
Rel(routes, services, "Calls")
|
|
26
|
+
Rel(routes, auth, "Checks permissions")
|
|
27
|
+
Rel(services, db, "Queries")
|
|
28
|
+
Rel(services, lib, "Uses")
|
|
29
|
+
Rel(db, d1, "SQL")
|
|
30
|
+
Rel(middleware, kv, "Sessions")
|
|
31
|
+
Rel(services, r2, "Files")
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Middleware Stack [HIGH]
|
|
35
|
+
|
|
36
|
+
| Order | Middleware | File | Purpose |
|
|
37
|
+
|-------|------------|------|---------|
|
|
38
|
+
| 1 | Error Handler | `middleware/error-handler.ts` | Global error handling |
|
|
39
|
+
| 2 | Request Context | `middleware/request-context.ts` | Transaction ID, timing |
|
|
40
|
+
| 3 | Request Logger | `middleware/request-logger.ts` | Structured logging |
|
|
41
|
+
| 4 | CORS | `middleware/cors.ts` | Cross-origin requests |
|
|
42
|
+
| 5 | Rate Limiter | `middleware/rate-limit.ts` | Throttling protection |
|
|
43
|
+
| 6 | Session Auth | `middleware/auth.ts` | Session validation |
|
|
44
|
+
| 7 | Account Context | `middleware/account.ts` | Multi-tenant context |
|
|
45
|
+
|
|
46
|
+
### Middleware Flow
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Request
|
|
50
|
+
│
|
|
51
|
+
▼
|
|
52
|
+
┌──────────────────┐
|
|
53
|
+
│ Error Handler │ ◄── Catches all errors
|
|
54
|
+
└────────┬─────────┘
|
|
55
|
+
│
|
|
56
|
+
▼
|
|
57
|
+
┌──────────────────┐
|
|
58
|
+
│ Request Context │ ◄── Adds transactionId, startTime
|
|
59
|
+
└────────┬─────────┘
|
|
60
|
+
│
|
|
61
|
+
▼
|
|
62
|
+
┌──────────────────┐
|
|
63
|
+
│ Request Logger │ ◄── Logs request details
|
|
64
|
+
└────────┬─────────┘
|
|
65
|
+
│
|
|
66
|
+
▼
|
|
67
|
+
┌──────────────────┐
|
|
68
|
+
│ CORS │ ◄── Handles preflight
|
|
69
|
+
└────────┬─────────┘
|
|
70
|
+
│
|
|
71
|
+
▼
|
|
72
|
+
┌──────────────────┐
|
|
73
|
+
│ Rate Limiter │ ◄── Throttles excessive requests
|
|
74
|
+
└────────┬─────────┘
|
|
75
|
+
│
|
|
76
|
+
▼
|
|
77
|
+
┌──────────────────┐
|
|
78
|
+
│ Session Auth │ ◄── Validates session cookie
|
|
79
|
+
└────────┬─────────┘
|
|
80
|
+
│
|
|
81
|
+
▼
|
|
82
|
+
┌──────────────────┐
|
|
83
|
+
│ Account Context │ ◄── Sets current account
|
|
84
|
+
└────────┬─────────┘
|
|
85
|
+
│
|
|
86
|
+
▼
|
|
87
|
+
Route Handler
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Route Handlers [HIGH]
|
|
91
|
+
|
|
92
|
+
| Module | Path | Endpoints | Purpose |
|
|
93
|
+
|--------|------|-----------|---------|
|
|
94
|
+
| Auth | `/auth/*` | 6 | Authentication flows |
|
|
95
|
+
| Users | `/api/users/*` | 8 | User CRUD + bulk |
|
|
96
|
+
| Accounts | `/api/accounts/*` | 6 | Account CRUD |
|
|
97
|
+
| Invitations | `/api/invitations/*` | 3 | Team invitations |
|
|
98
|
+
| Audits | `/api/audits/*` | 1 | Audit log queries |
|
|
99
|
+
| Storage | `/api/storage/*` | 3 | File operations |
|
|
100
|
+
| Health | `/health/*` | 3 | Health probes |
|
|
101
|
+
|
|
102
|
+
### Route Structure
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
src/server/routes/
|
|
106
|
+
├── index.ts # API router composition
|
|
107
|
+
├── schemas.ts # Shared schemas
|
|
108
|
+
├── openapi.ts # OpenAPI config
|
|
109
|
+
├── api.ts # API router export
|
|
110
|
+
├── auth/
|
|
111
|
+
│ ├── index.ts # Auth router
|
|
112
|
+
│ ├── routes.ts # Route definitions (OpenAPI)
|
|
113
|
+
│ ├── handlers.ts # Request handlers
|
|
114
|
+
│ └── schemas.ts # Auth schemas
|
|
115
|
+
├── users/
|
|
116
|
+
│ ├── index.ts
|
|
117
|
+
│ ├── routes.ts
|
|
118
|
+
│ ├── handlers.ts
|
|
119
|
+
│ └── schemas.ts
|
|
120
|
+
├── accounts/
|
|
121
|
+
│ ├── index.ts
|
|
122
|
+
│ ├── routes.ts
|
|
123
|
+
│ ├── handlers.ts
|
|
124
|
+
│ └── schemas.ts
|
|
125
|
+
├── invitations/
|
|
126
|
+
│ ├── index.ts
|
|
127
|
+
│ ├── routes.ts
|
|
128
|
+
│ ├── handlers.ts
|
|
129
|
+
│ └── schemas.ts
|
|
130
|
+
├── audits/
|
|
131
|
+
│ ├── index.ts
|
|
132
|
+
│ ├── routes.ts
|
|
133
|
+
│ ├── handlers.ts
|
|
134
|
+
│ └── schemas.ts
|
|
135
|
+
├── storage/
|
|
136
|
+
│ ├── index.ts
|
|
137
|
+
│ ├── routes.ts
|
|
138
|
+
│ ├── handlers.ts
|
|
139
|
+
│ └── schemas.ts
|
|
140
|
+
└── health/
|
|
141
|
+
├── index.ts
|
|
142
|
+
├── routes.ts
|
|
143
|
+
└── handlers.ts
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Service Layer [HIGH]
|
|
147
|
+
|
|
148
|
+
| Service | File | Responsibilities |
|
|
149
|
+
|---------|------|------------------|
|
|
150
|
+
| AuthService | `services/auth.ts` | OAuth flow, session management, token refresh |
|
|
151
|
+
| UsersService | `services/users.ts` | User CRUD, account memberships |
|
|
152
|
+
| AccountsService | `services/accounts.ts` | Account CRUD, member management |
|
|
153
|
+
| InvitationsService | `services/invitations.ts` | Invitation lifecycle |
|
|
154
|
+
| AuditsService | `services/audits.ts` | Audit log queries |
|
|
155
|
+
|
|
156
|
+
### Service Pattern
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// Each service follows this pattern:
|
|
160
|
+
export class UsersService {
|
|
161
|
+
constructor(
|
|
162
|
+
private db: D1Database,
|
|
163
|
+
private context: RequestContext
|
|
164
|
+
) {}
|
|
165
|
+
|
|
166
|
+
async list(accountId: string, pagination: Pagination): Promise<PaginatedUsers> {
|
|
167
|
+
// Business logic + DB queries
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async create(data: CreateUser): Promise<User> {
|
|
171
|
+
// Validation + creation + audit logging
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Auth Module [HIGH]
|
|
177
|
+
|
|
178
|
+
| Component | File | Purpose |
|
|
179
|
+
|-----------|------|---------|
|
|
180
|
+
| Roles | `auth/roles.ts` | Role definitions and hierarchy |
|
|
181
|
+
| Permissions | `auth/permissions.ts` | Permission constants |
|
|
182
|
+
| Guards | `auth/guards.ts` | Authorization checks |
|
|
183
|
+
|
|
184
|
+
### Role Hierarchy
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
ADMIN
|
|
188
|
+
└── MANAGER
|
|
189
|
+
└── EDITOR
|
|
190
|
+
└── AUTHOR
|
|
191
|
+
└── VIEWER
|
|
192
|
+
|
|
193
|
+
BILLING (separate branch)
|
|
194
|
+
ANALYTICS (separate branch)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Guard Functions
|
|
198
|
+
|
|
199
|
+
| Guard | Purpose |
|
|
200
|
+
|-------|---------|
|
|
201
|
+
| `requireAuth()` | Ensures user is authenticated |
|
|
202
|
+
| `requireRole(role)` | Checks user has role or higher |
|
|
203
|
+
| `requirePermission(perm)` | Checks specific permission |
|
|
204
|
+
| `requireSuperAdmin()` | Checks super admin flag |
|
|
205
|
+
| `requireAccountMember()` | Verifies account membership |
|
|
206
|
+
|
|
207
|
+
## Database Layer [HIGH]
|
|
208
|
+
|
|
209
|
+
| Component | File | Purpose |
|
|
210
|
+
|-----------|------|---------|
|
|
211
|
+
| SQL Helpers | `db/sql.ts` | `queryOne`, `queryAll`, `execute` |
|
|
212
|
+
| Record Types | `db/records.ts` | TypeScript types for SQL results |
|
|
213
|
+
| Client | `db/client.ts` | D1 client wrapper |
|
|
214
|
+
| Seed | `db/seed.ts` | Test data generator |
|
|
215
|
+
|
|
216
|
+
### SQL Helper Pattern
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
// Type-safe SQL execution
|
|
220
|
+
const user = await queryOne<UserRecord>(db,
|
|
221
|
+
'SELECT * FROM users WHERE id = ?',
|
|
222
|
+
[userId]
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const users = await queryAll<UserRecord>(db,
|
|
226
|
+
'SELECT * FROM users WHERE account_id = ? LIMIT ? OFFSET ?',
|
|
227
|
+
[accountId, limit, offset]
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
await execute(db,
|
|
231
|
+
'UPDATE users SET name = ? WHERE id = ?',
|
|
232
|
+
[name, userId]
|
|
233
|
+
);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Utility Libraries [HIGH]
|
|
237
|
+
|
|
238
|
+
| Library | File | Purpose |
|
|
239
|
+
|---------|------|---------|
|
|
240
|
+
| OAuth | `lib/oauth.ts` | Google OAuth helpers |
|
|
241
|
+
| Session | `lib/session.ts` | Session create/validate/destroy |
|
|
242
|
+
| Tokens | `lib/tokens.ts` | Refresh token management |
|
|
243
|
+
| Audit | `lib/audit.ts` | Audit log creation |
|
|
244
|
+
| Email | `lib/email.ts` | SendGrid integration |
|
|
245
|
+
| Errors | `lib/errors.ts` | Custom error classes |
|
|
246
|
+
| Pagination | `lib/pagination.ts` | Pagination helpers |
|
|
247
|
+
| R2 Storage | `lib/r2-storage.ts` | File storage helpers |
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Frontend Components (React SPA)
|
|
252
|
+
|
|
253
|
+
```mermaid
|
|
254
|
+
C4Component
|
|
255
|
+
title Component Diagram - React SPA
|
|
256
|
+
|
|
257
|
+
Container_Boundary(spa, "React SPA") {
|
|
258
|
+
Component(router, "TanStack Router", "File-based routing", "Client-side navigation")
|
|
259
|
+
Component(auth, "Auth Provider", "React Context", "Authentication state")
|
|
260
|
+
Component(query, "React Query", "Data fetching", "Server state management")
|
|
261
|
+
Component(routes, "Route Components", "React", "Page components")
|
|
262
|
+
Component(ui, "UI Components", "Radix + Tailwind", "Reusable components")
|
|
263
|
+
Component(hooks, "Custom Hooks", "React", "Shared logic")
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
Container(api, "Hono API", "Backend")
|
|
267
|
+
|
|
268
|
+
Rel(router, routes, "Renders")
|
|
269
|
+
Rel(routes, auth, "Uses")
|
|
270
|
+
Rel(routes, query, "Fetches data")
|
|
271
|
+
Rel(routes, ui, "Composes")
|
|
272
|
+
Rel(routes, hooks, "Uses")
|
|
273
|
+
Rel(query, api, "REST calls")
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Frontend Route Structure [HIGH]
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
src/client/routes/
|
|
280
|
+
├── __root.tsx # Root layout
|
|
281
|
+
├── index.tsx # Landing page (/)
|
|
282
|
+
├── login.tsx # Login page (/login)
|
|
283
|
+
├── $.tsx # 404 catch-all
|
|
284
|
+
├── invite.$token.tsx # Invitation acceptance
|
|
285
|
+
└── _authenticated/ # Protected routes
|
|
286
|
+
├── dashboard.tsx # Dashboard (/dashboard)
|
|
287
|
+
├── account.tsx # Account page (/account)
|
|
288
|
+
├── team.tsx # Team management (/team)
|
|
289
|
+
├── settings.tsx # User settings (/settings)
|
|
290
|
+
└── integrations.tsx # Integrations (/integrations)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## UI Component Library [HIGH]
|
|
294
|
+
|
|
295
|
+
| Category | Components |
|
|
296
|
+
|----------|------------|
|
|
297
|
+
| **Layout** | Sidebar |
|
|
298
|
+
| **Feedback** | Sonner (Toasts), Loading Skeleton, Error Fallback |
|
|
299
|
+
| **Forms** | Input, Label, Form, Button |
|
|
300
|
+
| **Display** | Card, Badge, Avatar, Tabs |
|
|
301
|
+
| **Overlay** | Dialog |
|
|
302
|
+
| **Utility** | Separator, Skeleton |
|
|
303
|
+
|
|
304
|
+
## Custom Hooks [HIGH]
|
|
305
|
+
|
|
306
|
+
| Hook | File | Purpose |
|
|
307
|
+
|------|------|---------|
|
|
308
|
+
| `useAuth` | `hooks/use-auth.ts` | Authentication state + methods |
|
|
309
|
+
| `useTheme` | `hooks/use-theme.tsx` | Theme (dark/light) management |
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# C4 Model - Level 2: Container Diagram
|
|
2
|
+
|
|
3
|
+
> Shows the high-level shape of the software architecture and how responsibilities are distributed.
|
|
4
|
+
|
|
5
|
+
## Container Diagram
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
C4Container
|
|
9
|
+
title Container Diagram - BHono Platform
|
|
10
|
+
|
|
11
|
+
Person(user, "User", "SaaS platform user")
|
|
12
|
+
|
|
13
|
+
System_Boundary(bhono, "BHono Platform") {
|
|
14
|
+
Container(spa, "React SPA", "React 19, TanStack Router", "Single-page application providing the user interface")
|
|
15
|
+
Container(api, "Hono API", "Hono.js, TypeScript", "REST API handling business logic and data access")
|
|
16
|
+
ContainerDb(d1, "D1 Database", "SQLite at Edge", "Stores users, accounts, invitations, audit logs")
|
|
17
|
+
ContainerDb(kv, "KV Store", "Cloudflare KV", "Stores user sessions")
|
|
18
|
+
ContainerDb(r2, "R2 Storage", "Cloudflare R2", "Stores uploaded files")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
System_Ext(google, "Google OAuth", "Identity provider")
|
|
22
|
+
System_Ext(sendgrid, "SendGrid", "Email service")
|
|
23
|
+
|
|
24
|
+
Rel(user, spa, "Uses", "HTTPS")
|
|
25
|
+
Rel(spa, api, "API calls", "REST/JSON")
|
|
26
|
+
Rel(api, d1, "Reads/Writes", "SQL")
|
|
27
|
+
Rel(api, kv, "Sessions", "KV API")
|
|
28
|
+
Rel(api, r2, "Files", "R2 API")
|
|
29
|
+
Rel(api, google, "Auth", "OAuth 2.0")
|
|
30
|
+
Rel(api, sendgrid, "Emails", "REST API")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Container Details
|
|
34
|
+
|
|
35
|
+
### React SPA [HIGH]
|
|
36
|
+
|
|
37
|
+
| Attribute | Value |
|
|
38
|
+
|-----------|-------|
|
|
39
|
+
| **Technology** | React 19, TanStack Router, TanStack Query |
|
|
40
|
+
| **Deployment** | Static assets served from Cloudflare R2/Edge |
|
|
41
|
+
| **Purpose** | User interface for the SaaS platform |
|
|
42
|
+
| **Build Output** | `dist/` directory |
|
|
43
|
+
|
|
44
|
+
**Responsibilities:**
|
|
45
|
+
- Render user interface
|
|
46
|
+
- Handle client-side routing
|
|
47
|
+
- Manage client state
|
|
48
|
+
- Call backend API
|
|
49
|
+
- Handle authentication redirects
|
|
50
|
+
|
|
51
|
+
**Key Dependencies:**
|
|
52
|
+
- `react` - UI library
|
|
53
|
+
- `@tanstack/react-router` - File-based routing
|
|
54
|
+
- `@tanstack/react-query` - Data fetching/caching
|
|
55
|
+
- `react-hook-form` - Form handling
|
|
56
|
+
- `tailwindcss` - Styling
|
|
57
|
+
- `radix-ui/*` - Accessible UI primitives
|
|
58
|
+
|
|
59
|
+
### Hono API [HIGH]
|
|
60
|
+
|
|
61
|
+
| Attribute | Value |
|
|
62
|
+
|-----------|-------|
|
|
63
|
+
| **Technology** | Hono.js 4.x, TypeScript, Zod |
|
|
64
|
+
| **Deployment** | Cloudflare Workers |
|
|
65
|
+
| **Purpose** | REST API for all backend operations |
|
|
66
|
+
| **Entry Point** | `src/server/index.ts` |
|
|
67
|
+
|
|
68
|
+
**Responsibilities:**
|
|
69
|
+
- Handle HTTP requests
|
|
70
|
+
- Authenticate/authorize users
|
|
71
|
+
- Execute business logic
|
|
72
|
+
- Access data stores
|
|
73
|
+
- Generate OpenAPI documentation
|
|
74
|
+
|
|
75
|
+
**Key Dependencies:**
|
|
76
|
+
- `hono` - Web framework
|
|
77
|
+
- `@hono/zod-openapi` - OpenAPI integration
|
|
78
|
+
- `zod` - Request/response validation
|
|
79
|
+
- `uuidv7` - ID generation
|
|
80
|
+
|
|
81
|
+
### D1 Database [HIGH]
|
|
82
|
+
|
|
83
|
+
| Attribute | Value |
|
|
84
|
+
|-----------|-------|
|
|
85
|
+
| **Technology** | Cloudflare D1 (SQLite) |
|
|
86
|
+
| **Binding** | `DB` |
|
|
87
|
+
| **Schema** | `schema.sql` |
|
|
88
|
+
|
|
89
|
+
**Tables:**
|
|
90
|
+
| Table | Purpose |
|
|
91
|
+
|-------|---------|
|
|
92
|
+
| `users` | User profiles and authentication |
|
|
93
|
+
| `accounts` | Workspaces/organizations |
|
|
94
|
+
| `user_accounts` | User-account memberships with roles |
|
|
95
|
+
| `invitations` | Pending team invitations |
|
|
96
|
+
| `refresh_tokens` | Token storage for session refresh |
|
|
97
|
+
| `audit_logs` | All state change audit trail |
|
|
98
|
+
|
|
99
|
+
### KV Store [HIGH]
|
|
100
|
+
|
|
101
|
+
| Attribute | Value |
|
|
102
|
+
|-----------|-------|
|
|
103
|
+
| **Technology** | Cloudflare KV |
|
|
104
|
+
| **Binding** | `SESSIONS` |
|
|
105
|
+
| **Purpose** | Session storage |
|
|
106
|
+
|
|
107
|
+
**Data Stored:**
|
|
108
|
+
- Session ID → User session data (JSON)
|
|
109
|
+
- Session expiration via TTL
|
|
110
|
+
|
|
111
|
+
### R2 Storage [HIGH]
|
|
112
|
+
|
|
113
|
+
| Attribute | Value |
|
|
114
|
+
|-----------|-------|
|
|
115
|
+
| **Technology** | Cloudflare R2 |
|
|
116
|
+
| **Binding** | `R2_BUCKET` |
|
|
117
|
+
| **Purpose** | File storage |
|
|
118
|
+
|
|
119
|
+
**Usage:**
|
|
120
|
+
- User-uploaded files
|
|
121
|
+
- Account-scoped file storage
|
|
122
|
+
- Presigned URL support for secure uploads
|
|
123
|
+
|
|
124
|
+
## Inter-Container Communication
|
|
125
|
+
|
|
126
|
+
| From | To | Protocol | Purpose |
|
|
127
|
+
|------|-----|----------|---------|
|
|
128
|
+
| React SPA | Hono API | REST/JSON | All data operations |
|
|
129
|
+
| Hono API | D1 | SQL | Data persistence |
|
|
130
|
+
| Hono API | KV | KV API | Session management |
|
|
131
|
+
| Hono API | R2 | R2 API | File operations |
|
|
132
|
+
| Hono API | Google | OAuth 2.0 | Authentication |
|
|
133
|
+
| Hono API | SendGrid | REST | Email delivery |
|
|
134
|
+
|
|
135
|
+
## Deployment Architecture
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
┌─────────────────────────────────────────────────────────┐
|
|
139
|
+
│ Cloudflare Edge Network │
|
|
140
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
141
|
+
│ │ Cloudflare Worker │ │
|
|
142
|
+
│ │ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
|
143
|
+
│ │ │ Static Assets │ │ Hono API │ │ │
|
|
144
|
+
│ │ │ (React SPA) │ │ (Server Logic) │ │ │
|
|
145
|
+
│ │ └─────────────────┘ └──────────┬──────────┘ │ │
|
|
146
|
+
│ └──────────────────────────────────┼───────────────┘ │
|
|
147
|
+
│ │ │
|
|
148
|
+
│ ┌───────────┬───────────────────┼───────────────┐ │
|
|
149
|
+
│ │ │ │ │ │
|
|
150
|
+
│ ▼ ▼ ▼ │ │
|
|
151
|
+
│ ┌─────┐ ┌─────┐ ┌─────────┐ │ │
|
|
152
|
+
│ │ D1 │ │ KV │ │ R2 │ │ │
|
|
153
|
+
│ └─────┘ └─────┘ └─────────┘ │ │
|
|
154
|
+
└─────────────────────────────────────────────────────────┘
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Request Flow
|
|
158
|
+
|
|
159
|
+
### Authenticated Request
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
1. User → React SPA: Navigate to /dashboard
|
|
163
|
+
2. React SPA → Hono API: GET /api/users (with session cookie)
|
|
164
|
+
3. Hono API → KV: Validate session
|
|
165
|
+
4. Hono API → D1: Query users for account
|
|
166
|
+
5. D1 → Hono API: User data
|
|
167
|
+
6. Hono API → React SPA: JSON response
|
|
168
|
+
7. React SPA → User: Render dashboard
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Authentication Flow
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
1. User → React SPA: Click "Login with Google"
|
|
175
|
+
2. React SPA → Hono API: GET /auth/login
|
|
176
|
+
3. Hono API → User: Redirect to Google OAuth
|
|
177
|
+
4. User → Google: Authorize
|
|
178
|
+
5. Google → Hono API: GET /auth/callback (with code)
|
|
179
|
+
6. Hono API → Google: Exchange code for tokens
|
|
180
|
+
7. Hono API → D1: Create/update user
|
|
181
|
+
8. Hono API → KV: Create session
|
|
182
|
+
9. Hono API → User: Set cookie, redirect to app
|
|
183
|
+
```
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# C4 Model - Level 1: System Context
|
|
2
|
+
|
|
3
|
+
> Shows how BHono fits into the world around it.
|
|
4
|
+
|
|
5
|
+
## System Context Diagram
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
C4Context
|
|
9
|
+
title System Context Diagram - BHono SaaS Platform
|
|
10
|
+
|
|
11
|
+
Person(user, "User", "A person who uses the SaaS application")
|
|
12
|
+
Person(admin, "Admin", "Account administrator managing team members")
|
|
13
|
+
|
|
14
|
+
System(bhono, "BHono Platform", "Multi-tenant SaaS application with user management, team collaboration, and file storage")
|
|
15
|
+
|
|
16
|
+
System_Ext(google, "Google OAuth", "Identity provider for authentication")
|
|
17
|
+
System_Ext(sendgrid, "SendGrid", "Email delivery service for invitations")
|
|
18
|
+
|
|
19
|
+
Rel(user, bhono, "Uses", "HTTPS")
|
|
20
|
+
Rel(admin, bhono, "Manages teams", "HTTPS")
|
|
21
|
+
Rel(bhono, google, "Authenticates users", "OAuth 2.0")
|
|
22
|
+
Rel(bhono, sendgrid, "Sends emails", "REST API")
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Context Description
|
|
26
|
+
|
|
27
|
+
| Element | Type | Description | Confidence |
|
|
28
|
+
|---------|------|-------------|------------|
|
|
29
|
+
| **User** | Person | End user of the SaaS platform. Can belong to multiple accounts (workspaces). | HIGH |
|
|
30
|
+
| **Admin** | Person | Account administrator with elevated permissions to manage team members and invitations. | HIGH |
|
|
31
|
+
| **BHono Platform** | System | The main application - a multi-tenant SaaS platform deployed on Cloudflare Workers edge. | HIGH |
|
|
32
|
+
| **Google OAuth** | External System | Google's OAuth 2.0 service used for user authentication. | HIGH |
|
|
33
|
+
| **SendGrid** | External System | Email delivery service for sending team invitations. | HIGH |
|
|
34
|
+
|
|
35
|
+
## System Responsibilities
|
|
36
|
+
|
|
37
|
+
### BHono Platform
|
|
38
|
+
|
|
39
|
+
The core system provides:
|
|
40
|
+
|
|
41
|
+
| Capability | Description | Confidence |
|
|
42
|
+
|------------|-------------|------------|
|
|
43
|
+
| **User Authentication** | OAuth 2.0 flow with Google, session management via cookies | HIGH |
|
|
44
|
+
| **Multi-tenancy** | Users can belong to multiple Accounts with different roles | HIGH |
|
|
45
|
+
| **Team Collaboration** | Invite team members via email, manage permissions | HIGH |
|
|
46
|
+
| **File Storage** | Upload/download files via R2 storage | HIGH |
|
|
47
|
+
| **Audit Logging** | Track all state changes for compliance | HIGH |
|
|
48
|
+
| **API Access** | REST API with OpenAPI documentation | HIGH |
|
|
49
|
+
|
|
50
|
+
## External System Dependencies
|
|
51
|
+
|
|
52
|
+
### Google OAuth [HIGH]
|
|
53
|
+
|
|
54
|
+
- **Purpose**: User authentication
|
|
55
|
+
- **Protocol**: OAuth 2.0 with PKCE
|
|
56
|
+
- **Endpoints Used**:
|
|
57
|
+
- `https://accounts.google.com/o/oauth2/v2/auth` - Authorization
|
|
58
|
+
- `https://oauth2.googleapis.com/token` - Token exchange
|
|
59
|
+
- `https://www.googleapis.com/oauth2/v3/userinfo` - User info
|
|
60
|
+
- **Data Exchanged**: User email, name, avatar URL, Google ID
|
|
61
|
+
|
|
62
|
+
### SendGrid [HIGH]
|
|
63
|
+
|
|
64
|
+
- **Purpose**: Email delivery for invitations
|
|
65
|
+
- **Protocol**: REST API
|
|
66
|
+
- **Endpoints Used**: SendGrid Mail Send API
|
|
67
|
+
- **Data Exchanged**: Recipient email, invitation details, sender info
|
|
68
|
+
|
|
69
|
+
## User Roles
|
|
70
|
+
|
|
71
|
+
| Role | Description | Confidence |
|
|
72
|
+
|------|-------------|------------|
|
|
73
|
+
| **ADMIN** | Full account access, can manage all members and settings | HIGH |
|
|
74
|
+
| **MANAGER** | Can manage team members (invite, remove) | HIGH |
|
|
75
|
+
| **EDITOR** | Can edit all content | HIGH |
|
|
76
|
+
| **AUTHOR** | Can create and edit own content | HIGH |
|
|
77
|
+
| **VIEWER** | Read-only access | HIGH |
|
|
78
|
+
| **BILLING** | Access to billing information | HIGH |
|
|
79
|
+
| **ANALYTICS** | Access to analytics and audit logs | HIGH |
|
|
80
|
+
|
|
81
|
+
## Non-Functional Requirements
|
|
82
|
+
|
|
83
|
+
| Requirement | Target | Implementation | Confidence |
|
|
84
|
+
|-------------|--------|----------------|------------|
|
|
85
|
+
| **Latency** | <100ms globally | Cloudflare Edge deployment | HIGH |
|
|
86
|
+
| **Availability** | 99.9%+ | Cloudflare Workers SLA | HIGH |
|
|
87
|
+
| **Security** | OAuth 2.0, RBAC | Google OAuth + Guards | HIGH |
|
|
88
|
+
| **Compliance** | Audit trail | audit_logs table | HIGH |
|
|
89
|
+
| **Multi-region** | Global | Cloudflare Edge network | HIGH |
|
|
90
|
+
|
|
91
|
+
## Data Flow Overview
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
┌─────────┐ HTTPS ┌──────────────────┐
|
|
95
|
+
│ User │───────────────▶│ BHono Platform │
|
|
96
|
+
└─────────┘ └────────┬─────────┘
|
|
97
|
+
│
|
|
98
|
+
┌───────────────┼───────────────┐
|
|
99
|
+
│ │ │
|
|
100
|
+
▼ ▼ ▼
|
|
101
|
+
┌───────────┐ ┌───────────┐ ┌───────────┐
|
|
102
|
+
│ Google │ │ SendGrid │ │ Cloudflare│
|
|
103
|
+
│ OAuth │ │ │ │ Services │
|
|
104
|
+
└───────────┘ └───────────┘ └───────────┘
|
|
105
|
+
D1 | KV | R2
|
|
106
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Data Requirements Document (DRD)
|
|
2
2
|
|
|
3
3
|
## 1. Objetivo e escopo
|
|
4
|
-
Este documento define os requisitos de dados do projeto, cobrindo o modelo relacional (D1/SQLite), armazenamento de sessao (KV) e objetos (R2). Serve como referencia para manutencao, auditoria e
|
|
4
|
+
Este documento define os requisitos de dados do projeto, cobrindo o modelo relacional (D1/SQLite), armazenamento de sessao (KV) e objetos (R2). Serve como referencia para manutencao, auditoria e evolucao do SQL puro.
|
|
5
5
|
|
|
6
6
|
## 2. Componentes de armazenamento
|
|
7
7
|
- D1 (SQLite): armazenamento relacional principal.
|
|
@@ -102,8 +102,9 @@ Principais entidades:
|
|
|
102
102
|
- Requisito: manter procedimento de backup/restore do D1 (ex.: exportacao periodica) e verificar restauracao.
|
|
103
103
|
- KV e R2 devem ter estrategia de recuperacao alinhada com RPO/RTO desejados.
|
|
104
104
|
|
|
105
|
-
## 12. Consideracoes para
|
|
105
|
+
## 12. Consideracoes para SQL puro (sem migrations)
|
|
106
106
|
- Todas as queries devem ser parametrizadas para evitar SQL injection.
|
|
107
107
|
- Manter mapeadores de resultado (ex.: validacao via Zod) para preservar contratos tipados.
|
|
108
108
|
- Centralizar SQL em um modulo `db` e reutilizar modelos do ERD.
|
|
109
|
-
-
|
|
109
|
+
- `schema.sql` e a fonte de verdade do schema e deve ser aplicado via `wrangler d1 execute`.
|
|
110
|
+
- `seed.sql` e gerado a partir de `src/server/db/seed.ts` e aplicado apos o bootstrap quando necessario.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Database Bootstrap (schema.sql)
|
|
2
|
+
|
|
3
|
+
## Objetivo
|
|
4
|
+
O boilerplate nao usa migrations. O schema do D1 e versionado em `schema.sql` e aplicado via `wrangler d1 execute`. O seed e gerado em `seed.sql` a partir de `src/server/db/seed.ts`.
|
|
5
|
+
|
|
6
|
+
## Arquivos
|
|
7
|
+
- `schema.sql` - fonte de verdade do schema
|
|
8
|
+
- `src/server/db/seed.ts` - gerador de seed
|
|
9
|
+
- `seed.sql` - output do seed (gerado)
|
|
10
|
+
|
|
11
|
+
## Fluxos recomendados
|
|
12
|
+
### Local
|
|
13
|
+
```bash
|
|
14
|
+
# aplicar schema
|
|
15
|
+
pnpm db:schema:local
|
|
16
|
+
|
|
17
|
+
# gerar e aplicar seed
|
|
18
|
+
pnpm db:seed:local
|
|
19
|
+
|
|
20
|
+
# reset completo (schema + seed)
|
|
21
|
+
pnpm db:reset:local
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Remoto (opcional)
|
|
25
|
+
```bash
|
|
26
|
+
# aplicar schema
|
|
27
|
+
pnpm db:schema:remote
|
|
28
|
+
|
|
29
|
+
# gerar e aplicar seed
|
|
30
|
+
pnpm db:seed:remote
|
|
31
|
+
|
|
32
|
+
# reset completo (schema + seed)
|
|
33
|
+
pnpm db:reset:remote
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Notas
|
|
37
|
+
- `schema.sql` deve ser atualizado a cada mudanca estrutural.
|
|
38
|
+
- `seed.sql` deve ser re-gerado apos alteracoes em `seed.ts`.
|
|
39
|
+
- As migrations nao sao usadas neste boilerplate para manter o fluxo simples.
|