insforge 0.3.2 → 1.2.10

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 (507) hide show
  1. package/.claude-plugin/marketplace.json +20 -0
  2. package/.cursor/rules/cursor-rules.mdc +94 -0
  3. package/.dockerignore +3 -0
  4. package/.env.example +33 -4
  5. package/.github/ISSUE_TEMPLATE/bug_report.yml +13 -60
  6. package/.github/ISSUE_TEMPLATE/config.yml +2 -2
  7. package/.github/ISSUE_TEMPLATE/feature_request.yml +10 -63
  8. package/.github/PULL_REQUEST_TEMPLATE.md +7 -0
  9. package/.github/workflows/build-image.yml +2 -1
  10. package/.github/workflows/e2e.yml +63 -0
  11. package/CHANGELOG.md +41 -0
  12. package/CLAUDE_PLUGIN.md +104 -0
  13. package/CODE_OF_CONDUCT.md +128 -0
  14. package/CONTRIBUTING.md +1 -1
  15. package/Dockerfile +4 -1
  16. package/README.md +66 -18
  17. package/assets/mcpInstallv2.png +0 -0
  18. package/assets/sampleResponse.png +0 -0
  19. package/auth/index.html +13 -0
  20. package/auth/package.json +28 -0
  21. package/auth/public/favicon.ico +0 -0
  22. package/auth/src/App.tsx +33 -0
  23. package/auth/src/components/ErrorCard.tsx +37 -0
  24. package/auth/src/components/Layout.tsx +13 -0
  25. package/auth/src/index.css +19 -0
  26. package/auth/src/lib/broadcastService.ts +115 -0
  27. package/auth/src/lib/utils.ts +11 -0
  28. package/auth/src/main.tsx +22 -0
  29. package/auth/src/pages/ForgotPasswordPage.tsx +11 -0
  30. package/auth/src/pages/ResetPasswordPage.tsx +11 -0
  31. package/auth/src/pages/SignInPage.tsx +57 -0
  32. package/auth/src/pages/SignUpPage.tsx +57 -0
  33. package/auth/src/pages/VerifyEmailPage.tsx +20 -0
  34. package/auth/src/vite-env.d.ts +10 -0
  35. package/auth/tsconfig.json +32 -0
  36. package/auth/tsconfig.node.json +11 -0
  37. package/auth/vite.config.ts +25 -0
  38. package/backend/package.json +9 -9
  39. package/backend/src/api/{middleware → middlewares}/auth.ts +8 -9
  40. package/backend/src/api/middlewares/rate-limiters.ts +127 -0
  41. package/backend/src/api/routes/{ai.ts → ai/index.routes.ts} +20 -24
  42. package/backend/src/api/routes/auth/index.routes.ts +570 -0
  43. package/backend/src/api/routes/auth/oauth.routes.ts +448 -0
  44. package/backend/src/api/routes/{database.advance.ts → database/advance.routes.ts} +107 -65
  45. package/backend/src/api/routes/database/index.routes.ts +13 -0
  46. package/backend/src/api/routes/{database.records.ts → database/records.routes.ts} +22 -8
  47. package/backend/src/api/routes/{database.tables.ts → database/tables.routes.ts} +20 -23
  48. package/backend/src/api/routes/docs/index.routes.ts +76 -0
  49. package/backend/src/api/routes/functions/index.routes.ts +188 -0
  50. package/backend/src/api/routes/{logs.ts → logs/index.routes.ts} +25 -30
  51. package/backend/src/api/routes/{metadata.ts → metadata/index.routes.ts} +21 -31
  52. package/backend/src/api/routes/{secrets.ts → secrets/index.routes.ts} +27 -22
  53. package/backend/src/api/routes/{storage.ts → storage/index.routes.ts} +34 -53
  54. package/backend/src/api/routes/usage/index.routes.ts +89 -0
  55. package/backend/src/infra/config/app.config.ts +51 -0
  56. package/backend/src/{core/database/manager.ts → infra/database/database.manager.ts} +76 -85
  57. package/backend/src/infra/database/migrations/013_create-auth-schema-functions.sql +44 -0
  58. package/backend/src/infra/database/migrations/014_add-updated-at-trigger-user-table.sql +8 -0
  59. package/backend/src/infra/database/migrations/015_create-auth-config-and-email-otp-tables.sql +60 -0
  60. package/backend/src/infra/database/migrations/016_update-auth-config-and-email-otp.sql +24 -0
  61. package/backend/src/{core/secrets/encryption.ts → infra/security/encryption.manager.ts} +3 -2
  62. package/backend/src/infra/security/token.manager.ts +125 -0
  63. package/backend/src/{core/socket/socket.ts → infra/socket/socket.manager.ts} +15 -15
  64. package/backend/src/providers/ai/openrouter.provider.ts +377 -0
  65. package/backend/src/providers/email/base.provider.ts +41 -0
  66. package/backend/src/providers/email/cloud.provider.ts +187 -0
  67. package/backend/src/{core/logs/providers → providers/logs}/base.provider.ts +11 -11
  68. package/backend/src/{core/logs/providers → providers/logs}/cloudwatch.provider.ts +61 -38
  69. package/backend/src/providers/logs/local.provider.ts +185 -0
  70. package/backend/src/providers/oauth/base.provider.ts +29 -0
  71. package/backend/src/providers/oauth/discord.provider.ts +195 -0
  72. package/backend/src/providers/oauth/facebook.provider.ts +194 -0
  73. package/backend/src/providers/oauth/github.provider.ts +208 -0
  74. package/backend/src/providers/oauth/google.provider.ts +249 -0
  75. package/backend/src/providers/oauth/index.ts +7 -0
  76. package/backend/src/providers/oauth/linkedin.provider.ts +240 -0
  77. package/backend/src/providers/oauth/microsoft.provider.ts +169 -0
  78. package/backend/src/providers/oauth/x.provider.ts +202 -0
  79. package/backend/src/providers/storage/base.provider.ts +29 -0
  80. package/backend/src/providers/storage/local.provider.ts +103 -0
  81. package/backend/src/providers/storage/s3.provider.ts +313 -0
  82. package/backend/src/server.ts +70 -74
  83. package/backend/src/{core/ai/config.ts → services/ai/ai-config.service.ts} +19 -24
  84. package/backend/src/services/ai/ai-model.service.ts +60 -0
  85. package/backend/src/{core/ai/usage.ts → services/ai/ai-usage.service.ts} +28 -35
  86. package/backend/src/{core/ai/chat.ts → services/ai/chat-completion.service.ts} +37 -24
  87. package/backend/src/services/ai/helpers.ts +64 -0
  88. package/backend/src/{core/ai/image.ts → services/ai/image-generation.service.ts} +17 -19
  89. package/backend/src/services/ai/index.ts +13 -0
  90. package/backend/src/services/auth/auth-config.service.ts +250 -0
  91. package/backend/src/services/auth/auth-otp.service.ts +424 -0
  92. package/backend/src/services/auth/auth.service.ts +1136 -0
  93. package/backend/src/services/auth/index.ts +4 -0
  94. package/backend/src/{core/auth/oauth.ts → services/auth/oauth-config.service.ts} +106 -52
  95. package/backend/src/{core/database/advance.ts → services/database/database-advance.service.ts} +97 -131
  96. package/backend/src/services/database/database-table.service.ts +811 -0
  97. package/backend/src/services/email/email.service.ts +75 -0
  98. package/backend/src/{core/functions/functions.ts → services/functions/function.service.ts} +95 -88
  99. package/backend/src/{core/logs/audit.ts → services/logs/audit.service.ts} +92 -75
  100. package/backend/src/services/logs/log.service.ts +73 -0
  101. package/backend/src/{core/secrets/secrets.ts → services/secrets/secret.service.ts} +48 -66
  102. package/backend/src/services/storage/storage.service.ts +617 -0
  103. package/backend/src/services/usage/usage.service.ts +149 -0
  104. package/backend/src/types/auth.ts +66 -2
  105. package/backend/src/types/email.ts +8 -0
  106. package/backend/src/types/error-constants.ts +4 -0
  107. package/backend/src/types/logs.ts +0 -29
  108. package/backend/src/{core/socket/types.ts → types/socket.ts} +5 -6
  109. package/backend/src/utils/environment.ts +9 -3
  110. package/backend/src/utils/logger.ts +20 -2
  111. package/backend/src/utils/seed.ts +150 -57
  112. package/backend/src/utils/sql-parser.ts +1 -1
  113. package/backend/src/utils/utils.ts +114 -0
  114. package/backend/src/utils/validations.ts +40 -4
  115. package/backend/tests/local/test-ai-config.sh +129 -0
  116. package/backend/tests/local/test-ai-usage.sh +80 -0
  117. package/backend/tests/local/test-auth-router.sh +1 -1
  118. package/backend/tests/local/test-e2e.sh +1 -1
  119. package/backend/tests/local/test-functions.sh +123 -0
  120. package/backend/tests/local/test-logs.sh +132 -0
  121. package/backend/tests/local/test-public-bucket.sh +3 -3
  122. package/backend/tests/local/test-secrets.sh +14 -12
  123. package/backend/tests/local/test-traditional-rest.sh +2 -2
  124. package/backend/tests/manual/test-rawsql-modes.sh +244 -0
  125. package/backend/tests/test-config.sh +37 -1
  126. package/backend/tests/unit/cloud-token.test.ts +48 -0
  127. package/backend/tests/unit/constant.test.ts +8 -0
  128. package/backend/tests/unit/email.test.ts +372 -0
  129. package/backend/tests/unit/environment.test.ts +59 -0
  130. package/backend/tests/unit/helpers.test.ts +63 -0
  131. package/backend/tests/unit/logger.test.ts +22 -0
  132. package/backend/tests/unit/rate-limit.test.ts +154 -0
  133. package/backend/tests/unit/response.test.ts +58 -0
  134. package/backend/tests/unit/sql-parser.test.ts +74 -0
  135. package/backend/tests/unit/uuid.test.ts +21 -0
  136. package/backend/tests/unit/validations.test.ts +80 -0
  137. package/backend/tsconfig.json +1 -1
  138. package/backend/vitest.config.ts +11 -0
  139. package/claude-plugin/.claude-plugin/plugin.json +24 -0
  140. package/claude-plugin/README.md +133 -0
  141. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +270 -0
  142. package/docker-compose.prod.yml +60 -4
  143. package/docker-compose.yml +65 -4
  144. package/docker-init/db/db-init.sql +6 -34
  145. package/docker-init/logs/vector.yml +236 -0
  146. package/docs/README.md +44 -0
  147. package/docs/changelog.mdx +67 -0
  148. package/docs/core-concepts/ai/architecture.mdx +373 -0
  149. package/docs/core-concepts/ai/sdk.mdx +213 -0
  150. package/docs/core-concepts/authentication/architecture.mdx +278 -0
  151. package/docs/core-concepts/authentication/sdk.mdx +414 -0
  152. package/docs/core-concepts/authentication/ui-components/customization.mdx +529 -0
  153. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +221 -0
  154. package/docs/core-concepts/authentication/ui-components/react-router.mdx +184 -0
  155. package/docs/core-concepts/authentication/ui-components/react.mdx +129 -0
  156. package/docs/core-concepts/database/architecture.mdx +256 -0
  157. package/docs/core-concepts/database/sdk.mdx +382 -0
  158. package/docs/core-concepts/functions/architecture.mdx +105 -0
  159. package/docs/core-concepts/functions/sdk.mdx +184 -0
  160. package/docs/core-concepts/storage/architecture.mdx +243 -0
  161. package/docs/core-concepts/storage/sdk.mdx +253 -0
  162. package/docs/deployment/README.md +94 -0
  163. package/docs/deployment/deploy-to-aws-ec2.md +565 -0
  164. package/docs/deployment/deploy-to-azure-virtual-machines.md +313 -0
  165. package/docs/deployment/deploy-to-google-cloud-compute-engine.md +613 -0
  166. package/docs/deployment/deploy-to-render.md +441 -0
  167. package/docs/docs.json +210 -0
  168. package/docs/examples/framework-guides/nextjs.mdx +131 -0
  169. package/docs/examples/framework-guides/nuxt.mdx +165 -0
  170. package/docs/examples/framework-guides/react.mdx +165 -0
  171. package/docs/examples/framework-guides/svelte.mdx +153 -0
  172. package/docs/examples/framework-guides/vue.mdx +159 -0
  173. package/docs/examples/overview.mdx +67 -0
  174. package/docs/favicon.svg +19 -0
  175. package/docs/images/changelog/nov-2025/auth-components.webp +0 -0
  176. package/docs/images/changelog/nov-2025/database-metadata.webp +0 -0
  177. package/docs/images/changelog/nov-2025/quickstart-prompts.webp +0 -0
  178. package/docs/images/changelog/nov-2025/sql-editor.webp +0 -0
  179. package/docs/images/changelog/nov-2025/usage-page.webp +0 -0
  180. package/docs/images/changelog/october-2025/csv-upload.webp +0 -0
  181. package/docs/images/changelog/october-2025/logs-feature.webp +0 -0
  182. package/docs/images/changelog/october-2025/oauth-providers.webp +0 -0
  183. package/docs/images/checks-passed.png +0 -0
  184. package/docs/images/dashboard-connect-expanded.png +0 -0
  185. package/docs/images/dashboard-connect.png +0 -0
  186. package/docs/images/hero-dark.png +0 -0
  187. package/docs/images/hero-light.png +0 -0
  188. package/docs/images/icons/ai.svg +4 -0
  189. package/docs/images/icons/auth.svg +1 -0
  190. package/docs/images/icons/database.svg +1 -0
  191. package/docs/images/icons/function.svg +1 -0
  192. package/docs/images/icons/storage.svg +1 -0
  193. package/docs/images/logos/nextjs.svg +4 -0
  194. package/docs/images/logos/nuxt.svg +4 -0
  195. package/docs/images/logos/react.svg +5 -0
  196. package/docs/images/logos/svelte.svg +4 -0
  197. package/docs/images/logos/vue.svg +5 -0
  198. package/docs/images/mcp-install.png +0 -0
  199. package/docs/images/onboarding-mcp.png +0 -0
  200. package/docs/insforge-instructions-sdk.md +55 -374
  201. package/docs/introduction.mdx +45 -0
  202. package/docs/logo/dark.svg +22 -0
  203. package/docs/logo/light.svg +20 -0
  204. package/docs/partnership.mdx +647 -0
  205. package/docs/quickstart.mdx +83 -0
  206. package/docs/showcase/2048-arena.png +0 -0
  207. package/docs/showcase/framegen-cloud.png +0 -0
  208. package/docs/showcase/line-connect-race.png +0 -0
  209. package/docs/showcase/moment-vibe.png +0 -0
  210. package/docs/showcase/national-flags.png +0 -0
  211. package/docs/showcase/pokemon-vibe.png +0 -0
  212. package/docs/showcase/pure-browse-buy.png +0 -0
  213. package/docs/showcase.mdx +52 -0
  214. package/docs/snippets/sdk-installation.mdx +22 -0
  215. package/docs/snippets/service-icons.mdx +27 -0
  216. package/eslint.config.js +10 -3
  217. package/frontend/package.json +10 -4
  218. package/frontend/src/App.tsx +13 -82
  219. package/frontend/src/assets/icons/connected.svg +3 -0
  220. package/frontend/src/assets/icons/loader.svg +9 -0
  221. package/frontend/src/assets/logos/apple.svg +4 -0
  222. package/frontend/src/assets/logos/discord.svg +1 -1
  223. package/frontend/src/assets/logos/facebook.svg +3 -0
  224. package/frontend/src/assets/logos/instagram.svg +2 -0
  225. package/frontend/src/assets/logos/linkedin.svg +3 -0
  226. package/frontend/src/assets/logos/microsoft.svg +1 -0
  227. package/frontend/src/assets/logos/spotify.svg +17 -0
  228. package/frontend/src/assets/logos/tiktok.svg +6 -0
  229. package/frontend/src/assets/logos/x.svg +3 -0
  230. package/frontend/src/components/Checkbox.tsx +27 -29
  231. package/frontend/src/components/CodeBlock.tsx +55 -2
  232. package/frontend/src/components/CodeEditor.tsx +92 -0
  233. package/frontend/src/components/ConfirmDialog.tsx +1 -1
  234. package/frontend/src/components/ConnectCTA.tsx +38 -0
  235. package/frontend/src/components/CopyButton.tsx +52 -15
  236. package/frontend/src/components/ErrorState.tsx +1 -2
  237. package/frontend/src/components/FeatureSidebar.tsx +6 -6
  238. package/frontend/src/components/FeatureSidebarItem.tsx +2 -2
  239. package/frontend/src/components/JsonHighlight.tsx +21 -9
  240. package/frontend/src/components/ProjectInfoModal.tsx +128 -0
  241. package/frontend/src/components/PromptDialog.tsx +1 -4
  242. package/frontend/src/components/SearchInput.tsx +1 -2
  243. package/frontend/src/components/Stepper.tsx +53 -0
  244. package/frontend/src/components/ThemeToggle.tsx +3 -3
  245. package/frontend/src/components/datagrid/DataGrid.tsx +25 -32
  246. package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +1 -2
  247. package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +2 -4
  248. package/frontend/src/components/datagrid/index.ts +23 -0
  249. package/frontend/src/components/index.ts +23 -30
  250. package/frontend/src/components/layout/AppHeader.tsx +133 -92
  251. package/frontend/src/components/layout/AppSidebar.tsx +80 -170
  252. package/frontend/src/components/layout/Layout.tsx +12 -23
  253. package/frontend/src/components/layout/PrimaryMenu.tsx +187 -0
  254. package/frontend/src/components/layout/SecondaryMenu.tsx +70 -0
  255. package/frontend/src/components/layout/index.ts +5 -0
  256. package/frontend/src/components/radix/Tooltip.tsx +24 -13
  257. package/frontend/src/components/radix/index.ts +22 -0
  258. package/frontend/src/features/ai/components/AIConfigCard.tsx +129 -83
  259. package/frontend/src/features/ai/components/AIEmptyState.tsx +12 -7
  260. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +101 -0
  261. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -0
  262. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -0
  263. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -0
  264. package/frontend/src/features/ai/components/index.ts +6 -0
  265. package/frontend/src/features/ai/helpers.ts +57 -71
  266. package/frontend/src/features/ai/hooks/useAIConfigs.ts +39 -113
  267. package/frontend/src/features/ai/hooks/useAIUsage.ts +0 -2
  268. package/frontend/src/features/ai/page/AIPage.tsx +67 -79
  269. package/frontend/src/features/ai/services/ai.service.ts +5 -5
  270. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -0
  271. package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +53 -30
  272. package/frontend/src/features/auth/components/UserFormDialog.tsx +13 -6
  273. package/frontend/src/features/auth/components/UsersDataGrid.tsx +44 -14
  274. package/frontend/src/features/auth/components/index.ts +5 -0
  275. package/frontend/src/features/auth/helpers.tsx +200 -0
  276. package/frontend/src/features/auth/hooks/useAnonToken.ts +30 -0
  277. package/frontend/src/features/auth/hooks/useAuthConfig.ts +48 -0
  278. package/frontend/src/features/auth/hooks/useOAuthConfig.ts +14 -10
  279. package/frontend/src/features/auth/hooks/useUsers.ts +43 -5
  280. package/frontend/src/features/auth/index.ts +3 -2
  281. package/frontend/src/features/auth/page/AuthMethodsPage.tsx +275 -0
  282. package/frontend/src/features/auth/page/ConfigurationPage.tsx +395 -0
  283. package/frontend/src/features/auth/page/UsersPage.tsx +285 -0
  284. package/frontend/src/features/auth/services/anonToken.service.ts +11 -0
  285. package/frontend/src/features/auth/services/config.service.ts +19 -0
  286. package/frontend/src/features/auth/services/{oauth.service.ts → oauth-config.service.ts} +4 -4
  287. package/frontend/src/features/auth/services/{auth.service.ts → user.service.ts} +7 -53
  288. package/frontend/src/features/dashboard/components/ConnectionSuccessBanner.tsx +35 -0
  289. package/frontend/src/features/dashboard/components/PromptCard.tsx +21 -0
  290. package/frontend/src/features/dashboard/components/PromptDialog.tsx +103 -0
  291. package/frontend/src/features/dashboard/components/StatsCard.tsx +50 -0
  292. package/frontend/src/features/dashboard/components/index.ts +4 -0
  293. package/frontend/src/features/dashboard/page/DashboardPage.tsx +187 -169
  294. package/frontend/src/features/dashboard/prompts/ai-chatbot.ts +13 -0
  295. package/frontend/src/features/dashboard/prompts/crm-system.ts +13 -0
  296. package/frontend/src/features/dashboard/prompts/ecommerce-platform.ts +12 -0
  297. package/frontend/src/features/dashboard/prompts/index.ts +31 -0
  298. package/frontend/src/features/dashboard/prompts/instagram-clone.ts +11 -0
  299. package/frontend/src/features/dashboard/prompts/notion-clone.ts +14 -0
  300. package/frontend/src/features/dashboard/prompts/reddit-clone.ts +12 -0
  301. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +48 -17
  302. package/frontend/src/features/database/components/ForeignKeyCell.tsx +15 -34
  303. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +19 -20
  304. package/frontend/src/features/database/components/LinkRecordModal.tsx +120 -125
  305. package/frontend/src/features/database/components/RecordFormDialog.tsx +22 -33
  306. package/frontend/src/features/database/components/RecordFormField.tsx +45 -47
  307. package/frontend/src/features/database/components/TableEmptyState.tsx +6 -5
  308. package/frontend/src/features/database/components/TableForm.tsx +28 -15
  309. package/frontend/src/features/database/components/TableFormColumn.tsx +2 -3
  310. package/frontend/src/features/database/components/TableSidebar.tsx +1 -1
  311. package/frontend/src/features/database/components/TablesEmptyState.tsx +48 -0
  312. package/frontend/src/features/database/components/TemplateCard.tsx +37 -0
  313. package/frontend/src/features/database/components/TemplatePreview.tsx +92 -0
  314. package/frontend/src/features/database/components/index.ts +19 -0
  315. package/frontend/src/features/database/constants.ts +28 -2
  316. package/frontend/src/features/database/contexts/SQLEditorContext.tsx +188 -0
  317. package/frontend/src/features/database/helpers.ts +2 -2
  318. package/frontend/src/features/database/hooks/useCSVImport.ts +29 -0
  319. package/frontend/src/features/database/hooks/useFullMetadata.ts +18 -0
  320. package/frontend/src/features/database/hooks/useRawSQL.ts +55 -0
  321. package/frontend/src/features/database/hooks/useRecords.ts +139 -0
  322. package/frontend/src/features/database/hooks/useTables.ts +131 -0
  323. package/frontend/src/features/database/index.ts +6 -1
  324. package/frontend/src/features/database/page/FunctionsPage.tsx +211 -0
  325. package/frontend/src/features/database/page/IndexesPage.tsx +240 -0
  326. package/frontend/src/features/database/page/PoliciesPage.tsx +248 -0
  327. package/frontend/src/features/database/page/SQLEditorPage.tsx +382 -0
  328. package/frontend/src/features/database/page/{DatabasePage.tsx → TablesPage.tsx} +186 -185
  329. package/frontend/src/features/database/page/TemplatesPage.tsx +39 -0
  330. package/frontend/src/features/database/page/TriggersPage.tsx +242 -0
  331. package/frontend/src/features/database/services/advance.service.ts +66 -0
  332. package/frontend/src/features/database/services/{database.service.ts → record.service.ts} +67 -64
  333. package/frontend/src/features/database/services/table.service.ts +64 -0
  334. package/frontend/src/features/database/templates/ai-chatbot.ts +402 -0
  335. package/frontend/src/features/database/templates/crm-system.ts +528 -0
  336. package/frontend/src/features/database/templates/ecommerce-platform.ts +553 -0
  337. package/frontend/src/features/database/templates/index.ts +34 -0
  338. package/frontend/src/features/database/templates/instagram-clone.ts +222 -0
  339. package/frontend/src/features/database/templates/notion-clone.ts +483 -0
  340. package/frontend/src/features/database/templates/reddit-clone.ts +526 -0
  341. package/frontend/src/features/functions/components/FunctionRow.tsx +2 -1
  342. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +1 -1
  343. package/frontend/src/features/functions/components/SecretRow.tsx +1 -1
  344. package/frontend/src/features/functions/components/index.ts +5 -0
  345. package/frontend/src/features/functions/hooks/useFunctions.ts +4 -4
  346. package/frontend/src/features/{secrets → functions}/hooks/useSecrets.ts +5 -5
  347. package/frontend/src/features/functions/page/FunctionsPage.tsx +160 -17
  348. package/frontend/src/features/functions/{components/SecretsContent.tsx → page/SecretsPage.tsx} +8 -12
  349. package/frontend/src/features/functions/services/{functions.service.ts → function.service.ts} +2 -2
  350. package/frontend/src/features/{secrets/services/secrets.service.ts → functions/services/secret.service.ts} +2 -2
  351. package/frontend/src/features/login/hooks/usePartnerOrigin.ts +27 -0
  352. package/frontend/src/features/login/page/CloudLoginPage.tsx +79 -54
  353. package/frontend/src/features/login/page/LoginPage.tsx +16 -23
  354. package/frontend/src/features/login/services/partnership.service.ts +65 -0
  355. package/frontend/src/features/logs/components/LogsDataGrid.tsx +89 -0
  356. package/frontend/src/features/logs/components/SeverityBadge.tsx +18 -0
  357. package/frontend/src/features/logs/components/index.ts +2 -0
  358. package/frontend/src/features/logs/helpers.ts +24 -0
  359. package/frontend/src/features/logs/hooks/useAuditLogs.ts +4 -4
  360. package/frontend/src/features/logs/hooks/useLogSources.ts +137 -0
  361. package/frontend/src/features/logs/hooks/useLogs.ts +163 -0
  362. package/frontend/src/features/logs/hooks/useMcpUsage.ts +181 -0
  363. package/frontend/src/features/logs/index.ts +8 -2
  364. package/frontend/src/features/logs/page/AuditsPage.tsx +91 -38
  365. package/frontend/src/features/logs/page/LogsPage.tsx +152 -0
  366. package/frontend/src/features/logs/page/MCPLogsPage.tsx +84 -0
  367. package/frontend/src/features/logs/services/audit.service.ts +63 -0
  368. package/frontend/src/features/logs/services/log.service.ts +15 -110
  369. package/frontend/src/features/logs/services/usage.service.ts +31 -0
  370. package/frontend/src/features/onboard/components/McpConnectionStatus.tsx +68 -0
  371. package/frontend/src/features/onboard/components/OnboardingModal.tsx +267 -0
  372. package/frontend/src/features/onboard/components/VideoDemoModal.tsx +38 -0
  373. package/frontend/src/features/onboard/components/index.ts +4 -0
  374. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +2 -2
  375. package/frontend/src/features/onboard/components/mcp/{mcp-helper.tsx → helpers.tsx} +8 -8
  376. package/frontend/src/features/onboard/components/mcp/index.ts +2 -3
  377. package/frontend/src/features/onboard/index.ts +13 -3
  378. package/frontend/src/features/storage/components/BucketEmptyState.tsx +9 -6
  379. package/frontend/src/features/storage/components/BucketFormDialog.tsx +25 -41
  380. package/frontend/src/features/storage/components/FilePreviewDialog.tsx +20 -8
  381. package/frontend/src/features/storage/components/StorageDataGrid.tsx +4 -3
  382. package/frontend/src/features/storage/components/StorageManager.tsx +23 -34
  383. package/frontend/src/features/storage/components/index.ts +12 -0
  384. package/frontend/src/features/storage/hooks/useStorage.ts +208 -0
  385. package/frontend/src/features/storage/page/StoragePage.tsx +41 -115
  386. package/frontend/src/features/storage/services/storage.service.ts +22 -1
  387. package/frontend/src/features/visualizer/components/AuthNode.tsx +72 -56
  388. package/frontend/src/features/visualizer/components/BucketNode.tsx +4 -4
  389. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +108 -80
  390. package/frontend/src/features/visualizer/components/TableNode.tsx +34 -41
  391. package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +12 -4
  392. package/frontend/src/features/visualizer/page/VisualizerPage.tsx +33 -29
  393. package/frontend/src/index.css +1 -0
  394. package/frontend/src/lib/analytics/posthog.tsx +27 -0
  395. package/frontend/src/lib/contexts/AuthContext.tsx +38 -31
  396. package/frontend/src/lib/contexts/SocketContext.tsx +5 -6
  397. package/frontend/src/{features/metadata → lib}/hooks/useMetadata.ts +1 -1
  398. package/frontend/src/lib/hooks/useToast.tsx +6 -2
  399. package/frontend/src/lib/routing/AppRoutes.tsx +84 -0
  400. package/frontend/src/lib/routing/RequireAuth.tsx +27 -0
  401. package/frontend/src/lib/utils/cloudMessaging.ts +20 -0
  402. package/frontend/src/lib/utils/menuItems.ts +183 -0
  403. package/frontend/src/lib/utils/{validation-schemas.ts → schemaValidations.ts} +10 -5
  404. package/frontend/src/lib/utils/utils.ts +19 -1
  405. package/frontend/src/vite-env.d.ts +1 -0
  406. package/frontend/vite.config.ts +5 -3
  407. package/functions/server.ts +28 -3
  408. package/functions/worker-template.js +15 -4
  409. package/i18n/README.ar.md +130 -0
  410. package/i18n/README.de.md +130 -0
  411. package/i18n/README.es.md +154 -0
  412. package/i18n/README.fr.md +134 -0
  413. package/i18n/README.hi.md +129 -0
  414. package/i18n/README.ja.md +174 -0
  415. package/i18n/README.ko.md +137 -0
  416. package/i18n/README.pt-BR.md +131 -0
  417. package/i18n/README.ru.md +129 -0
  418. package/i18n/README.zh-CN.md +133 -0
  419. package/openapi/ai.yaml +31 -4
  420. package/openapi/auth.yaml +827 -146
  421. package/package.json +16 -7
  422. package/shared-schemas/package.json +1 -1
  423. package/shared-schemas/src/ai-api.schema.ts +34 -58
  424. package/shared-schemas/src/ai.schema.ts +5 -0
  425. package/shared-schemas/src/auth-api.schema.ts +154 -8
  426. package/shared-schemas/src/auth.schema.ts +42 -6
  427. package/shared-schemas/src/cloud-events.schema.ts +57 -0
  428. package/shared-schemas/src/database-api.schema.ts +3 -3
  429. package/shared-schemas/src/database.schema.ts +1 -1
  430. package/shared-schemas/src/index.ts +1 -0
  431. package/shared-schemas/src/logs-api.schema.ts +7 -1
  432. package/shared-schemas/src/logs.schema.ts +26 -0
  433. package/shared-schemas/src/metadata.schema.ts +9 -4
  434. package/test-gemini.sh +35 -0
  435. package/test-usage-admin.sh +57 -0
  436. package/test-usage.sh +50 -0
  437. package/zeabur/README.md +13 -0
  438. package/zeabur/template.yml +1032 -0
  439. package/.github/workflows/deploy-aws.yml +0 -130
  440. package/backend/src/api/routes/agent.ts +0 -29
  441. package/backend/src/api/routes/auth.oauth.ts +0 -482
  442. package/backend/src/api/routes/auth.ts +0 -386
  443. package/backend/src/api/routes/docs.ts +0 -66
  444. package/backend/src/api/routes/functions.ts +0 -183
  445. package/backend/src/api/routes/openapi.ts +0 -82
  446. package/backend/src/api/routes/usage.ts +0 -96
  447. package/backend/src/core/ai/client.ts +0 -242
  448. package/backend/src/core/ai/model.ts +0 -117
  449. package/backend/src/core/auth/auth.ts +0 -781
  450. package/backend/src/core/database/table.ts +0 -772
  451. package/backend/src/core/documentation/agent.ts +0 -689
  452. package/backend/src/core/documentation/openapi.ts +0 -856
  453. package/backend/src/core/logs/analytics.ts +0 -76
  454. package/backend/src/core/logs/providers/localdb.provider.ts +0 -246
  455. package/backend/src/core/storage/storage.ts +0 -923
  456. package/backend/src/utils/cloud-token.ts +0 -39
  457. package/backend/src/utils/helpers.ts +0 -49
  458. package/backend/src/utils/uuid.ts +0 -9
  459. package/backend/tests/manual/test-better-auth.sh +0 -303
  460. package/docker-init/db/logs.sql +0 -9
  461. package/frontend/README.md +0 -112
  462. package/frontend/src/components/datagrid/index.tsx +0 -20
  463. package/frontend/src/components/layout/CloudLayout.tsx +0 -95
  464. package/frontend/src/features/ai/components/AIConfigDialog.tsx +0 -76
  465. package/frontend/src/features/ai/components/AIConfigForm.tsx +0 -222
  466. package/frontend/src/features/ai/components/fields/ModalityField.tsx +0 -87
  467. package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +0 -134
  468. package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +0 -33
  469. package/frontend/src/features/auth/components/AddOAuthDialog.tsx +0 -106
  470. package/frontend/src/features/auth/components/AuthMethodTab.tsx +0 -238
  471. package/frontend/src/features/auth/components/UsersTab.tsx +0 -114
  472. package/frontend/src/features/auth/page/AuthenticationPage.tsx +0 -169
  473. package/frontend/src/features/database/hooks/UseLinkModal.tsx +0 -78
  474. package/frontend/src/features/functions/components/FunctionViewer.tsx +0 -46
  475. package/frontend/src/features/functions/components/FunctionsContent.tsx +0 -88
  476. package/frontend/src/features/login/components/AuthErrorBoundary.tsx +0 -87
  477. package/frontend/src/features/login/components/PrivateRoute.tsx +0 -24
  478. package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +0 -313
  479. package/frontend/src/features/logs/components/LogsTable.tsx +0 -199
  480. package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +0 -530
  481. package/frontend/src/features/metadata/index.ts +0 -0
  482. package/frontend/src/features/metadata/page/MetadataPage.tsx +0 -136
  483. package/frontend/src/features/onboard/components/CompletionCard.tsx +0 -41
  484. package/frontend/src/features/onboard/components/OnboardButton.tsx +0 -84
  485. package/frontend/src/features/onboard/components/StepContent.tsx +0 -91
  486. package/frontend/src/features/onboard/components/TestConnectionStep.tsx +0 -53
  487. package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +0 -144
  488. package/frontend/src/features/onboard/page/OnBoardPage.tsx +0 -104
  489. package/frontend/src/features/onboard/types.ts +0 -8
  490. package/frontend/src/lib/contexts/OnboardStepContext.tsx +0 -68
  491. package/frontend/src/lib/hooks/useOnboardingCompletion.ts +0 -29
  492. /package/backend/src/api/{middleware → middlewares}/error.ts +0 -0
  493. /package/backend/src/api/{middleware → middlewares}/upload.ts +0 -0
  494. /package/backend/{migrations → src/infra/database/migrations}/000_create-base-tables.sql +0 -0
  495. /package/backend/{migrations → src/infra/database/migrations}/001_create-helper-functions.sql +0 -0
  496. /package/backend/{migrations → src/infra/database/migrations}/002_rename-auth-tables.sql +0 -0
  497. /package/backend/{migrations → src/infra/database/migrations}/003_create-users-table.sql +0 -0
  498. /package/backend/{migrations → src/infra/database/migrations}/004_add-reload-postgrest-func.sql +0 -0
  499. /package/backend/{migrations → src/infra/database/migrations}/005_enable-project-admin-modify-users.sql +0 -0
  500. /package/backend/{migrations → src/infra/database/migrations}/006_modify-ai-usage-table.sql +0 -0
  501. /package/backend/{migrations → src/infra/database/migrations}/007_drop-metadata-table.sql +0 -0
  502. /package/backend/{migrations → src/infra/database/migrations}/008_add-system-tables.sql +0 -0
  503. /package/backend/{migrations → src/infra/database/migrations}/009_add-function-secrets.sql +0 -0
  504. /package/backend/{migrations → src/infra/database/migrations}/010_modify-ai-config-modalities.sql +0 -0
  505. /package/backend/{migrations → src/infra/database/migrations}/011_refactor-secrets-table.sql +0 -0
  506. /package/backend/{migrations → src/infra/database/migrations}/012_add-storage-uploaded-by.sql +0 -0
  507. /package/frontend/src/{features/metadata → lib}/services/metadata.service.ts +0 -0
@@ -1,31 +1,36 @@
1
- import { useState, useEffect, useCallback } from 'react';
2
- import { useQuery, useQueryClient } from '@tanstack/react-query';
3
- import { Plus } from 'lucide-react';
1
+ import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
2
+ import { useQueryClient } from '@tanstack/react-query';
3
+ import { Plus, Upload } from 'lucide-react';
4
4
  import PencilIcon from '@/assets/icons/pencil.svg?react';
5
5
  import RefreshIcon from '@/assets/icons/refresh.svg?react';
6
- import { databaseService } from '@/features/database/services/database.service';
7
- import { useMetadata } from '@/features/metadata/hooks/useMetadata';
8
- import { Button } from '@/components/radix/Button';
9
- import { Alert, AlertDescription } from '@/components/radix/Alert';
6
+ import { useTables } from '@/features/database/hooks/useTables';
7
+ import { useRecords } from '@/features/database/hooks/useRecords';
10
8
  import { TableSidebar } from '@/features/database/components/TableSidebar';
11
9
  import { RecordFormDialog } from '@/features/database/components/RecordFormDialog';
12
10
  import { TableForm } from '@/features/database/components/TableForm';
13
- import { ConfirmDialog } from '@/components/ConfirmDialog';
14
- import { EmptyState } from '@/components/EmptyState';
11
+ import { TablesEmptyState } from '@/features/database/components/TablesEmptyState';
12
+ import { TemplatePreview } from '@/features/database/components/TemplatePreview';
13
+ import { DATABASE_TEMPLATES, DatabaseTemplate } from '@/features/database/templates';
15
14
  import {
15
+ Alert,
16
+ AlertDescription,
17
+ Button,
18
+ ConfirmDialog,
19
+ ConnectCTA,
20
+ EmptyState,
21
+ SearchInput,
22
+ SelectionClearButton,
23
+ DeleteActionButton,
16
24
  Tooltip,
17
25
  TooltipContent,
18
26
  TooltipProvider,
19
27
  TooltipTrigger,
20
- } from '@/components/radix/Tooltip';
28
+ } from '@/components';
21
29
  import { useConfirm } from '@/lib/hooks/useConfirm';
22
30
  import { useToast } from '@/lib/hooks/useToast';
23
31
  import { DatabaseDataGrid } from '@/features/database/components/DatabaseDataGrid';
24
- import { SearchInput, SelectionClearButton, DeleteActionButton } from '@/components';
25
32
  import { SortColumn } from 'react-data-grid';
26
33
  import { convertValueForColumn } from '@/lib/utils/utils';
27
- import { LinkModalProvider, useLinkModal } from '@/features/database/hooks/UseLinkModal';
28
- import { LinkRecordModal } from '@/features/database/components/LinkRecordModal';
29
34
  import {
30
35
  DataUpdatePayload,
31
36
  DataUpdateResourceType,
@@ -33,10 +38,11 @@ import {
33
38
  SocketMessage,
34
39
  useSocket,
35
40
  } from '@/lib/contexts/SocketContext';
41
+ import { useCSVImport } from '@/features/database/hooks/useCSVImport';
36
42
 
37
43
  const PAGE_SIZE = 50;
38
44
 
39
- function DatabasePageContent() {
45
+ export default function TablesPage() {
40
46
  // Load selected table from localStorage on mount
41
47
  const [selectedTable, setSelectedTable] = useState<string | null>(() => {
42
48
  return localStorage.getItem('selectedTable');
@@ -52,14 +58,30 @@ function DatabasePageContent() {
52
58
  const [currentPage, setCurrentPage] = useState(1);
53
59
  const [isSorting, setIsSorting] = useState(false);
54
60
  const [isRefreshing, setIsRefreshing] = useState(false);
61
+ const [previewingTemplate, setPreviewingTemplate] = useState<DatabaseTemplate | null>(null);
55
62
 
56
63
  const { confirm, confirmDialogProps } = useConfirm();
57
64
  const { showToast } = useToast();
58
65
  const queryClient = useQueryClient();
59
- const { modalState, closeModal } = useLinkModal();
66
+ const fileInputRef = useRef<HTMLInputElement>(null);
67
+ const { tables, isLoadingTables, tablesError, deleteTable, useTableSchema, refetchTables } =
68
+ useTables();
69
+
70
+ const recordsHook = useRecords(selectedTable || '');
60
71
 
61
72
  const { socket, isConnected } = useSocket();
62
73
 
74
+ const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
75
+ const file = event.target.files?.[0];
76
+ if (file && selectedTable) {
77
+ importCSV(file);
78
+ }
79
+ // Reset file input to allow re-uploading the same file
80
+ if (event.target) {
81
+ event.target.value = '';
82
+ }
83
+ };
84
+
63
85
  // Persist selected table to localStorage when it changes
64
86
  useEffect(() => {
65
87
  if (selectedTable) {
@@ -96,74 +118,71 @@ function DatabasePageContent() {
96
118
  [showToast]
97
119
  );
98
120
 
99
- // Fetch metadata
100
- const { tables, isLoading, error: metadataError, refetch: refetchMetadata } = useMetadata();
121
+ // Fetch schema for selected table
122
+ const { data: schemaData } = useTableSchema(selectedTable || '', !!selectedTable);
123
+
124
+ // Fetch schema for editing table
125
+ const { data: editingTableSchema } = useTableSchema(editingTable || '', !!editingTable);
126
+
127
+ const primaryKeyColumn = useMemo(() => {
128
+ return schemaData?.columns.find((col) => col.isPrimaryKey)?.columnName;
129
+ }, [schemaData]);
101
130
 
102
- // Fetch table data when selected
103
131
  const {
104
- data: tableData,
105
- isLoading: isLoadingTable,
106
- error: tableError,
107
- refetch: refetchTableData,
108
- } = useQuery({
109
- queryKey: [
110
- 'table',
111
- selectedTable,
112
- currentPage,
113
- PAGE_SIZE,
114
- searchQuery,
115
- JSON.stringify(sortColumns),
116
- ],
117
- queryFn: async () => {
118
- if (!selectedTable) {
119
- return null;
132
+ mutate: importCSV,
133
+ isPending: isImporting,
134
+ reset: resetImport,
135
+ } = useCSVImport(selectedTable || '', {
136
+ onSuccess: (data) => {
137
+ if (data.success) {
138
+ showToast(data.message || 'Import successful!', 'success');
139
+ void refetchTableData();
140
+ } else {
141
+ // This case handles validation errors returned with a 200 OK but success: false
142
+ const errorMessage =
143
+ data.message || 'CSV import failed due to validation errors. Please check the file.';
144
+ showToast(errorMessage, 'error');
120
145
  }
146
+ resetImport();
147
+ },
148
+ onError: (error: Error) => {
149
+ // This handles 400/500 errors from the API client
150
+ const message =
151
+ error?.message || 'An unexpected error occurred during import. Please try again.';
152
+ showToast(message, 'error');
153
+ resetImport();
154
+ },
155
+ });
121
156
 
122
- const offset = (currentPage - 1) * PAGE_SIZE;
157
+ // Fetch table records using the hook
158
+ const offset = (currentPage - 1) * PAGE_SIZE;
159
+ const {
160
+ data: recordsData,
161
+ isLoading: isLoadingRecords,
162
+ error: recordsError,
163
+ refetch: refetchRecords,
164
+ } = recordsHook.useTableRecords(
165
+ PAGE_SIZE,
166
+ offset,
167
+ searchQuery,
168
+ sortColumns,
169
+ !!selectedTable && !!schemaData
170
+ );
123
171
 
124
- try {
125
- const [schema, records] = await Promise.all([
126
- databaseService.getTableSchema(selectedTable),
127
- databaseService.getTableRecords(
128
- selectedTable,
129
- PAGE_SIZE,
130
- offset,
131
- searchQuery,
132
- sortColumns
133
- ),
134
- ]);
135
-
136
- return {
172
+ // Combine schema and records data
173
+ const tableData =
174
+ selectedTable && schemaData && recordsData
175
+ ? {
137
176
  name: selectedTable,
138
- schema,
139
- records: records.records,
140
- totalRecords: records.pagination.total ?? schema.recordCount,
141
- };
142
- } catch (error) {
143
- // If sorting caused the error, retry without sorting
144
- if (sortColumns && sortColumns.length > 0) {
145
- setSortColumns([]);
146
-
147
- const [schema, records] = await Promise.all([
148
- databaseService.getTableSchema(selectedTable),
149
- databaseService.getTableRecords(selectedTable, PAGE_SIZE, offset, searchQuery, []),
150
- ]);
151
-
152
- showToast('Sorting not supported for this table. Showing unsorted results.', 'info');
153
-
154
- return {
155
- name: selectedTable,
156
- schema,
157
- records: records.records,
158
- totalRecords: records.pagination.total || schema.recordCount,
159
- };
177
+ schema: schemaData,
178
+ records: recordsData.records,
179
+ totalRecords: recordsData.pagination.total ?? schemaData.recordCount,
160
180
  }
161
- throw error;
162
- }
163
- },
164
- enabled: !!selectedTable,
165
- placeholderData: (previousData) => previousData, // Keep previous data while loading new sorted data
166
- });
181
+ : null;
182
+
183
+ const isLoadingTable = isLoadingRecords;
184
+ const tableError = recordsError;
185
+ const refetchTableData = refetchRecords;
167
186
 
168
187
  useEffect(() => {
169
188
  if (!socket || !isConnected) {
@@ -171,12 +190,21 @@ function DatabasePageContent() {
171
190
  }
172
191
 
173
192
  const handleDataUpdate = (message: SocketMessage<DataUpdatePayload>) => {
174
- if (
175
- message.payload?.resource === DataUpdateResourceType.METADATA ||
176
- message.payload?.resource === DataUpdateResourceType.DATABASE_SCHEMA
177
- ) {
193
+ if (message.payload?.resource === DataUpdateResourceType.DATABASE) {
178
194
  // Invalidate all tables queries
179
195
  void queryClient.invalidateQueries({ queryKey: ['tables'] });
196
+ void queryClient.invalidateQueries({ queryKey: ['records', selectedTable] });
197
+ }
198
+
199
+ if (message.payload?.resource === DataUpdateResourceType.RECORDS) {
200
+ // Invalidate records queries for the updated table
201
+ const data = message.payload.data as { tableName?: string };
202
+ const updatedTableName = data?.tableName;
203
+
204
+ // Only invalidate if this is the currently selected table
205
+ if (updatedTableName && updatedTableName === selectedTable) {
206
+ void queryClient.invalidateQueries({ queryKey: ['records', selectedTable] });
207
+ }
180
208
  }
181
209
  };
182
210
 
@@ -185,7 +213,7 @@ function DatabasePageContent() {
185
213
  return () => {
186
214
  socket.off(ServerEvents.DATA_UPDATE, handleDataUpdate);
187
215
  };
188
- }, [socket, isConnected, queryClient]);
216
+ }, [socket, isConnected, queryClient, selectedTable]);
189
217
 
190
218
  // Reset sorting flag when loading completes
191
219
  useEffect(() => {
@@ -196,7 +224,7 @@ function DatabasePageContent() {
196
224
 
197
225
  // Auto-select first table (excluding system tables)
198
226
  useEffect(() => {
199
- if (!isLoading && tables) {
227
+ if (!isLoadingTables && tables) {
200
228
  if (pendingTableSelection && tables.includes(pendingTableSelection)) {
201
229
  setSelectedTable(pendingTableSelection);
202
230
  setPendingTableSelection(undefined);
@@ -208,11 +236,11 @@ function DatabasePageContent() {
208
236
  return;
209
237
  }
210
238
 
211
- if (!selectedTable && tables.length > 0 && !showTableForm && !pendingTableSelection) {
239
+ if (!selectedTable && tables.length && !showTableForm && !pendingTableSelection) {
212
240
  setSelectedTable(tables[0]);
213
241
  }
214
242
  }
215
- }, [tables, pendingTableSelection, selectedTable, showTableForm, isLoading]);
243
+ }, [tables, pendingTableSelection, selectedTable, showTableForm, isLoadingTables]);
216
244
 
217
245
  const handleRefresh = async () => {
218
246
  setIsRefreshing(true);
@@ -227,7 +255,7 @@ function DatabasePageContent() {
227
255
  if (selectedTable) {
228
256
  await refetchTableData();
229
257
  }
230
- await refetchMetadata();
258
+ await refetchTables();
231
259
  } finally {
232
260
  setIsRefreshing(false);
233
261
  }
@@ -291,28 +319,23 @@ function DatabasePageContent() {
291
319
  const shouldDelete = await confirm(confirmOptions);
292
320
 
293
321
  if (shouldDelete) {
294
- try {
295
- // Update selectedTable BEFORE deleting to prevent queries on deleted table
296
- if (selectedTable === tableName) {
297
- setSelectedTable(null);
298
- }
299
-
300
- await databaseService.deleteTable(tableName);
301
- showToast('Table deleted successfully', 'success');
302
-
303
- // Invalidate all related queries for the deleted table
304
- void queryClient.invalidateQueries({ queryKey: ['metadata'] });
305
- void queryClient.invalidateQueries({ queryKey: ['tables'] });
306
- void queryClient.invalidateQueries({ queryKey: ['table', tableName] });
307
- void queryClient.invalidateQueries({ queryKey: ['table-schema', tableName] });
308
- void queryClient.invalidateQueries({ queryKey: ['metadata'] });
309
- } catch (error) {
310
- const errorMessage = error instanceof Error ? error.message : 'Failed to delete table';
311
- showToast(errorMessage, 'error');
322
+ // Update selectedTable BEFORE deleting to prevent queries on deleted table
323
+ if (selectedTable === tableName) {
324
+ setSelectedTable(null);
312
325
  }
326
+
327
+ deleteTable(tableName);
313
328
  }
314
329
  };
315
330
 
331
+ const handleTemplateClick = (template: DatabaseTemplate) => {
332
+ setPreviewingTemplate(template);
333
+ };
334
+
335
+ const handleCancelPreview = () => {
336
+ setPreviewingTemplate(null);
337
+ };
338
+
316
339
  // Handle record update
317
340
  const handleRecordUpdate = async (rowId: string, columnKey: string, newValue: string) => {
318
341
  if (!selectedTable) {
@@ -331,9 +354,11 @@ function DatabasePageContent() {
331
354
  return;
332
355
  }
333
356
  const updates = { [columnKey]: conversionResult.value };
334
- await databaseService.updateRecord(selectedTable, rowId, updates);
335
- await refetchTableData();
336
- showToast('Record updated successfully', 'success');
357
+ await recordsHook.updateRecord({
358
+ pkColumn: primaryKeyColumn || 'id',
359
+ pkValue: rowId,
360
+ data: updates,
361
+ });
337
362
  }
338
363
  } catch (error) {
339
364
  showToast('Failed to update record', 'error');
@@ -343,7 +368,7 @@ function DatabasePageContent() {
343
368
 
344
369
  // Handle bulk delete
345
370
  const handleBulkDelete = async (ids: string[]) => {
346
- if (!selectedTable || ids.length === 0) {
371
+ if (!selectedTable || !ids.length) {
347
372
  return;
348
373
  }
349
374
 
@@ -355,51 +380,25 @@ function DatabasePageContent() {
355
380
  });
356
381
 
357
382
  if (shouldDelete) {
358
- try {
359
- await Promise.all(ids.map((id) => databaseService.deleteRecord(selectedTable, id)));
360
- await Promise.all([
361
- refetchTableData(),
362
- refetchMetadata(), // Also refresh metadata to update sidebar record counts
363
- ]);
364
- setSelectedRows(new Set());
365
- showToast(`${ids.length} records deleted successfully`, 'success');
366
- } catch {
367
- showToast('Failed to delete some records', 'error');
368
- }
383
+ await recordsHook.deleteRecords({ pkColumn: primaryKeyColumn || 'id', pkValues: ids });
384
+ // Query invalidation is handled by the mutation, no manual refetch needed
385
+ setSelectedRows(new Set());
369
386
  }
370
387
  };
371
388
 
372
- const error = metadataError || tableError;
373
-
374
- // Fetch schema for selected table
375
- const { data: schemaData } = useQuery({
376
- queryKey: ['table-schema', selectedTable],
377
- queryFn: async () => {
378
- if (!selectedTable) {
379
- return undefined;
380
- }
381
- return await databaseService.getTableSchema(selectedTable);
382
- },
383
- enabled: !!selectedTable,
384
- staleTime: 30 * 1000, // 30 seconds
385
- });
386
-
387
- // Fetch schema for editing table
388
- const { data: editingTableSchema } = useQuery({
389
- queryKey: ['table-schema', editingTable],
390
- queryFn: async () => {
391
- if (!editingTable) {
392
- return undefined;
393
- }
394
- const editingTableSchema = await databaseService.getTableSchema(editingTable);
395
- return editingTableSchema;
396
- },
397
- enabled: !!editingTable,
398
- });
389
+ const error = tablesError || tableError;
399
390
 
400
391
  // Calculate pagination
401
392
  const totalPages = Math.ceil((tableData?.totalRecords || 0) / PAGE_SIZE);
402
393
 
394
+ // Show empty state when there are no tables and not loading
395
+ const showEmptyState = !isLoadingTables && tables?.length === 0 && !showTableForm;
396
+
397
+ // Show template preview - takes full width without sidebar
398
+ if (previewingTemplate) {
399
+ return <TemplatePreview template={previewingTemplate} onCancel={handleCancelPreview} />;
400
+ }
401
+
403
402
  return (
404
403
  <div className="flex h-full bg-bg-gray dark:bg-neutral-800">
405
404
  {/* Secondary Sidebar - Table List */}
@@ -407,7 +406,7 @@ function DatabasePageContent() {
407
406
  tables={tables}
408
407
  selectedTable={selectedTable || undefined}
409
408
  onTableSelect={handleSelectTable}
410
- loading={isLoading}
409
+ loading={isLoadingTables}
411
410
  onNewTable={handleCreateTable}
412
411
  onEditTable={handleEditTable}
413
412
  onDeleteTable={(tableName) => void handleDeleteTable(tableName)}
@@ -428,7 +427,7 @@ function DatabasePageContent() {
428
427
  editTable={editingTable ? editingTableSchema : undefined}
429
428
  setFormIsDirty={setIsTableFormDirty}
430
429
  onSuccess={(newTableName?: string) => {
431
- void refetchMetadata();
430
+ void refetchTables();
432
431
  void refetchTableData();
433
432
  setShowTableForm(false);
434
433
  setPendingTableSelection(newTableName);
@@ -469,7 +468,6 @@ function DatabasePageContent() {
469
468
  <p>Edit Table</p>
470
469
  </TooltipContent>
471
470
  </Tooltip>
472
-
473
471
  <Tooltip>
474
472
  <TooltipTrigger asChild>
475
473
  <Button
@@ -503,11 +501,13 @@ function DatabasePageContent() {
503
501
  itemType="record"
504
502
  onClear={() => setSelectedRows(new Set())}
505
503
  />
506
- <DeleteActionButton
507
- selectedCount={selectedRows.size}
508
- itemType="record"
509
- onDelete={() => void handleBulkDelete(Array.from(selectedRows))}
510
- />
504
+ {
505
+ <DeleteActionButton
506
+ selectedCount={selectedRows.size}
507
+ itemType="record"
508
+ onDelete={() => void handleBulkDelete(Array.from(selectedRows))}
509
+ />
510
+ }
511
511
  </div>
512
512
  ) : (
513
513
  <SearchInput
@@ -519,8 +519,18 @@ function DatabasePageContent() {
519
519
  />
520
520
  )}
521
521
  <div className="flex items-center gap-2 ml-4">
522
- {selectedRows.size === 0 && selectedTable !== 'users' && (
522
+ {selectedRows.size === 0 && (
523
523
  <>
524
+ {/* Import CSV Button */}
525
+ <Button
526
+ variant="secondary"
527
+ className="h-10 px-4 font-medium gap-1.5 border border-zinc-200 dark:border-neutral-600"
528
+ onClick={() => fileInputRef.current?.click()}
529
+ disabled={isImporting}
530
+ >
531
+ <Upload className="w-5 h-5" />
532
+ {isImporting ? 'Importing...' : 'Import CSV'}
533
+ </Button>
524
534
  {/* Add Record Button */}
525
535
  <Button
526
536
  className="h-10 px-4 font-medium gap-1.5 dark:bg-emerald-300 dark:hover:bg-emerald-400"
@@ -546,7 +556,13 @@ function DatabasePageContent() {
546
556
  </Alert>
547
557
  )}
548
558
 
549
- {!selectedTable ? (
559
+ {showEmptyState ? (
560
+ <TablesEmptyState
561
+ templates={DATABASE_TEMPLATES}
562
+ onCreateTable={handleCreateTable}
563
+ onTemplateClick={handleTemplateClick}
564
+ />
565
+ ) : !selectedTable ? (
550
566
  <div className="flex-1 flex items-center justify-center">
551
567
  <EmptyState
552
568
  title="No Table Selected"
@@ -560,18 +576,24 @@ function DatabasePageContent() {
560
576
  loading={isLoadingTable && !tableData}
561
577
  isSorting={isSorting}
562
578
  isRefreshing={isRefreshing}
579
+ rowKeyGetter={(row) => String(row[primaryKeyColumn || 'id'])}
563
580
  selectedRows={selectedRows}
564
581
  onSelectedRowsChange={setSelectedRows}
565
582
  sortColumns={sortColumns}
566
583
  onSortColumnsChange={handleSortColumnsChange}
567
584
  onCellEdit={handleRecordUpdate}
568
585
  onJumpToTable={setSelectedTable}
569
- searchQuery={searchQuery}
570
586
  currentPage={currentPage}
571
587
  totalPages={totalPages}
572
588
  pageSize={PAGE_SIZE}
573
589
  totalRecords={tableData?.totalRecords || 0}
574
590
  onPageChange={setCurrentPage}
591
+ emptyState={
592
+ <div className="text-sm text-black dark:text-white">
593
+ {searchQuery ? 'No records match your search criteria' : 'No records found'}.{' '}
594
+ <ConnectCTA />
595
+ </div>
596
+ }
575
597
  />
576
598
  )}
577
599
  </div>
@@ -579,6 +601,14 @@ function DatabasePageContent() {
579
601
  )}
580
602
  </div>
581
603
 
604
+ <input
605
+ type="file"
606
+ ref={fileInputRef}
607
+ onChange={handleFileSelect}
608
+ accept=".csv,text/csv"
609
+ style={{ display: 'none' }}
610
+ />
611
+
582
612
  {/* Add Record Form */}
583
613
  {selectedTable && schemaData && (
584
614
  // In the RecordForm onSuccess callback
@@ -587,40 +617,11 @@ function DatabasePageContent() {
587
617
  onOpenChange={setShowRecordForm}
588
618
  tableName={selectedTable}
589
619
  schema={schemaData.columns}
590
- onSuccess={() => {
591
- void refetchTableData();
592
- void refetchMetadata();
593
- // Also invalidate the schema cache to ensure fresh data
594
- void queryClient.invalidateQueries({ queryKey: ['table-schema', selectedTable] });
595
- }}
596
620
  />
597
621
  )}
598
622
 
599
623
  {/* Confirm Dialog */}
600
624
  <ConfirmDialog {...confirmDialogProps} />
601
-
602
- {/* Global Link Record Modal */}
603
- {modalState.isOpen && modalState.referenceTable && modalState.referenceColumn && (
604
- <LinkRecordModal
605
- open={modalState.isOpen}
606
- onOpenChange={closeModal}
607
- referenceTable={modalState.referenceTable}
608
- referenceColumn={modalState.referenceColumn}
609
- currentValue={modalState.currentValue}
610
- onSelectRecord={(record) => {
611
- modalState.onSelectRecord?.(record);
612
- closeModal();
613
- }}
614
- />
615
- )}
616
625
  </div>
617
626
  );
618
627
  }
619
-
620
- export default function DatabasePage() {
621
- return (
622
- <LinkModalProvider>
623
- <DatabasePageContent />
624
- </LinkModalProvider>
625
- );
626
- }
@@ -0,0 +1,39 @@
1
+ import { useNavigate } from 'react-router-dom';
2
+ import { DATABASE_TEMPLATES, type DatabaseTemplate } from '@/features/database/templates';
3
+ import { useSQLEditorContext } from '@/features/database/contexts/SQLEditorContext';
4
+ import { TemplateCard } from '@/features/database/components/TemplateCard';
5
+
6
+ export default function TemplatesPage() {
7
+ const navigate = useNavigate();
8
+ const { addTab } = useSQLEditorContext();
9
+
10
+ const handleTemplateClick = (template: DatabaseTemplate) => {
11
+ // Create a new tab with the template's SQL query prefilled
12
+ addTab(template.sql, template.title);
13
+ // Navigate to the SQL Editor page
14
+ void navigate('/dashboard/database/sql-editor');
15
+ };
16
+
17
+ return (
18
+ <div className="flex flex-col h-full items-center bg-bg-gray dark:bg-neutral-800 overflow-auto">
19
+ {/* Main Content - Centered */}
20
+ <div className="flex flex-col max-w-[1024px] justify-center px-6 pb-6">
21
+ {/* Header */}
22
+ <div className="flex items-center justify-start gap-3 h-[72px] bg-bg-gray dark:bg-neutral-800 flex-shrink-0">
23
+ <h1 className="text-xl font-semibold text-zinc-950 dark:text-white">Database Template</h1>
24
+ </div>
25
+ <div className="w-full max-w-[1024px]">
26
+ <div className="grid grid-cols-2 xl:grid-cols-3 gap-6">
27
+ {DATABASE_TEMPLATES.map((template) => (
28
+ <TemplateCard
29
+ key={template.id}
30
+ template={template}
31
+ onClick={() => handleTemplateClick(template)}
32
+ />
33
+ ))}
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ );
39
+ }