@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.
Files changed (300) hide show
  1. package/dist/index.js +0 -0
  2. package/package.json +7 -2
  3. package/templates/base/.claude/commands/check-skill-rules.md +112 -29
  4. package/templates/base/.claude/commands/linear/implement-issue.md +383 -55
  5. package/templates/base/.claude/commands/ship.md +77 -13
  6. package/templates/base/.claude/hooks/package-lock.json +0 -419
  7. package/templates/base/.claude/hooks/skill-activation-prompt.ts +185 -113
  8. package/templates/base/.claude/hooks/skill-tool-guard.sh +6 -0
  9. package/templates/base/.claude/hooks/skill-tool-guard.ts +198 -0
  10. package/templates/base/.claude/scripts/validate-skill-rules.sh +55 -32
  11. package/templates/base/.claude/settings.json +18 -11
  12. package/templates/base/.claude/skills/skill-rules.json +326 -173
  13. package/templates/base/.env.example +3 -0
  14. package/templates/base/CLAUDE.md +5 -5
  15. package/templates/base/README.md +40 -27
  16. package/templates/base/config/eslint.config.js +1 -0
  17. package/templates/base/config/wrangler.json +16 -17
  18. package/templates/base/docs/SETUP-GUIDE.md +566 -0
  19. package/templates/base/docs/app_spec.txt +13 -10
  20. package/templates/base/docs/architecture/README.md +162 -5
  21. package/templates/base/docs/architecture/api-catalog.md +575 -0
  22. package/templates/base/docs/architecture/c4-component.md +309 -0
  23. package/templates/base/docs/architecture/c4-container.md +183 -0
  24. package/templates/base/docs/architecture/c4-context.md +106 -0
  25. package/templates/base/docs/architecture/data-requirements.md +4 -3
  26. package/templates/base/docs/architecture/db-bootstrap.md +39 -0
  27. package/templates/base/docs/architecture/dependencies.md +327 -0
  28. package/templates/base/docs/architecture/drizzle-migration-plan.md +125 -0
  29. package/templates/base/docs/architecture/erd.md +1 -1
  30. package/templates/base/docs/architecture/sql-standards.md +100 -0
  31. package/templates/base/docs/architecture/tech-debt.md +184 -0
  32. package/templates/base/docs/testing.md +36 -29
  33. package/templates/base/package.json +26 -20
  34. package/templates/base/schema.sql +84 -0
  35. package/templates/base/scripts/capture-prod-session.ts +2 -2
  36. package/templates/base/scripts/init.sh +244 -59
  37. package/templates/base/scripts/sync-template.sh +104 -0
  38. package/templates/base/src/client/hooks/use-auth.ts +5 -0
  39. package/templates/base/src/client/routes/_authenticated/dashboard.tsx +1 -1
  40. package/templates/base/src/client/routes/index.tsx +1 -1
  41. package/templates/base/src/server/db/client.ts +3 -5
  42. package/templates/base/src/server/db/records.ts +81 -0
  43. package/templates/base/src/server/db/seed.ts +3 -2
  44. package/templates/base/src/server/db/sql.ts +116 -0
  45. package/templates/base/src/server/index.ts +17 -2
  46. package/templates/base/src/server/lib/audit.ts +74 -26
  47. package/templates/base/src/server/lib/audited-db.ts +219 -109
  48. package/templates/base/src/server/lib/transaction.ts +10 -16
  49. package/templates/base/src/server/middleware/account.ts +9 -16
  50. package/templates/base/src/server/middleware/auth.ts +102 -38
  51. package/templates/base/src/server/middleware/rate-limit.ts +8 -6
  52. package/templates/base/src/server/routes/accounts/handlers.ts +18 -6
  53. package/templates/base/src/server/routes/audits/handlers.ts +3 -1
  54. package/templates/base/src/server/routes/auth/handlers.ts +15 -10
  55. package/templates/base/src/server/routes/auth/test-login.ts +99 -45
  56. package/templates/base/src/server/routes/health/handlers.ts +4 -4
  57. package/templates/base/src/server/routes/index.ts +9 -0
  58. package/templates/base/src/server/routes/invitations/handlers.ts +9 -6
  59. package/templates/base/src/server/routes/openapi.ts +1 -1
  60. package/templates/base/src/server/routes/users/handlers.ts +21 -14
  61. package/templates/base/src/server/services/accounts.ts +242 -217
  62. package/templates/base/src/server/services/audits.ts +114 -61
  63. package/templates/base/src/server/services/auth.ts +310 -180
  64. package/templates/base/src/server/services/invitations.ts +282 -222
  65. package/templates/base/src/server/services/users.ts +383 -293
  66. package/templates/base/src/server/types/index.ts +1 -2
  67. package/templates/base/src/shared/types/api.ts +66 -198
  68. package/templates/base/tests/e2e/auth.setup.ts +1 -1
  69. package/templates/base/{src/server/__tests__/fixtures.ts → tests/fixtures/server.ts} +3 -3
  70. package/templates/base/{src/client/__tests__/setup-browser.ts → tests/helpers/client-setup-browser.ts} +2 -2
  71. package/templates/base/{src/client/__tests__/setup.ts → tests/helpers/client-setup.ts} +1 -1
  72. package/templates/base/{src/client/__tests__/test-utils.tsx → tests/helpers/client-test-utils.tsx} +2 -2
  73. package/templates/base/{src/server/__tests__/setup.ts → tests/helpers/server.ts} +9 -9
  74. package/templates/base/tests/integration/accounts/crud.test.ts +2 -11
  75. package/templates/base/tests/integration/audits/list.test.ts +2 -11
  76. package/templates/base/tests/integration/auth/auth-service.test.ts +1 -10
  77. package/templates/base/tests/integration/auth/invitation-token.test.ts +2 -11
  78. package/templates/base/tests/integration/auth/logout.test.ts +2 -11
  79. package/templates/base/tests/integration/auth/oauth.test.ts +23 -42
  80. package/templates/base/tests/integration/auth/refresh-token.test.ts +1 -9
  81. package/templates/base/tests/integration/auth/session-expiry.test.ts +1 -9
  82. package/templates/base/tests/integration/auth/session.test.ts +2 -11
  83. package/templates/base/tests/integration/auth/super-admin.test.ts +1 -9
  84. package/templates/base/tests/integration/authorization/analytics-role.test.ts +2 -11
  85. package/templates/base/tests/integration/authorization/billing-role.test.ts +2 -11
  86. package/templates/base/tests/integration/authorization/guards-roles.test.ts +1 -9
  87. package/templates/base/tests/integration/authorization/multi-tenancy.test.ts +2 -11
  88. package/templates/base/tests/integration/authorization/roles.test.ts +2 -11
  89. package/templates/base/tests/integration/config/production-behavior.test.ts +2 -11
  90. package/templates/base/tests/integration/health/health.test.ts +25 -44
  91. package/templates/base/tests/integration/invitations/crud.test.ts +2 -11
  92. package/templates/base/tests/integration/invitations/email.test.ts +1 -9
  93. package/templates/base/tests/integration/middleware/auth.test.ts +3 -12
  94. package/templates/base/tests/integration/middleware/request-logger.test.ts +1 -9
  95. package/templates/base/tests/integration/performance/response-times.test.ts +1 -9
  96. package/templates/base/tests/integration/security/cookie-security.test.ts +2 -11
  97. package/templates/base/tests/integration/security/csrf-protection.test.ts +2 -11
  98. package/templates/base/tests/integration/security/log-sanitization.test.ts +1 -9
  99. package/templates/base/tests/integration/security/rate-limiting.test.ts +1 -9
  100. package/templates/base/tests/integration/security/sql-injection.test.ts +7 -18
  101. package/templates/base/tests/integration/security/xss-prevention.test.ts +2 -11
  102. package/templates/base/tests/integration/setup.ts +13 -90
  103. package/templates/base/tests/integration/smoke.test.ts +3 -2
  104. package/templates/base/tests/integration/storage/upload.test.ts +2 -11
  105. package/templates/base/tests/integration/storage/validation.test.ts +2 -11
  106. package/templates/base/tests/integration/users/crud.test.ts +2 -11
  107. package/templates/base/tests/integration/users/list.test.ts +2 -11
  108. package/templates/base/tests/integration/vitest.config.ts +2 -9
  109. package/templates/base/{src/server/__tests__ → tests}/mocks/db.ts +1 -1
  110. package/templates/base/{src/server/__tests__ → tests}/mocks/index.ts +1 -1
  111. package/templates/base/{src/server/__tests__ → tests}/mocks/kv.ts +1 -1
  112. package/templates/base/{src/server/__tests__ → tests}/mocks/r2.ts +1 -1
  113. package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/sidebar.test.tsx +1 -1
  114. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/avatar.test.tsx +1 -1
  115. package/templates/base/{src/client/__tests__ → tests/unit/client/components/ui}/button.test.tsx +1 -1
  116. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/card.test.tsx +1 -1
  117. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/dialog.test.tsx +1 -1
  118. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/input.test.tsx +1 -1
  119. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/loading-skeleton.test.tsx +1 -1
  120. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/skeleton.test.tsx +1 -1
  121. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/sonner.test.tsx +1 -1
  122. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/tabs.test.tsx +1 -1
  123. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/account.test.tsx +1 -1
  124. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/integrations.test.tsx +1 -1
  125. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/settings.test.tsx +1 -1
  126. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/team.test.tsx +1 -1
  127. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/authenticated-layout.test.tsx +1 -1
  128. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/dashboard.test.tsx +1 -1
  129. package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/invite.test.tsx +1 -1
  130. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/login.test.tsx +1 -1
  131. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/navigation.test.tsx +1 -1
  132. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/root-layout.test.tsx +1 -1
  133. package/templates/base/{src/server/auth/__tests__ → tests/unit/server/auth}/guards.test.ts +2 -2
  134. package/templates/base/{src → tests/unit}/server/auth/permissions.test.ts +1 -1
  135. package/templates/base/{src → tests/unit}/server/auth/roles.test.ts +1 -1
  136. package/templates/base/tests/unit/server/db/sql.test.ts +68 -0
  137. package/templates/base/{src → tests/unit}/server/env.test.ts +1 -1
  138. package/templates/base/tests/unit/server/lib/audited-db.test.ts +78 -0
  139. package/templates/base/{src → tests/unit}/server/lib/email.test.ts +1 -1
  140. package/templates/base/{src → tests/unit}/server/lib/errors.test.ts +1 -1
  141. package/templates/base/{src → tests/unit}/server/lib/oauth.test.ts +1 -1
  142. package/templates/base/{src → tests/unit}/server/lib/pagination.test.ts +1 -1
  143. package/templates/base/{src → tests/unit}/server/lib/password.test.ts +1 -1
  144. package/templates/base/{src → tests/unit}/server/lib/providers.test.ts +1 -1
  145. package/templates/base/{src → tests/unit}/server/lib/r2-storage.test.ts +2 -2
  146. package/templates/base/{src → tests/unit}/server/lib/session.test.ts +2 -2
  147. package/templates/base/{src → tests/unit}/server/lib/tokens.test.ts +1 -1
  148. package/templates/base/{src → tests/unit}/server/lib/transaction.test.ts +5 -14
  149. package/templates/base/{src → tests/unit}/server/middleware/account.test.ts +16 -24
  150. package/templates/base/tests/unit/server/middleware/auth.test.ts +647 -0
  151. package/templates/base/{src → tests/unit}/server/middleware/cors.test.ts +1 -1
  152. package/templates/base/{src → tests/unit}/server/middleware/error-handler.test.ts +2 -2
  153. package/templates/base/{src → tests/unit}/server/middleware/rate-limit.test.ts +3 -2
  154. package/templates/base/{src → tests/unit}/server/middleware/request-context.test.ts +1 -1
  155. package/templates/base/{src → tests/unit}/server/middleware/request-logger.test.ts +1 -1
  156. package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/db.test.ts +1 -1
  157. package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/kv.test.ts +1 -1
  158. package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/r2.test.ts +1 -1
  159. package/templates/base/{src/server/routes/accounts/__tests__ → tests/unit/server/routes/accounts}/handlers.test.ts +12 -12
  160. package/templates/base/{src/server/routes/audits/__tests__ → tests/unit/server/routes/audits}/handlers.test.ts +11 -11
  161. package/templates/base/{src/server/routes/auth/__tests__ → tests/unit/server/routes/auth}/handlers.test.ts +124 -13
  162. package/templates/base/{src/server/routes/health/__tests__ → tests/unit/server/routes/health}/handlers.test.ts +27 -23
  163. package/templates/base/{src/server/routes/invitations/__tests__ → tests/unit/server/routes/invitations}/handlers.test.ts +14 -17
  164. package/templates/base/{src/server/routes/storage/__tests__ → tests/unit/server/routes/storage}/handlers.test.ts +6 -6
  165. package/templates/base/{src/server/routes/users/__tests__ → tests/unit/server/routes/users}/handlers.test.ts +81 -17
  166. package/templates/base/tests/unit/server/services/accounts.test.ts +406 -0
  167. package/templates/base/tests/unit/server/services/audits.test.ts +360 -0
  168. package/templates/base/tests/unit/server/services/auth.test.ts +656 -0
  169. package/templates/base/tests/unit/server/services/invitations.test.ts +343 -0
  170. package/templates/base/tests/unit/server/services/users.test.ts +706 -0
  171. package/templates/base/{src/shared/schemas/__tests__ → tests/unit/shared}/schemas.test.ts +1 -1
  172. package/templates/base/tsconfig.json +2 -1
  173. package/templates/base/vite.config.ts +3 -1
  174. package/templates/base/vitest.config.browser.ts +3 -2
  175. package/templates/base/vitest.config.frontend.ts +3 -2
  176. package/templates/base/vitest.config.ts +7 -14
  177. package/templates/base/.claude/settings.local.json +0 -11
  178. package/templates/base/.github/workflows/test.yml +0 -127
  179. package/templates/base/auth-setup-error.png +0 -0
  180. package/templates/base/config/drizzle.config.ts +0 -10
  181. package/templates/base/pnpm-lock.yaml +0 -8175
  182. package/templates/base/src/server/db/schema/accounts.ts +0 -20
  183. package/templates/base/src/server/db/schema/audit-logs.ts +0 -26
  184. package/templates/base/src/server/db/schema/index.ts +0 -7
  185. package/templates/base/src/server/db/schema/invitations.ts +0 -30
  186. package/templates/base/src/server/db/schema/refresh-tokens.ts +0 -22
  187. package/templates/base/src/server/db/schema/user-accounts.ts +0 -25
  188. package/templates/base/src/server/db/schema/users.ts +0 -33
  189. package/templates/base/src/server/lib/audited-db.test.ts +0 -107
  190. package/templates/base/src/server/lib/schema-helpers.ts +0 -16
  191. package/templates/base/src/server/middleware/auth.test.ts +0 -345
  192. package/templates/base/src/server/services/__tests__/accounts.test.ts +0 -764
  193. package/templates/base/src/server/services/__tests__/audits.test.ts +0 -235
  194. package/templates/base/src/server/services/__tests__/auth.test.ts +0 -765
  195. package/templates/base/src/server/services/__tests__/invitations.test.ts +0 -704
  196. package/templates/base/src/server/services/__tests__/users.test.ts +0 -755
  197. package/templates/base/tests/e2e/_auth/.gitkeep +0 -0
  198. package/templates/base/tests/integration/lib/schema-helpers.test.ts +0 -129
  199. package/templates/base/tsconfig.tsbuildinfo +0 -1
  200. /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
  201. /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
  202. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-logout-button-click-1.png +0 -0
  203. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-navigation-clicks-1.png +0 -0
  204. /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
  205. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-highlights-active-route-1.png +0 -0
  206. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-renders-sidebar-navigation-items-1.png +0 -0
  207. /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
  208. /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
  209. /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
  210. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/error-boundary.test.tsx +0 -0
  211. /package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/error-fallback.test.tsx +0 -0
  212. /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-auth.test.tsx +0 -0
  213. /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-theme.test.tsx +0 -0
  214. /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
  215. /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
  216. /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
  217. /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
  218. /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
  219. /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
  220. /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
  221. /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
  222. /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
  223. /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
  224. /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
  225. /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
  226. /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
  227. /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
  228. /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
  229. /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
  230. /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
  231. /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
  232. /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
  233. /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
  234. /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
  235. /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
  236. /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
  237. /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
  238. /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
  239. /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
  240. /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
  241. /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
  242. /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
  243. /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
  244. /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
  245. /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
  246. /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
  247. /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
  248. /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
  249. /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
  250. /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
  251. /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
  252. /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
  253. /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
  254. /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
  255. /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
  256. /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
  257. /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
  258. /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
  259. /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
  260. /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
  261. /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
  262. /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
  263. /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
  264. /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
  265. /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
  266. /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
  267. /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
  268. /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
  269. /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
  270. /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
  271. /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
  272. /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
  273. /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
  274. /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
  275. /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
  276. /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
  277. /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
  278. /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
  279. /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
  280. /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
  281. /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
  282. /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
  283. /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
  284. /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
  285. /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
  286. /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
  287. /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
  288. /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
  289. /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
  290. /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
  291. /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
  292. /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
  293. /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
  294. /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
  295. /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
  296. /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
  297. /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
  298. /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
  299. /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
  300. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/error-components.test.tsx +0 -0
@@ -20,6 +20,9 @@ UPDATE_PACKAGES=0
20
20
  SKIP_DEV=0
21
21
  SKIP_PROVISION=0
22
22
  SKIP_SEED=0
23
+ DEV_PORT=""
24
+ GOOGLE_CLIENT_ID_ARG=""
25
+ GOOGLE_CLIENT_SECRET_ARG=""
23
26
 
24
27
  while [[ $# -gt 0 ]]; do
25
28
  case "$1" in
@@ -35,6 +38,51 @@ while [[ $# -gt 0 ]]; do
35
38
  --skip-seed)
36
39
  SKIP_SEED=1
37
40
  ;;
41
+ --port)
42
+ DEV_PORT="$2"
43
+ shift
44
+ ;;
45
+ --port=*)
46
+ DEV_PORT="${1#*=}"
47
+ ;;
48
+ --google-id)
49
+ GOOGLE_CLIENT_ID_ARG="$2"
50
+ shift
51
+ ;;
52
+ --google-id=*)
53
+ GOOGLE_CLIENT_ID_ARG="${1#*=}"
54
+ ;;
55
+ --google-secret)
56
+ GOOGLE_CLIENT_SECRET_ARG="$2"
57
+ shift
58
+ ;;
59
+ --google-secret=*)
60
+ GOOGLE_CLIENT_SECRET_ARG="${1#*=}"
61
+ ;;
62
+ --help|-h)
63
+ echo ""
64
+ echo "BHono - Development Environment Setup"
65
+ echo ""
66
+ echo "Usage: ./scripts/init.sh [OPTIONS]"
67
+ echo ""
68
+ echo "Options:"
69
+ echo " --port PORT Set dev server port (default: 8787)"
70
+ echo " --google-id ID Set Google OAuth Client ID"
71
+ echo " --google-secret SEC Set Google OAuth Client Secret"
72
+ echo " --no-provision Skip Cloudflare resource provisioning"
73
+ echo " --skip-dev Don't start dev server after setup"
74
+ echo " --skip-seed Skip database seeding"
75
+ echo " --update Update dependencies"
76
+ echo " --help, -h Show this help message"
77
+ echo ""
78
+ echo "Examples:"
79
+ echo " ./scripts/init.sh"
80
+ echo " ./scripts/init.sh --port 3000"
81
+ echo " ./scripts/init.sh --port 8787 --google-id 'xxx.apps.googleusercontent.com' --google-secret 'GOCSPX-xxx'"
82
+ echo " CLOUDFLARE_ACCOUNT_ID=xxx ./scripts/init.sh"
83
+ echo ""
84
+ exit 0
85
+ ;;
38
86
  *)
39
87
  echo -e "${YELLOW}Ignoring unknown argument: $1${NC}"
40
88
  ;;
@@ -42,6 +90,9 @@ while [[ $# -gt 0 ]]; do
42
90
  shift
43
91
  done
44
92
 
93
+ # Set default port if not specified
94
+ DEV_PORT="${DEV_PORT:-8787}"
95
+
45
96
  log_info() { echo -e "${BLUE}$*${NC}"; }
46
97
  log_ok() { echo -e "${GREEN}$*${NC}"; }
47
98
  log_warn() { echo -e "${YELLOW}$*${NC}"; }
@@ -114,6 +165,38 @@ fi
114
165
 
115
166
  log_ok "Project name: $PROJECT_NAME"
116
167
 
168
+ # ============================================================================
169
+ # FIX PROJECT NAME IN ALL CONFIG FILES (handles "." issue from bhono-app)
170
+ # ============================================================================
171
+ log_info "Fixing project name in config files..."
172
+
173
+ # Fix package.json if name is "." or empty
174
+ if [[ -f package.json ]]; then
175
+ PROJECT_NAME="$PROJECT_NAME" node -e "
176
+ const fs = require('fs');
177
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
178
+ if (pkg.name === '.' || pkg.name === '' || !pkg.name) {
179
+ pkg.name = process.env.PROJECT_NAME;
180
+ fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
181
+ console.log(' Fixed package.json name');
182
+ }
183
+ " 2>/dev/null || true
184
+ fi
185
+
186
+ # Fix etus.config.json if name is "." or empty
187
+ if [[ -f etus.config.json ]]; then
188
+ PROJECT_NAME="$PROJECT_NAME" node -e "
189
+ const fs = require('fs');
190
+ const data = JSON.parse(fs.readFileSync('etus.config.json', 'utf8'));
191
+ if (data.name === '.' || data.name === '' || !data.name) {
192
+ data.name = process.env.PROJECT_NAME;
193
+ data.domain = process.env.PROJECT_NAME + '.com';
194
+ fs.writeFileSync('etus.config.json', JSON.stringify(data, null, 2));
195
+ console.log(' Fixed etus.config.json name');
196
+ }
197
+ " 2>/dev/null || true
198
+ fi
199
+
117
200
  # Ensure wrangler.json exists
118
201
  if [[ ! -f config/wrangler.json ]]; then
119
202
  log_err "Missing config/wrangler.json"
@@ -151,6 +234,114 @@ if (!data.name || data.name.includes('{{projectName}}')) {
151
234
  fs.writeFileSync(path, JSON.stringify(data, null, 2));
152
235
  NODE
153
236
 
237
+ # ============================================================================
238
+ # FIX VITE.CONFIG.TS (configPath + server port)
239
+ # ============================================================================
240
+ log_info "Checking vite.config.ts..."
241
+
242
+ if [[ -f vite.config.ts ]]; then
243
+ VITE_UPDATED=0
244
+
245
+ # Add configPath to cloudflare plugin if not present
246
+ if ! grep -q "configPath:" vite.config.ts; then
247
+ sed -i.bak 's/cloudflare()/cloudflare({\n configPath: ".\\/config\\/wrangler.json",\n })/g' vite.config.ts
248
+ rm -f vite.config.ts.bak
249
+ VITE_UPDATED=1
250
+ log_ok " Added configPath to cloudflare plugin"
251
+ fi
252
+
253
+ # Add server port if not present
254
+ if ! grep -q "server:" vite.config.ts; then
255
+ sed -i.bak "s/export default defineConfig({/export default defineConfig({\n server: {\n port: $DEV_PORT,\n },/g" vite.config.ts
256
+ rm -f vite.config.ts.bak
257
+ VITE_UPDATED=1
258
+ log_ok " Added server port $DEV_PORT"
259
+ fi
260
+
261
+ [[ "$VITE_UPDATED" -eq 0 ]] && log_ok " vite.config.ts already configured"
262
+ fi
263
+
264
+ # ============================================================================
265
+ # CREATE/UPDATE CONFIG/.DEV.VARS
266
+ # ============================================================================
267
+ log_info "Checking config/.dev.vars..."
268
+
269
+ # Determine Google OAuth credentials
270
+ GOOGLE_ID="${GOOGLE_CLIENT_ID_ARG:-seu-google-client-id}"
271
+ GOOGLE_SECRET="${GOOGLE_CLIENT_SECRET_ARG:-seu-google-client-secret}"
272
+
273
+ if [[ ! -f config/.dev.vars ]]; then
274
+ # Generate a random JWT secret
275
+ JWT_RAND=$(openssl rand -hex 16 2>/dev/null || node -e "console.log(require('crypto').randomBytes(16).toString('hex'))")
276
+
277
+ cat > config/.dev.vars << EOF
278
+ # Environment
279
+ ENVIRONMENT=development
280
+ APP_URL=http://localhost:$DEV_PORT
281
+
282
+ # JWT Configuration (IMPORTANTE: mínimo 32 caracteres)
283
+ JWT_SECRET=super-secret-jwt-key-with-at-least-32-chars-${JWT_RAND}
284
+ JWT_EXPIRY_MINUTES=15
285
+
286
+ # Google OAuth
287
+ GOOGLE_CLIENT_ID=$GOOGLE_ID
288
+ GOOGLE_CLIENT_SECRET=$GOOGLE_SECRET
289
+ GOOGLE_REDIRECT_URI=http://localhost:$DEV_PORT/auth/callback
290
+
291
+ # Refresh Token
292
+ REFRESH_TOKEN_EXPIRY_DAYS=30
293
+
294
+ # SendGrid (opcional para desenvolvimento)
295
+ SENDGRID_API_KEY=your-sendgrid-api-key
296
+ SENDGRID_FROM_EMAIL=noreply@example.com
297
+ EOF
298
+ log_ok " config/.dev.vars created"
299
+
300
+ if [[ "$GOOGLE_ID" == "seu-google-client-id" ]]; then
301
+ log_warn " IMPORTANTE: Edite config/.dev.vars com suas credenciais Google OAuth!"
302
+ else
303
+ log_ok " Google OAuth credentials configured"
304
+ fi
305
+ else
306
+ # Update Google credentials if provided via arguments
307
+ if [[ -n "$GOOGLE_CLIENT_ID_ARG" ]]; then
308
+ sed -i.bak "s|GOOGLE_CLIENT_ID=.*|GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID_ARG|g" config/.dev.vars
309
+ rm -f config/.dev.vars.bak
310
+ log_ok " Updated GOOGLE_CLIENT_ID"
311
+ fi
312
+ if [[ -n "$GOOGLE_CLIENT_SECRET_ARG" ]]; then
313
+ sed -i.bak "s|GOOGLE_CLIENT_SECRET=.*|GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET_ARG|g" config/.dev.vars
314
+ rm -f config/.dev.vars.bak
315
+ log_ok " Updated GOOGLE_CLIENT_SECRET"
316
+ fi
317
+
318
+ # Ensure APP_URL is set for local development
319
+ if ! grep -q "APP_URL=http://localhost" config/.dev.vars; then
320
+ echo "" >> config/.dev.vars
321
+ echo "# Added by init.sh" >> config/.dev.vars
322
+ echo "APP_URL=http://localhost:$DEV_PORT" >> config/.dev.vars
323
+ log_ok " Added APP_URL to config/.dev.vars"
324
+ fi
325
+
326
+ # Update redirect URI if port changed
327
+ if ! grep -q "GOOGLE_REDIRECT_URI=http://localhost:$DEV_PORT" config/.dev.vars; then
328
+ sed -i.bak "s|GOOGLE_REDIRECT_URI=http://localhost:[0-9]*|GOOGLE_REDIRECT_URI=http://localhost:$DEV_PORT|g" config/.dev.vars
329
+ rm -f config/.dev.vars.bak
330
+ fi
331
+ fi
332
+
333
+ # ============================================================================
334
+ # UPDATE .GITIGNORE FOR SECURITY
335
+ # ============================================================================
336
+ log_info "Checking .gitignore..."
337
+
338
+ if [[ -f .gitignore ]]; then
339
+ if ! grep -q "config/.dev.vars" .gitignore; then
340
+ echo "config/.dev.vars" >> .gitignore
341
+ log_ok " Added config/.dev.vars to .gitignore"
342
+ fi
343
+ fi
344
+
154
345
  WRANGLER="pnpm exec wrangler"
155
346
  WRANGLER_CONFIG="$WRANGLER --config config/wrangler.json"
156
347
  WRANGLER_AVAILABLE=1
@@ -248,86 +439,80 @@ NODE
248
439
  log_info "Generating Cloudflare types..."
249
440
  pnpm cf-typegen >/dev/null 2>&1 || log_warn "Skipping cf-typegen (wrangler not configured)"
250
441
 
251
- # Ensure local D1 exists and update drizzle config
442
+ # Ensure local D1 exists
252
443
  log_info "Preparing local D1 database..."
253
444
  if [[ "$WRANGLER_AVAILABLE" -eq 1 ]]; then
254
445
  $WRANGLER_CONFIG d1 execute "$DB_NAME" --local --command "SELECT 1;" >/dev/null 2>&1 || log_warn "Local D1 init failed (continuing)."
255
446
  fi
256
447
 
257
- D1_ID_FROM_CONFIG=$(node -e "const c=require('./config/wrangler.json'); console.log((c.d1_databases&&c.d1_databases[0]&&c.d1_databases[0].database_id)||'');")
258
- if [[ -n "$D1_ID_FROM_CONFIG" ]]; then
259
- LOCAL_D1_DIR=".wrangler/state/v3/d1/miniflare-D1DatabaseObject"
260
- LOCAL_DB_PATH="${LOCAL_D1_DIR}/${D1_ID_FROM_CONFIG}.sqlite"
261
- DRIZZLE_DB_URL="../${LOCAL_DB_PATH}"
262
-
263
- mkdir -p "$LOCAL_D1_DIR"
264
- touch "$LOCAL_DB_PATH"
448
+ # Apply schema.sql and seed
449
+ DB_BOOTSTRAP_OK=0
450
+ SEED_OK=0
265
451
 
266
- if [[ -f config/drizzle.config.ts ]]; then
267
- DRIZZLE_DB_URL="$DRIZZLE_DB_URL" node - <<'NODE'
268
- const fs = require('fs');
269
- const path = 'config/drizzle.config.ts';
270
- const nextUrl = process.env.DRIZZLE_DB_URL;
271
- let content = fs.readFileSync(path, 'utf8');
272
- const pattern = /url:\s*['"][^'"]*\.sqlite['"]/;
273
- if (pattern.test(content)) {
274
- content = content.replace(pattern, `url: '${nextUrl}'`);
275
- } else {
276
- // Fallback: append url if not found
277
- content = content.replace('dbCredentials: {', `dbCredentials: {\n url: '${nextUrl}',`);
278
- }
279
- fs.writeFileSync(path, content);
280
- NODE
281
- log_ok "Updated config/drizzle.config.ts with local DB path."
452
+ if [[ "$WRANGLER_AVAILABLE" -eq 1 ]]; then
453
+ log_info "Applying schema.sql to local D1..."
454
+ if pnpm db:schema:local >/tmp/bhono-db-schema.log 2>&1; then
455
+ DB_BOOTSTRAP_OK=1
282
456
  else
283
- log_warn "config/drizzle.config.ts not found. Skipping DB config update."
457
+ log_warn "Schema apply failed."
458
+ tail -n 20 /tmp/bhono-db-schema.log || true
284
459
  fi
285
460
  else
286
- log_warn "D1 id not found in wrangler.json. Skipping drizzle config update."
287
- fi
288
-
289
- # Push schema (no migrations) and seed
290
- DB_PUSH_OK=0
291
- SEED_OK=0
292
-
293
- log_info "Pushing schema to local D1..."
294
- if pnpm db:push >/tmp/bhono-db-push.log 2>&1; then
295
- DB_PUSH_OK=1
296
- else
297
- log_warn "Schema push failed."
298
- tail -n 20 /tmp/bhono-db-push.log || true
461
+ log_warn "Wrangler not available. Skipping schema apply."
299
462
  fi
300
463
 
301
464
  if [[ "$SKIP_SEED" -eq 0 ]]; then
302
- log_info "Generating seed data..."
303
- if pnpm db:seed >/tmp/bhono-seed-generate.log 2>&1; then
304
- if [[ -f seed.sql ]]; then
305
- if [[ "$WRANGLER_AVAILABLE" -eq 1 ]]; then
306
- log_info "Seeding local D1..."
307
- if $WRANGLER_CONFIG d1 execute "$DB_NAME" --local --file=seed.sql >/tmp/bhono-seed-apply.log 2>&1; then
308
- SEED_OK=1
309
- else
310
- log_warn "Seed apply failed."
311
- tail -n 20 /tmp/bhono-seed-apply.log || true
312
- fi
313
- else
314
- log_warn "Wrangler not available. Skipping seed apply."
315
- fi
465
+ if [[ "$WRANGLER_AVAILABLE" -eq 1 ]]; then
466
+ log_info "Seeding local D1..."
467
+ if pnpm db:seed:local >/tmp/bhono-seed.log 2>&1; then
468
+ SEED_OK=1
316
469
  else
317
- log_warn "seed.sql not found. Seed generation did not create the file."
470
+ log_warn "Seed apply failed."
471
+ tail -n 20 /tmp/bhono-seed.log || true
318
472
  fi
319
473
  else
320
- log_warn "Seed generation failed."
321
- tail -n 20 /tmp/bhono-seed-generate.log || true
474
+ log_warn "Wrangler not available. Skipping seed apply."
322
475
  fi
323
476
  else
324
477
  log_warn "Skipping seed step (--skip-seed)."
325
478
  fi
326
479
 
327
- rm -f /tmp/bhono-db-push.log /tmp/bhono-seed-generate.log /tmp/bhono-seed-apply.log >/dev/null 2>&1 || true
480
+ rm -f /tmp/bhono-db-schema.log /tmp/bhono-seed.log >/dev/null 2>&1 || true
481
+
482
+ # ============================================================================
483
+ # SYNC DATABASES (handle plugin hash mismatch)
484
+ # ============================================================================
485
+ # The Cloudflare Vite plugin creates SQLite with a hash based on config,
486
+ # not the database_id. We need to sync all databases after seeding.
487
+ log_info "Synchronizing database files..."
488
+
489
+ SQLITE_DIR=".wrangler/state/v3/d1/miniflare-D1DatabaseObject"
490
+ if [[ -d "$SQLITE_DIR" ]]; then
491
+ SQLITE_FILES=$(find "$SQLITE_DIR" -name "*.sqlite" -not -name "*-shm" -not -name "*-wal" 2>/dev/null || true)
492
+ if [[ -n "$SQLITE_FILES" ]]; then
493
+ # Find the database with actual tables (largest file usually has data)
494
+ MAIN_DB=$(ls -S $SQLITE_FILES 2>/dev/null | head -1)
495
+
496
+ if [[ -n "$MAIN_DB" ]]; then
497
+ # Check if main DB has tables
498
+ HAS_TABLES=$(sqlite3 "$MAIN_DB" ".tables" 2>/dev/null | wc -w || echo "0")
499
+
500
+ if [[ "$HAS_TABLES" -gt 0 ]]; then
501
+ for DB in $SQLITE_FILES; do
502
+ if [[ "$DB" != "$MAIN_DB" ]]; then
503
+ cp "$MAIN_DB" "$DB" 2>/dev/null || true
504
+ fi
505
+ done
506
+ log_ok " Synced $(echo "$SQLITE_FILES" | wc -l | tr -d ' ') database files"
507
+ else
508
+ log_warn " Main database has no tables. Skipping sync."
509
+ fi
510
+ fi
511
+ fi
512
+ fi
328
513
 
329
- if [[ "$DB_PUSH_OK" -eq 1 && "$SEED_OK" -eq 1 ]]; then
330
- log_ok "Local D1 ready with seed data."
514
+ if [[ "$DB_BOOTSTRAP_OK" -eq 1 && ( "$SEED_OK" -eq 1 || "$SKIP_SEED" -eq 1 ) ]]; then
515
+ log_ok "Local D1 ready with schema${SKIP_SEED:+ (seed skipped)}."
331
516
  else
332
517
  log_warn "Local D1 setup incomplete. Review warnings above."
333
518
  fi
@@ -0,0 +1,104 @@
1
+ #!/bin/bash
2
+ # scripts/sync-template.sh
3
+ # Syncs the main boilerplate to the npm package template
4
+
5
+ set -e
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ ROOT_DIR="$(dirname "$SCRIPT_DIR")"
9
+ TEMPLATE_DIR="$ROOT_DIR/packages/bhono-app/templates/base"
10
+
11
+ # Colors for output
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ NC='\033[0m' # No Color
16
+
17
+ echo -e "${YELLOW}Syncing boilerplate to npm template...${NC}"
18
+ echo "Source: $ROOT_DIR"
19
+ echo "Target: $TEMPLATE_DIR"
20
+ echo ""
21
+
22
+ # Ensure template directory exists
23
+ mkdir -p "$TEMPLATE_DIR"
24
+
25
+ # Rsync with exclusions
26
+ # --delete removes files in target that don't exist in source
27
+ # --checksum compares by content, not timestamp
28
+ rsync -av --checksum --delete \
29
+ --exclude='node_modules/' \
30
+ --exclude='dist/' \
31
+ --exclude='.git/' \
32
+ --exclude='.env' \
33
+ --exclude='.dev.vars' \
34
+ --exclude='db.sqlite' \
35
+ --exclude='*.log' \
36
+ --exclude='.DS_Store' \
37
+ --exclude='packages/' \
38
+ --exclude='pnpm-workspace.yaml' \
39
+ --exclude='pnpm-lock.yaml' \
40
+ --exclude='.changeset/' \
41
+ --exclude='docs/plans/' \
42
+ --exclude='.claude/settings.local.json' \
43
+ --exclude='coverage/' \
44
+ --exclude='test-results/' \
45
+ --exclude='playwright-report/' \
46
+ --exclude='.wrangler/' \
47
+ --exclude='worker-configuration.d.ts' \
48
+ "$ROOT_DIR/" "$TEMPLATE_DIR/"
49
+
50
+ # Rename .gitignore to _gitignore (npm ignores .gitignore in packages)
51
+ if [ -f "$TEMPLATE_DIR/.gitignore" ]; then
52
+ mv "$TEMPLATE_DIR/.gitignore" "$TEMPLATE_DIR/_gitignore"
53
+ echo -e "${GREEN}Renamed .gitignore to _gitignore${NC}"
54
+ fi
55
+
56
+ # Rename .env.example if it exists (keep as is, just ensure it exists)
57
+ if [ ! -f "$TEMPLATE_DIR/.env.example" ] && [ -f "$ROOT_DIR/.env.example" ]; then
58
+ cp "$ROOT_DIR/.env.example" "$TEMPLATE_DIR/.env.example"
59
+ fi
60
+
61
+ # Update package.json in template to use template variables
62
+ TEMPLATE_PKG="$TEMPLATE_DIR/package.json"
63
+ if [ -f "$TEMPLATE_PKG" ]; then
64
+ # Use Node.js to safely modify JSON
65
+ node -e "
66
+ const fs = require('fs');
67
+ const pkg = JSON.parse(fs.readFileSync('$TEMPLATE_PKG', 'utf8'));
68
+
69
+ // Set template variables
70
+ pkg.name = '{{projectName}}';
71
+ pkg.version = '0.1.0';
72
+ pkg.description = '{{projectDescription}}';
73
+
74
+ // Remove monorepo-specific fields
75
+ delete pkg.repository;
76
+ delete pkg.homepage;
77
+ delete pkg.bugs;
78
+ delete pkg.author;
79
+ delete pkg.license;
80
+
81
+ // Remove monorepo-specific scripts
82
+ delete pkg.scripts?.changeset;
83
+ delete pkg.scripts?.['changeset:version'];
84
+ delete pkg.scripts?.['changeset:publish'];
85
+
86
+ // Remove monorepo-specific devDependencies
87
+ delete pkg.devDependencies?.['@changesets/cli'];
88
+ delete pkg.devDependencies?.['@commitlint/cli'];
89
+ delete pkg.devDependencies?.['@commitlint/config-conventional'];
90
+ delete pkg.devDependencies?.husky;
91
+ delete pkg.devDependencies?.['lint-staged'];
92
+
93
+ fs.writeFileSync('$TEMPLATE_PKG', JSON.stringify(pkg, null, 2) + '\n');
94
+ console.log('Updated package.json with template variables');
95
+ "
96
+ fi
97
+
98
+ echo ""
99
+ echo -e "${GREEN}Sync complete!${NC}"
100
+
101
+ # Show diff summary
102
+ echo ""
103
+ echo "Files synced:"
104
+ find "$TEMPLATE_DIR" -type f | wc -l | xargs echo " Total files:"
@@ -27,7 +27,12 @@ export function useAuth() {
27
27
  queryKey: ['auth', 'me'],
28
28
  queryFn: fetchMe,
29
29
  retry: false,
30
+ // Balance between reducing API calls and detecting expired sessions
30
31
  staleTime: 1000 * 60 * 5, // 5 minutes
32
+ gcTime: 1000 * 60 * 30, // 30 minutes
33
+ refetchOnMount: false, // Avoid redundant calls on component mount
34
+ refetchOnWindowFocus: true, // Re-check when user returns to tab (industry standard)
35
+ refetchOnReconnect: true, // Re-check after network reconnection
31
36
  })
32
37
 
33
38
  const logoutMutation = useMutation({
@@ -82,7 +82,7 @@ function DashboardPage() {
82
82
  </CardHeader>
83
83
  <CardContent>
84
84
  <p className="text-sm text-muted-foreground">
85
- Built with Drizzle ORM for type-safe database queries.
85
+ Built with SQL-first access to Cloudflare D1.
86
86
  </p>
87
87
  </CardContent>
88
88
  </Card>
@@ -100,7 +100,7 @@ function HomePage() {
100
100
  <TechBadge name="Hono" />
101
101
  <TechBadge name="React" />
102
102
  <TechBadge name="TypeScript" />
103
- <TechBadge name="Drizzle" />
103
+ <TechBadge name="SQL" />
104
104
  <TechBadge name="Tailwind" />
105
105
  <TechBadge name="Cloudflare" />
106
106
  </div>
@@ -1,12 +1,10 @@
1
1
  // src/server/db/client.ts
2
- import { drizzle } from 'drizzle-orm/d1'
3
- import * as schema from './schema'
4
2
 
5
3
  export function createDb(d1: D1Database) {
6
- return drizzle(d1, { schema })
4
+ return d1
7
5
  }
8
6
 
9
- export type Database = ReturnType<typeof createDb>
7
+ export type Database = D1Database
10
8
 
11
9
  // For use in middleware - db instance per request
12
- export type DbInstance = Database
10
+ export type DbInstance = D1Database
@@ -0,0 +1,81 @@
1
+ // src/server/db/records.ts
2
+
3
+ export type UserStatus = 'active' | 'inactive'
4
+
5
+ export interface UserRecord {
6
+ id: string
7
+ googleId: string
8
+ email: string
9
+ name: string
10
+ avatarUrl: string | null
11
+ status: UserStatus
12
+ providerIds: string[]
13
+ isSuperAdmin: boolean
14
+ createdAt: string
15
+ updatedAt: string
16
+ deletedAt: string | null
17
+ createdById?: string | null
18
+ updatedById?: string | null
19
+ deletedById?: string | null
20
+ }
21
+
22
+ export interface AccountRecord {
23
+ id: string
24
+ name: string
25
+ description: string | null
26
+ domain: string | null
27
+ createdAt: string
28
+ updatedAt: string
29
+ deletedAt: string | null
30
+ }
31
+
32
+ export interface UserAccountRecord {
33
+ userId: string
34
+ accountId: string
35
+ role: string
36
+ }
37
+
38
+ export interface RefreshTokenRecord {
39
+ id: string
40
+ userId: string
41
+ tokenHash: string
42
+ expiresAt: number
43
+ createdAt: number
44
+ revokedAt: number | null
45
+ }
46
+
47
+ export interface InvitationRecord {
48
+ id: string
49
+ accountId: string
50
+ email: string
51
+ role: string
52
+ token: string
53
+ invitedById: string
54
+ expiresAt: string
55
+ acceptedAt: string | null
56
+ createdAt: string
57
+ }
58
+
59
+ export type AuditAction =
60
+ | 'INSERT'
61
+ | 'UPDATE'
62
+ | 'DELETE'
63
+ | 'LOGIN'
64
+ | 'LOGOUT'
65
+ | 'SIGNUP'
66
+ | 'TOKEN_REFRESH'
67
+ | 'LOGIN_FAILED'
68
+
69
+ export interface AuditLogRecord {
70
+ id: string
71
+ transactionId: string
72
+ accountId: string | null
73
+ userId: string | null
74
+ entity: string
75
+ entityId: string
76
+ action: AuditAction
77
+ changes: Record<string, unknown> | null
78
+ ipAddress: string | null
79
+ userAgent: string | null
80
+ timestamp: string
81
+ }
@@ -4,7 +4,7 @@
4
4
  // Run with: npm run db:seed
5
5
  //
6
6
  // The generated SQL can be executed via wrangler:
7
- // npx wrangler d1 execute DB --local --file=seed.sql
7
+ // pnpm db:seed:local
8
8
 
9
9
  import { generateStrongPassword } from '../lib/password'
10
10
 
@@ -243,7 +243,8 @@ function printSummary(): void {
243
243
  console.log('\n🔐 Sample Strong Password:', generateStrongPassword())
244
244
 
245
245
  console.log('\n✅ Run the following command to seed the local database:')
246
- console.log(' npx wrangler d1 execute {{projectName}}-db --local --file=seed.sql\n')
246
+ console.log(' pnpm db:seed:local')
247
+ console.log(' # or: wrangler --config config/wrangler.json d1 execute <db-name> --local --file=seed.sql\n')
247
248
  }
248
249
 
249
250
  // ============================================================================