insforge 0.3.3 → 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 -780
  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,26 +1,25 @@
1
1
  import { useState, useEffect, useMemo } from 'react';
2
2
  import { useForm } from 'react-hook-form';
3
3
  import { zodResolver } from '@hookform/resolvers/zod';
4
- import { useMutation, useQueryClient } from '@tanstack/react-query';
4
+ import { useQueryClient } from '@tanstack/react-query';
5
5
  import { AlertCircle } from 'lucide-react';
6
6
  import {
7
+ Alert,
8
+ AlertDescription,
9
+ Button,
7
10
  Dialog,
8
11
  DialogContent,
9
12
  DialogHeader,
10
13
  DialogTitle,
11
14
  DialogFooter,
12
- } from '@/components/radix/Dialog';
13
- import { Button } from '@/components/radix/Button';
14
- import { Alert, AlertDescription } from '@/components/radix/Alert';
15
- import { ScrollArea } from '@/components/radix/ScrollArea';
16
- import { databaseService } from '@/features/database/services/database.service';
15
+ ScrollArea,
16
+ } from '@/components';
17
+ import { useRecords } from '@/features/database/hooks/useRecords';
17
18
  import { buildDynamicSchema, getInitialValues } from '@/features/database';
18
19
  import { RecordFormField } from '@/features/database/components/RecordFormField';
19
20
  import { cn } from '@/lib/utils/utils';
20
- import { useToast } from '@/lib/hooks/useToast';
21
21
  import { ColumnSchema } from '@insforge/shared-schemas';
22
22
  import { SYSTEM_FIELDS } from '../helpers';
23
- import { ConvertedValue } from '@/components/datagrid/datagridTypes';
24
23
 
25
24
  interface RecordFormDialogProps {
26
25
  open: boolean;
@@ -39,7 +38,7 @@ export function RecordFormDialog({
39
38
  }: RecordFormDialogProps) {
40
39
  const [error, setError] = useState<string | null>(null);
41
40
  const queryClient = useQueryClient();
42
- const { showToast } = useToast();
41
+ const { createRecord, isCreating } = useRecords(tableName);
43
42
 
44
43
  const displayFields = useMemo(() => {
45
44
  const filteredFields = schema.filter((field) => !SYSTEM_FIELDS.includes(field.columnName));
@@ -72,31 +71,21 @@ export function RecordFormDialog({
72
71
  }
73
72
  }, [open]);
74
73
 
75
- const createRecordMutation = useMutation({
76
- mutationFn: (data: { [key: string]: ConvertedValue }) => {
77
- return databaseService.createRecord(tableName, data);
78
- },
79
- onSuccess: () => {
80
- void queryClient.invalidateQueries({ queryKey: ['records', tableName] });
81
- void queryClient.invalidateQueries({ queryKey: ['table', tableName] });
82
- onOpenChange(false);
83
- form.reset();
84
- setError(null);
85
- if (onSuccess) {
86
- onSuccess();
87
- }
88
- showToast('Record created successfully', 'success');
89
- },
90
- onError: (err: Error) => {
91
- setError(err.message || 'Failed to create record');
92
- },
93
- });
94
-
95
74
  const handleSubmit = form.handleSubmit(
96
75
  async (data) => {
97
76
  try {
98
- await createRecordMutation.mutateAsync(data);
77
+ await createRecord(data);
78
+ void queryClient.invalidateQueries({ queryKey: ['records', tableName] });
79
+ void queryClient.invalidateQueries({ queryKey: ['table', tableName] });
80
+ onOpenChange(false);
81
+ form.reset();
82
+ setError(null);
83
+ if (onSuccess) {
84
+ onSuccess();
85
+ }
99
86
  } catch (err) {
87
+ const errorMessage = err instanceof Error ? err.message : 'Failed to create record';
88
+ setError(errorMessage);
100
89
  console.error('Form submission error:', err);
101
90
  }
102
91
  },
@@ -148,13 +137,13 @@ export function RecordFormDialog({
148
137
  </Button>
149
138
  <Button
150
139
  type="submit"
151
- disabled={createRecordMutation.isPending}
140
+ disabled={isCreating}
152
141
  className={cn(
153
142
  'h-10 px-4 bg-zinc-950 text-white hover:bg-zinc-800 dark:bg-emerald-300 dark:text-zinc-950 dark:hover:bg-emerald-400',
154
- createRecordMutation.isPending && 'opacity-40'
143
+ isCreating && 'opacity-40'
155
144
  )}
156
145
  >
157
- {createRecordMutation.isPending ? 'Saving...' : 'Add Record'}
146
+ {isCreating ? 'Saving...' : 'Add Record'}
158
147
  </Button>
159
148
  </DialogFooter>
160
149
  </form>
@@ -1,21 +1,21 @@
1
1
  import React, { useState } from 'react';
2
2
  import { Control, Controller, FieldError, UseFormReturn } from 'react-hook-form';
3
- import { Input } from '@/components/radix/Input';
4
- import { Label } from '@/components/radix/Label';
5
- import { Button } from '@/components/radix/Button';
6
3
  import { Calendar, Clock, Link2, X } from 'lucide-react';
7
4
  import {
5
+ Button,
6
+ Label,
7
+ Input,
8
8
  BooleanCellEditor,
9
9
  DateCellEditor,
10
10
  JsonCellEditor,
11
11
  type DatabaseRecord,
12
12
  type ConvertedValue,
13
13
  type UserInputValue,
14
- } from '@/components/datagrid';
14
+ TypeBadge,
15
+ } from '@/components';
15
16
  import { ColumnSchema, ColumnType } from '@insforge/shared-schemas';
16
- import { useLinkModal } from '@/features/database/hooks/UseLinkModal';
17
17
  import { convertValueForColumn, cn, formatValueForDisplay } from '@/lib/utils/utils';
18
- import { TypeBadge } from '@/components/TypeBadge';
18
+ import { LinkRecordModal } from '@/features/database/components/LinkRecordModal';
19
19
  import { isValid, parseISO } from 'date-fns';
20
20
 
21
21
  // Helper function to get appropriate placeholder text
@@ -184,7 +184,7 @@ function FormNumberEditor({ value, type, onChange, tableName, field }: FormNumbe
184
184
  }
185
185
  }}
186
186
  placeholder={getPlaceholderText(field)}
187
- className={`dark:text-white dark:placeholder:text-neutral-400 dark:bg-neutral-900 dark:border-neutral-700 ${field.foreignKey ? 'pr-16' : ''}`}
187
+ className={`dark:text-white dark:placeholder:text-neutral-400 dark:bg-neutral-900 dark:border-neutral-700 ${field.foreignKey ? 'pr-18' : ''}`}
188
188
  />
189
189
  );
190
190
  }
@@ -278,13 +278,14 @@ interface FieldWithLinkProps {
278
278
  }
279
279
 
280
280
  function FieldWithLink({ field, control, children }: FieldWithLinkProps) {
281
- const { openModal } = useLinkModal();
282
-
283
281
  if (!field.foreignKey) {
284
282
  // Regular field without foreign key
285
283
  return <>{children}</>;
286
284
  }
287
285
 
286
+ // Store foreignKey in a const to help TypeScript narrow the type
287
+ const foreignKey = field.foreignKey;
288
+
288
289
  // Field with foreign key linking capability - integrated design
289
290
  return (
290
291
  <>
@@ -309,56 +310,53 @@ function FieldWithLink({ field, control, children }: FieldWithLinkProps) {
309
310
  <div className="space-y-1">
310
311
  <div className="relative">
311
312
  {modifiedChildren}
312
- <div className="absolute right-0 top-1/2 -translate-y-1/2 flex items-center">
313
- {hasLinkedValue && (
313
+ <div className="absolute right-0 top-1/2 -translate-y-1/2 flex items-center gap-1">
314
+ {(hasLinkedValue || hasLinkedValue === 0) && (
314
315
  <Button
315
316
  type="button"
316
317
  variant="ghost"
317
318
  size="icon"
318
319
  onClick={() => formField.onChange('')}
319
- className="h-7 w-7 p-1 flex-shrink-0 text-zinc-500 hover:text-red-600 hover:bg-red-50 dark:text-neutral-400 dark:hover:text-red-400 dark:hover:bg-red-950/20"
320
+ className="h-7 w-7 p-1 flex-shrink-0 text-zinc-500 hover:text-zinc-700 hover:bg-zinc-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-700"
320
321
  title="Clear linked record"
321
322
  >
322
323
  <X className="h-4 w-4" />
323
324
  </Button>
324
325
  )}
325
- <Button
326
- type="button"
327
- variant="ghost"
328
- size="icon"
329
- onClick={() => {
330
- if (field.foreignKey) {
331
- openModal({
332
- referenceTable: field.foreignKey.referenceTable,
333
- referenceColumn: field.foreignKey.referenceColumn,
334
- currentValue: formField.value ? String(formField.value) : null,
335
- onSelectRecord: (record: DatabaseRecord) => {
336
- if (field.foreignKey) {
337
- const referenceValue = record[field.foreignKey.referenceColumn];
338
- const result = convertValueForColumn(
339
- field.type,
340
- String(referenceValue || '')
341
- );
342
- if (result.success) {
343
- formField.onChange(result.value);
344
- } else {
345
- // Fallback to string if conversion fails
346
- formField.onChange(String(referenceValue || ''));
347
- }
348
- }
349
- },
350
- });
326
+ <LinkRecordModal
327
+ referenceTable={foreignKey.referenceTable}
328
+ referenceColumn={foreignKey.referenceColumn}
329
+ onSelectRecord={(record: DatabaseRecord) => {
330
+ const referenceValue = record[foreignKey.referenceColumn];
331
+ const result = convertValueForColumn(
332
+ field.type,
333
+ String(referenceValue || '')
334
+ );
335
+ if (result.success) {
336
+ formField.onChange(result.value);
337
+ } else {
338
+ // Fallback to string if conversion fails
339
+ formField.onChange(String(referenceValue || ''));
351
340
  }
352
341
  }}
353
- className="rounded-l-none h-9 w-9 p-2 flex-shrink-0 text-zinc-500 hover:text-zinc-700 hover:bg-zinc-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-700 border-l border-zinc-200 dark:border-neutral-700"
354
- title={
355
- hasLinkedValue
356
- ? `Change linked ${field.foreignKey?.referenceTable} record`
357
- : `Link to ${field.foreignKey?.referenceTable} record`
358
- }
359
342
  >
360
- <Link2 className="h-5 w-5" />
361
- </Button>
343
+ {(openModal) => (
344
+ <Button
345
+ type="button"
346
+ variant="ghost"
347
+ size="icon"
348
+ onClick={openModal}
349
+ className="rounded-l-none h-9 w-9 p-2 flex-shrink-0 text-zinc-500 hover:text-zinc-700 hover:bg-zinc-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-700 border-l border-zinc-200 dark:border-neutral-700"
350
+ title={
351
+ hasLinkedValue
352
+ ? `Change linked ${foreignKey.referenceTable} record`
353
+ : `Link to ${foreignKey.referenceTable} record`
354
+ }
355
+ >
356
+ <Link2 className="h-5 w-5" />
357
+ </Button>
358
+ )}
359
+ </LinkRecordModal>
362
360
  </div>
363
361
  </div>
364
362
 
@@ -366,7 +364,7 @@ function FieldWithLink({ field, control, children }: FieldWithLinkProps) {
366
364
  <div className="text-xs text-medium text-black dark:text-neutral-400 flex items-center gap-1.5">
367
365
  <span>Has a Foreign Key relation to</span>
368
366
  <TypeBadge
369
- type={`${field.foreignKey?.referenceTable}.${field.foreignKey?.referenceColumn}`}
367
+ type={`${foreignKey.referenceTable}.${foreignKey.referenceColumn}`}
370
368
  className="dark:bg-neutral-700"
371
369
  />
372
370
  </div>
@@ -1,4 +1,5 @@
1
1
  import { Database } from 'lucide-react';
2
+ import { ConnectCTA } from '@/components/ConnectCTA';
2
3
 
3
4
  interface TableEmptyStateProps {
4
5
  searchTerm: string;
@@ -6,14 +7,14 @@ interface TableEmptyStateProps {
6
7
 
7
8
  export function TableEmptyState({ searchTerm }: TableEmptyStateProps) {
8
9
  return (
9
- <div className="text-center py-8">
10
- <Database className="mx-auto h-8 w-8 text-muted-foreground mb-2.5" />
11
- <p className="text-sm text-muted-foreground">
10
+ <div className="flex flex-col items-center justify-center py-4 text-center">
11
+ <Database className="h-10 w-10 text-gray-400 dark:text-neutral-600 mb-3" />
12
+ <p className="text-sm text-gray-600 dark:text-neutral-400 font-medium">
12
13
  {searchTerm ? 'No tables found' : 'No tables yet'}
13
14
  </p>
14
15
  {!searchTerm && (
15
- <p className="text-xs text-muted-foreground mt-2.5">
16
- Create your first table to get started
16
+ <p className="text-xs text-gray-500 dark:text-neutral-400 font-medium mt-1 mx-10">
17
+ <ConnectCTA fallback="Create your first table to get started" />
17
18
  </p>
18
19
  )}
19
20
  </div>
@@ -3,10 +3,8 @@ import { useForm, useFieldArray } from 'react-hook-form';
3
3
  import { zodResolver } from '@hookform/resolvers/zod';
4
4
  import { useMutation, useQueryClient } from '@tanstack/react-query';
5
5
  import { AlertCircle, Plus, X, Link, MoveRight } from 'lucide-react';
6
- import { Button } from '@/components/radix/Button';
7
- import { Input } from '@/components/radix/Input';
8
- import { Alert, AlertDescription } from '@/components/radix/Alert';
9
- import { databaseService } from '@/features/database/services/database.service';
6
+ import { Alert, AlertDescription, Button, Input } from '@/components';
7
+ import { tableService } from '@/features/database/services/table.service';
10
8
  import {
11
9
  TableFormColumnSchema,
12
10
  TableFormForeignKeySchema,
@@ -50,6 +48,7 @@ export function TableForm({
50
48
  const [showForeignKeyDialog, setShowForeignKeyDialog] = useState(false);
51
49
  const [editingForeignKey, setEditingForeignKey] = useState<string>();
52
50
  const [foreignKeys, setForeignKeys] = useState<TableFormForeignKeySchema[]>([]);
51
+ const [foreignKeysDirty, setForeignKeysDirty] = useState(false);
53
52
  const queryClient = useQueryClient();
54
53
  const { showToast } = useToast();
55
54
 
@@ -220,7 +219,7 @@ export function TableForm({
220
219
  };
221
220
  });
222
221
 
223
- return databaseService.createTable(data.tableName, columns);
222
+ return tableService.createTable(data.tableName, columns);
224
223
  },
225
224
  onSuccess: (data) => {
226
225
  void queryClient.invalidateQueries({ queryKey: ['database-metadata'] });
@@ -232,12 +231,13 @@ export function TableForm({
232
231
  form.reset();
233
232
  setError(null);
234
233
  setForeignKeys([]);
234
+ setForeignKeysDirty(false);
235
235
  onSuccess?.(data.tableName);
236
236
  },
237
237
  onError: (err) => {
238
238
  const errorMessage = err.message || 'Failed to create table';
239
239
  setError(errorMessage);
240
- showToast('Failed to create table', 'error');
240
+ showToast(errorMessage, 'error');
241
241
  },
242
242
  });
243
243
 
@@ -350,7 +350,7 @@ export function TableForm({
350
350
  operations.renameTable = { newTableName: data.tableName };
351
351
  }
352
352
 
353
- return databaseService.updateTableSchema(editTable.tableName, operations);
353
+ return tableService.updateTableSchema(editTable.tableName, operations);
354
354
  },
355
355
  onSuccess: (_, data) => {
356
356
  void queryClient.invalidateQueries({ queryKey: ['database-metadata'] });
@@ -377,11 +377,21 @@ export function TableForm({
377
377
 
378
378
  const errorMessage = err.message || 'Failed to update table';
379
379
  setError(errorMessage);
380
- showToast('Failed to update table', 'error');
380
+ showToast(errorMessage, 'error');
381
381
  },
382
382
  });
383
383
 
384
384
  const handleSubmit = form.handleSubmit((data) => {
385
+ const userColumns = data.columns.filter((col) => !col.isSystemColumn);
386
+ if (!userColumns.length) {
387
+ const msg =
388
+ mode === 'create'
389
+ ? 'Please add at least one user-defined column to create a table.'
390
+ : 'Please ensure the table has at least one user-defined column.';
391
+ setError(msg);
392
+ showToast(msg, 'error');
393
+ return;
394
+ }
385
395
  if (mode === 'edit') {
386
396
  updateTableMutation.mutate(data);
387
397
  } else {
@@ -402,6 +412,7 @@ export function TableForm({
402
412
  )
403
413
  );
404
414
  setEditingForeignKey(undefined);
415
+ setForeignKeysDirty(true);
405
416
  } else {
406
417
  // Add new foreign key
407
418
  setForeignKeys([
@@ -411,10 +422,12 @@ export function TableForm({
411
422
  },
412
423
  ]);
413
424
  }
425
+ setForeignKeysDirty(true);
414
426
  };
415
427
 
416
428
  const handleRemoveForeignKey = (columnName?: string) => {
417
429
  setForeignKeys(foreignKeys.filter((fk) => fk.columnName !== columnName));
430
+ setForeignKeysDirty(true);
418
431
  };
419
432
 
420
433
  if (!open) {
@@ -470,7 +483,7 @@ export function TableForm({
470
483
  {/* Columns Table */}
471
484
  <div className="px-3 overflow-x-auto">
472
485
  {/* Table Headers */}
473
- <div className="flex items-center gap-6 px-4 py-2 bg-slate-50 rounded-t text-sm font-medium text-zinc-950 dark:bg-neutral-700 dark:text-white">
486
+ <div className="flex items-center gap-6 px-4 py-2 w-min xl:w-full bg-slate-50 rounded-t text-sm font-medium text-zinc-950 dark:bg-neutral-700 dark:text-white">
474
487
  <div className="flex-1 min-w-[175px]">Name</div>
475
488
  <div className="flex-1 min-w-[175px]">Type</div>
476
489
  <div className="flex-1 min-w-[175px]">Default Value</div>
@@ -511,7 +524,7 @@ export function TableForm({
511
524
  </div>
512
525
 
513
526
  {/* Foreign Keys Section */}
514
- <div className="bg-white pb-3 rounded-xl border border-zinc-200 dark:bg-neutral-800 dark:border-transparent">
527
+ <div className="bg-white pb-3 rounded-xl border border-zinc-200 overflow-hidden dark:bg-neutral-800 dark:border-transparent">
515
528
  <div className="p-6">
516
529
  <h2 className="text-base font-semibold text-black dark:text-white">Foreign Keys</h2>
517
530
  <p className="text-sm text-zinc-500 dark:text-neutral-400">
@@ -521,11 +534,11 @@ export function TableForm({
521
534
 
522
535
  {/* Existing foreign keys */}
523
536
  {foreignKeys.length > 0 && (
524
- <div className="px-6 pb-6 space-y-3">
537
+ <div className="px-6 pb-6 space-y-3 overflow-x-auto">
525
538
  {foreignKeys.map((fk) => (
526
539
  <div
527
540
  key={fk.columnName}
528
- className="group flex items-center gap-6 2xl:gap-8 pl-4 pr-2 py-2 rounded-lg border border-zinc-200 bg-white hover:bg-zinc-100 transition-colors duration-150 dark:bg-neutral-700 dark:border-transparent dark:hover:bg-neutral-600"
541
+ className="group flex items-center gap-6 2xl:gap-8 pl-4 pr-2 py-2 w-min xl:w-full rounded-lg border border-zinc-200 bg-white hover:bg-zinc-100 transition-colors duration-150 dark:bg-neutral-700 dark:border-transparent dark:hover:bg-neutral-600"
529
542
  >
530
543
  <div className="flex items-center gap-2 flex-1 min-w-[188px] overflow-hidden">
531
544
  <Link className="flex-shrink-0 w-5 h-5 text-zinc-500 dark:text-neutral-400" />
@@ -632,9 +645,8 @@ export function TableForm({
632
645
  <div className="flex justify-end gap-3 max-w-[1080px] mx-auto px-6">
633
646
  <Button
634
647
  type="button"
635
- variant="outline"
636
648
  onClick={() => onOpenChange(false)}
637
- className="h-10 px-4 text-sm font-medium border-zinc-200 shadow-sm dark:bg-neutral-800 dark:text-zinc-300 dark:border-neutral-700 dark:hover:bg-neutral-700"
649
+ className="h-10 px-4 text-sm font-medium bg-white border border-zinc-200 shadow-[0px_1px_2px_0px_rgba(0,0,0,0.1)] text-zinc-950 hover:bg-zinc-50 dark:bg-neutral-600 dark:border-neutral-600 dark:text-white dark:hover:bg-neutral-700"
638
650
  >
639
651
  Cancel
640
652
  </Button>
@@ -643,7 +655,8 @@ export function TableForm({
643
655
  disabled={
644
656
  !form.formState.isValid ||
645
657
  createTableMutation.isPending ||
646
- updateTableMutation.isPending
658
+ updateTableMutation.isPending ||
659
+ (!form.formState.isDirty && !foreignKeysDirty)
647
660
  }
648
661
  className="h-10 px-4 text-sm font-medium bg-zinc-950 text-neutral-50 shadow-sm disabled:opacity-40 dark:bg-emerald-300 dark:text-zinc-950 dark:hover:bg-emerald-400"
649
662
  >
@@ -1,8 +1,7 @@
1
1
  import { memo } from 'react';
2
2
  import { Controller, Control } from 'react-hook-form';
3
3
  import { X, Key } from 'lucide-react';
4
- import { Input } from '@/components/radix/Input';
5
- import { Checkbox } from '@/components';
4
+ import { Input, Checkbox } from '@/components';
6
5
  import { TableFormColumnSchema, TableFormSchema } from '../schema';
7
6
  import { ColumnTypeSelect } from './ColumnTypeSelect';
8
7
 
@@ -25,7 +24,7 @@ export const TableFormColumn = memo(function TableFormColumn({
25
24
  }: TableFormColumnProps) {
26
25
  return (
27
26
  <div
28
- className={`flex items-center gap-6 px-4 py-2 ${
27
+ className={`flex items-center gap-6 px-4 py-2 w-min xl:w-full ${
29
28
  isNewColumn ? 'bg-slate-50 dark:bg-neutral-800' : 'bg-white dark:bg-[#2D2D2D]'
30
29
  }`}
31
30
  >
@@ -24,7 +24,7 @@ export function TableSidebar({
24
24
  }: TableSidebarProps) {
25
25
  return (
26
26
  <FeatureSidebar
27
- title="Database"
27
+ title="Tables"
28
28
  items={tables}
29
29
  selectedItem={selectedTable}
30
30
  onItemSelect={onTableSelect}
@@ -0,0 +1,48 @@
1
+ import { Plus } from 'lucide-react';
2
+ import { Button } from '@/components/radix/Button';
3
+ import { DatabaseTemplate } from '@/features/database/templates';
4
+ import { TemplateCard } from './TemplateCard';
5
+
6
+ interface TablesEmptyStateProps {
7
+ templates: DatabaseTemplate[];
8
+ onCreateTable: () => void;
9
+ onTemplateClick: (template: DatabaseTemplate) => void;
10
+ }
11
+
12
+ export function TablesEmptyState({
13
+ templates,
14
+ onCreateTable,
15
+ onTemplateClick,
16
+ }: TablesEmptyStateProps) {
17
+ return (
18
+ <div className="flex justify-center w-full h-full bg-bg-gray dark:bg-neutral-800 px-6">
19
+ <div className="flex flex-col gap-6 max-w-[1024px] w-full pb-9 pt-6">
20
+ <h2 className="text-xl font-semibold text-zinc-950 dark:text-white leading-7 tracking-[-0.1px]">
21
+ Create Your First Table
22
+ </h2>
23
+ <Button
24
+ className="h-9 w-50 gap-2 font-medium dark:bg-emerald-300 dark:hover:bg-emerald-400 dark:text-black"
25
+ onClick={onCreateTable}
26
+ >
27
+ <Plus className="w-5 h-5" />
28
+ Create Table
29
+ </Button>
30
+ <div className="flex flex-col gap-3">
31
+ <p className="text-sm font-normal text-zinc-500 dark:text-neutral-400 leading-6">
32
+ or choose a template to start
33
+ </p>
34
+ <div className="grid grid-cols-2 xl:grid-cols-3 gap-6">
35
+ {templates.map((template) => (
36
+ <TemplateCard
37
+ key={template.id}
38
+ template={template}
39
+ onClick={() => onTemplateClick(template)}
40
+ showTableCount
41
+ />
42
+ ))}
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ );
48
+ }
@@ -0,0 +1,37 @@
1
+ import { Table } from 'lucide-react';
2
+ import { DatabaseTemplate } from '@/features/database/templates';
3
+
4
+ interface TemplateCardProps {
5
+ template: DatabaseTemplate;
6
+ onClick: () => void;
7
+ showTableCount?: boolean;
8
+ }
9
+
10
+ export function TemplateCard({ template, onClick, showTableCount = false }: TemplateCardProps) {
11
+ return (
12
+ <button
13
+ onClick={onClick}
14
+ className="bg-white dark:bg-[#363636] border border-gray-200 dark:border-[#414141] rounded-[4px] pl-6 pr-4 pt-4 pb-6 text-left transition-colors hover:bg-gray-50 hover:border-gray-300 dark:hover:bg-neutral-700 dark:hover:border-[#525252] hover:shadow-sm flex flex-col gap-3"
15
+ >
16
+ <div className="flex flex-col gap-2">
17
+ <h3 className="text-base font-normal text-zinc-950 dark:text-white leading-6">
18
+ {template.title}
19
+ </h3>
20
+ {/* Fixed height container for description with line clamp */}
21
+ <div className="h-[72px]">
22
+ <p className="text-sm font-normal text-zinc-500 dark:text-neutral-400 leading-6 line-clamp-3">
23
+ {template.description}
24
+ </p>
25
+ </div>
26
+ </div>
27
+ {showTableCount && (
28
+ <div className="flex items-center gap-2">
29
+ <Table className="w-5 h-5 text-zinc-500 dark:text-neutral-400" />
30
+ <p className="text-sm font-normal text-zinc-500 dark:text-neutral-400 leading-6">
31
+ {template.tableCount} {template.tableCount === 1 ? 'Table' : 'Tables'}
32
+ </p>
33
+ </div>
34
+ )}
35
+ </button>
36
+ );
37
+ }
@@ -0,0 +1,92 @@
1
+ import { Button } from '@/components/radix/Button';
2
+ import { DatabaseTemplate } from '@/features/database/templates';
3
+ import { SchemaVisualizer } from '@/features/visualizer/components/SchemaVisualizer';
4
+ import { useRawSQL } from '@/features/database/hooks/useRawSQL';
5
+
6
+ interface TemplatePreviewProps {
7
+ template: DatabaseTemplate;
8
+ onCancel: () => void;
9
+ }
10
+
11
+ export function TemplatePreview({ template, onCancel }: TemplatePreviewProps) {
12
+ const { executeSQL, isPending } = useRawSQL({
13
+ showSuccessToast: true,
14
+ showErrorToast: true,
15
+ onSuccess: () => {
16
+ // Close preview after successful implementation
17
+ onCancel();
18
+ },
19
+ });
20
+
21
+ const handleImplementTemplate = () => {
22
+ executeSQL({ query: template.sql });
23
+ };
24
+
25
+ return (
26
+ <div className="flex flex-col h-full bg-bg-gray dark:bg-neutral-800">
27
+ {/* Top Bar */}
28
+ <div className="flex items-center justify-center gap-3 h-12 px-4 border-b border-gray-200 dark:border-neutral-700 bg-white dark:bg-neutral-800">
29
+ <p className="text-sm font-normal text-zinc-600 dark:text-neutral-400">
30
+ You are previewing a template
31
+ </p>
32
+ <Button
33
+ variant="outline"
34
+ onClick={onCancel}
35
+ className="h-8 px-4 dark:bg-neutral-600 dark:text-zinc-300 dark:border-neutral-600 dark:hover:bg-neutral-700"
36
+ >
37
+ Cancel
38
+ </Button>
39
+ <Button
40
+ className="h-8 px-4 font-medium bg-emerald-300 hover:bg-emerald-400 text-black dark:bg-emerald-300 dark:hover:bg-emerald-400"
41
+ onClick={handleImplementTemplate}
42
+ disabled={isPending}
43
+ >
44
+ {isPending ? 'Implementing...' : 'Implement Template'}
45
+ </Button>
46
+ </div>
47
+
48
+ {/* Visualizer Content */}
49
+ <div className="relative flex-1 overflow-hidden">
50
+ {/* Dot Matrix Background - Light Mode */}
51
+ <div
52
+ className="absolute inset-0 opacity-50 dark:hidden"
53
+ style={{
54
+ backgroundImage: `radial-gradient(circle, #D1D5DB 1px, transparent 1px)`,
55
+ backgroundSize: '12px 12px',
56
+ }}
57
+ />
58
+ {/* Dot Matrix Background - Dark Mode */}
59
+ <div
60
+ className="absolute inset-0 opacity-50 hidden dark:block"
61
+ style={{
62
+ backgroundImage: `radial-gradient(circle, #3B3B3B 1px, transparent 1px)`,
63
+ backgroundSize: '12px 12px',
64
+ }}
65
+ />
66
+
67
+ {/* SchemaVisualizer */}
68
+ <div className="relative z-10 w-full h-full">
69
+ <SchemaVisualizer
70
+ externalSchemas={template.visualizerSchema}
71
+ metadata={{
72
+ auth: {
73
+ oauths: [],
74
+ },
75
+ database: {
76
+ tables: [],
77
+ totalSizeInGB: 0,
78
+ },
79
+ storage: {
80
+ buckets: [],
81
+ totalSizeInGB: 0,
82
+ },
83
+ functions: [],
84
+ }}
85
+ showControls={false}
86
+ showMiniMap={false}
87
+ />
88
+ </div>
89
+ </div>
90
+ </div>
91
+ );
92
+ }
@@ -0,0 +1,19 @@
1
+ export { ColumnTypeSelect } from './ColumnTypeSelect';
2
+ export {
3
+ convertSchemaToColumns,
4
+ DatabaseDataGrid,
5
+ type DatabaseDataGridProps,
6
+ } from './DatabaseDataGrid';
7
+ export { ForeignKeyCell } from './ForeignKeyCell';
8
+ export { ForeignKeyPopover } from './ForeignKeyPopover';
9
+ export { LinkRecordModal } from './LinkRecordModal';
10
+ export { RecordFormDialog } from './RecordFormDialog';
11
+ export { RecordFormField } from './RecordFormField';
12
+ export { TableEmptyState } from './TableEmptyState';
13
+ export { TableForm } from './TableForm';
14
+ export { TableFormColumn } from './TableFormColumn';
15
+ export { TableListSkeleton } from './TableListSkeleton';
16
+ export { TableSidebar } from './TableSidebar';
17
+ export { TablesEmptyState } from './TablesEmptyState';
18
+ export { TemplateCard } from './TemplateCard';
19
+ export { TemplatePreview } from './TemplatePreview';