spine-framework 0.3.124 → 0.3.126

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 (319) hide show
  1. package/.framework/cli/commands/agents.ts +35 -37
  2. package/.framework/cli/commands/auth.ts +35 -34
  3. package/.framework/cli/commands/create-app.ts +104 -40
  4. package/.framework/cli/commands/dev.ts +104 -69
  5. package/.framework/cli/commands/doctor.ts +179 -69
  6. package/.framework/cli/commands/generate.ts +83 -143
  7. package/.framework/cli/commands/init.ts +72 -34
  8. package/.framework/cli/commands/install-app.ts +260 -125
  9. package/.framework/cli/commands/items.ts +33 -44
  10. package/.framework/cli/commands/migrate.ts +122 -40
  11. package/.framework/cli/commands/migrations.ts +33 -40
  12. package/.framework/cli/commands/pipelines.ts +31 -39
  13. package/.framework/cli/commands/status.ts +47 -23
  14. package/.framework/cli/commands/system.ts +47 -37
  15. package/.framework/cli/commands/test.ts +112 -68
  16. package/.framework/cli/commands/validate-app.ts +215 -121
  17. package/.framework/cli/context.ts +112 -130
  18. package/.framework/cli/env-loader.ts +47 -18
  19. package/.framework/cli/index.ts +81 -42
  20. package/.framework/docs/runtime-types.md +1024 -0
  21. package/.framework/functions/_shared/agent-runner.ts +1296 -961
  22. package/.framework/functions/_shared/app-manifest.ts +82 -68
  23. package/.framework/functions/_shared/audit.ts +135 -83
  24. package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
  25. package/.framework/functions/_shared/db.ts +80 -126
  26. package/.framework/functions/_shared/hash-api-key.ts +63 -0
  27. package/.framework/functions/_shared/index.ts +224 -335
  28. package/.framework/functions/_shared/kb.ts +319 -0
  29. package/.framework/functions/_shared/llm.ts +92 -0
  30. package/.framework/functions/_shared/logging.ts +288 -0
  31. package/.framework/functions/_shared/middleware.ts +329 -365
  32. package/.framework/functions/_shared/outcomes.ts +36 -0
  33. package/.framework/functions/_shared/permissions.ts +359 -643
  34. package/.framework/functions/_shared/pipeline-runner.ts +243 -316
  35. package/.framework/functions/_shared/principal.ts +376 -468
  36. package/.framework/functions/_shared/resolve-credentials.ts +102 -0
  37. package/.framework/functions/_shared/resolve-ids.ts +188 -16
  38. package/.framework/functions/_shared/retry-deliveries.ts +104 -0
  39. package/.framework/functions/_shared/schema-utils.ts +611 -373
  40. package/.framework/functions/_shared/testing.ts +207 -137
  41. package/.framework/functions/_shared/tracing.ts +276 -0
  42. package/.framework/functions/_shared/trigger-engine.ts +159 -211
  43. package/.framework/functions/_shared/webhook-registration.ts +95 -81
  44. package/.framework/functions/_shared/webhook-registry.ts +153 -75
  45. package/.framework/functions/account-nodes.ts +31 -53
  46. package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
  47. package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
  48. package/.framework/functions/adapters/openai-outbound.ts +40 -0
  49. package/.framework/functions/admin-data.ts +685 -537
  50. package/.framework/functions/admin-funnel.ts +31 -20
  51. package/.framework/functions/admin-install-funnel.ts +47 -28
  52. package/.framework/functions/admin-signals.ts +47 -29
  53. package/.framework/functions/ai-agents.ts +122 -147
  54. package/.framework/functions/ai-interactions.ts +180 -90
  55. package/.framework/functions/api-keys.ts +250 -192
  56. package/.framework/functions/apps.ts +203 -197
  57. package/.framework/functions/auth.ts +98 -91
  58. package/.framework/functions/cil-agent-ingest.ts +773 -0
  59. package/.framework/functions/cil-agent.ts +592 -0
  60. package/.framework/functions/cil-callmap.ts +1227 -0
  61. package/.framework/functions/cil-config.ts +583 -0
  62. package/.framework/functions/cil-context.ts +445 -0
  63. package/.framework/functions/cil-doc.ts +1752 -0
  64. package/.framework/functions/cil-embeddings.ts +1202 -0
  65. package/.framework/functions/cil-graph.ts +585 -0
  66. package/.framework/functions/cil-ingest.ts +2416 -0
  67. package/.framework/functions/cil-pipeline.ts +318 -0
  68. package/.framework/functions/cil-project.ts +499 -0
  69. package/.framework/functions/cil-validate.ts +469 -0
  70. package/.framework/functions/debug-auth.ts +73 -53
  71. package/.framework/functions/deliveries.ts +117 -0
  72. package/.framework/functions/embeddings.ts +528 -516
  73. package/.framework/functions/eval-harness.ts +158 -106
  74. package/.framework/functions/integration-outbound.ts +311 -0
  75. package/.framework/functions/integration-routes.ts +240 -466
  76. package/.framework/functions/integrations.ts +132 -140
  77. package/.framework/functions/invites.ts +401 -201
  78. package/.framework/functions/item-progress.ts +113 -53
  79. package/.framework/functions/kb.ts +28 -0
  80. package/.framework/functions/logs.ts +239 -222
  81. package/.framework/functions/observability.ts +308 -259
  82. package/.framework/functions/pipeline-executions.ts +179 -235
  83. package/.framework/functions/pipelines.ts +163 -205
  84. package/.framework/functions/prompt-configs.ts +109 -156
  85. package/.framework/functions/roles.ts +97 -147
  86. package/.framework/functions/system-cron.ts +132 -218
  87. package/.framework/functions/system.ts +112 -52
  88. package/.framework/functions/tests.ts +32 -28
  89. package/.framework/functions/timers.ts +162 -210
  90. package/.framework/functions/triggers.ts +282 -346
  91. package/.framework/functions/types.ts +283 -400
  92. package/.framework/migrations/001_core_schema.sql +630 -0
  93. package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
  94. package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
  95. package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
  96. package/.framework/migrations/005_core_observability.sql +598 -0
  97. package/.framework/migrations/006_security_hardening_rls.sql +97 -0
  98. package/.framework/migrations/007_kb_article_list.sql +237 -0
  99. package/.framework/migrations/008_items_target.sql +8 -0
  100. package/.framework/migrations/009_roles_slug_unique.sql +11 -0
  101. package/.framework/public/spine.config.json +91 -0
  102. package/.framework/scripts/app-install-cli.ts +112 -98
  103. package/.framework/src/App.tsx +67 -20
  104. package/.framework/src/apps/admin/index.tsx +97 -27
  105. package/.framework/src/components/AppWrapper.tsx +50 -11
  106. package/.framework/src/components/CustomAppLoader.tsx +131 -22
  107. package/.framework/src/components/admin/AdminListPage.tsx +75 -8
  108. package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
  109. package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
  110. package/.framework/src/components/admin/PageInstructions.tsx +49 -0
  111. package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
  112. package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
  113. package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
  114. package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
  115. package/.framework/src/components/app-sidebar.tsx +50 -3
  116. package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
  117. package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
  118. package/.framework/src/components/kb/KBArticleList.tsx +557 -0
  119. package/.framework/src/components/layout/AppShell.tsx +54 -16
  120. package/.framework/src/components/layout/Header.tsx +50 -38
  121. package/.framework/src/components/layout/Layout.tsx +48 -32
  122. package/.framework/src/components/layout/Sidebar.tsx +167 -16
  123. package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
  124. package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
  125. package/.framework/src/components/runtime/DataFilters.tsx +78 -1
  126. package/.framework/src/components/runtime/DataHeader.tsx +32 -29
  127. package/.framework/src/components/runtime/DataListPage.tsx +161 -2
  128. package/.framework/src/components/runtime/DataStats.tsx +48 -1
  129. package/.framework/src/components/runtime/DataTable.tsx +153 -1
  130. package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
  131. package/.framework/src/components/runtime/index.ts +16 -9
  132. package/.framework/src/components/search-form.tsx +33 -1
  133. package/.framework/src/components/shared/AgentView.tsx +48 -51
  134. package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
  135. package/.framework/src/components/shared/InviteManager.tsx +113 -52
  136. package/.framework/src/components/shared/MemberList.tsx +182 -0
  137. package/.framework/src/components/shared/SchemaFields.tsx +96 -78
  138. package/.framework/src/components/ui/DataTable.tsx +86 -56
  139. package/.framework/src/components/ui/Form.tsx +188 -109
  140. package/.framework/src/components/ui/ItemCard.tsx +86 -58
  141. package/.framework/src/components/ui/ItemListView.tsx +88 -61
  142. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
  143. package/.framework/src/components/ui/Modal.tsx +81 -4
  144. package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
  145. package/.framework/src/components/ui/accordion.tsx +97 -5
  146. package/.framework/src/components/ui/alert-dialog.tsx +225 -13
  147. package/.framework/src/components/ui/alert.tsx +113 -6
  148. package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
  149. package/.framework/src/components/ui/avatar.tsx +129 -7
  150. package/.framework/src/components/ui/badge.tsx +65 -3
  151. package/.framework/src/components/ui/breadcrumb.tsx +145 -8
  152. package/.framework/src/components/ui/button-group.tsx +81 -4
  153. package/.framework/src/components/ui/button.tsx +49 -2
  154. package/.framework/src/components/ui/calendar.tsx +65 -3
  155. package/.framework/src/components/ui/card.tsx +145 -8
  156. package/.framework/src/components/ui/carousel.tsx +129 -7
  157. package/.framework/src/components/ui/chart.tsx +161 -10
  158. package/.framework/src/components/ui/checkbox.tsx +49 -2
  159. package/.framework/src/components/ui/collapsible.tsx +81 -5
  160. package/.framework/src/components/ui/combobox.tsx +305 -20
  161. package/.framework/src/components/ui/command.tsx +177 -11
  162. package/.framework/src/components/ui/context-menu.tsx +273 -17
  163. package/.framework/src/components/ui/dialog.tsx +209 -27
  164. package/.framework/src/components/ui/direction.tsx +64 -4
  165. package/.framework/src/components/ui/drawer.tsx +193 -12
  166. package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
  167. package/.framework/src/components/ui/empty.tsx +145 -9
  168. package/.framework/src/components/ui/field.tsx +209 -14
  169. package/.framework/src/components/ui/hover-card.tsx +81 -4
  170. package/.framework/src/components/ui/input-group.tsx +162 -10
  171. package/.framework/src/components/ui/input-otp.tsx +98 -5
  172. package/.framework/src/components/ui/input.tsx +49 -2
  173. package/.framework/src/components/ui/item.tsx +225 -13
  174. package/.framework/src/components/ui/kbd.tsx +65 -3
  175. package/.framework/src/components/ui/label.tsx +49 -2
  176. package/.framework/src/components/ui/menubar.tsx +289 -17
  177. package/.framework/src/components/ui/native-select.tsx +97 -5
  178. package/.framework/src/components/ui/navigation-menu.tsx +177 -10
  179. package/.framework/src/components/ui/pagination.tsx +161 -9
  180. package/.framework/src/components/ui/popover.tsx +145 -8
  181. package/.framework/src/components/ui/progress.tsx +49 -2
  182. package/.framework/src/components/ui/radio-group.tsx +65 -3
  183. package/.framework/src/components/ui/resizable.tsx +82 -4
  184. package/.framework/src/components/ui/scroll-area.tsx +65 -3
  185. package/.framework/src/components/ui/select.tsx +193 -11
  186. package/.framework/src/components/ui/separator.tsx +49 -2
  187. package/.framework/src/components/ui/sheet.tsx +193 -11
  188. package/.framework/src/components/ui/sidebar.tsx +481 -38
  189. package/.framework/src/components/ui/skeleton.tsx +49 -2
  190. package/.framework/src/components/ui/slider.tsx +49 -2
  191. package/.framework/src/components/ui/sonner.tsx +49 -2
  192. package/.framework/src/components/ui/spinner.tsx +49 -2
  193. package/.framework/src/components/ui/switch.tsx +49 -2
  194. package/.framework/src/components/ui/table-primitives.tsx +160 -33
  195. package/.framework/src/components/ui/table.tsx +161 -9
  196. package/.framework/src/components/ui/tabs.tsx +113 -6
  197. package/.framework/src/components/ui/textarea.tsx +49 -2
  198. package/.framework/src/components/ui/toggle-group.tsx +81 -4
  199. package/.framework/src/components/ui/toggle.tsx +65 -3
  200. package/.framework/src/components/ui/tooltip.tsx +97 -5
  201. package/.framework/src/contexts/AppContext.tsx +129 -45
  202. package/.framework/src/contexts/AuthContext.tsx +187 -144
  203. package/.framework/src/hooks/use-mobile.ts +48 -2
  204. package/.framework/src/hooks/useApi.ts +208 -159
  205. package/.framework/src/hooks/useAppPath.ts +32 -23
  206. package/.framework/src/hooks/useApps.ts +51 -20
  207. package/.framework/src/hooks/useEntityList.ts +32 -78
  208. package/.framework/src/hooks/useEntityRecord.ts +35 -96
  209. package/.framework/src/hooks/useForm.ts +32 -92
  210. package/.framework/src/hooks/useListSchema.ts +49 -78
  211. package/.framework/src/hooks/useSchemaRecord.ts +114 -105
  212. package/.framework/src/lib/api.ts +195 -116
  213. package/.framework/src/lib/supabase.ts +98 -64
  214. package/.framework/src/lib/utils.ts +287 -151
  215. package/.framework/src/main.tsx +49 -3
  216. package/.framework/src/pages/DashboardPage.tsx +52 -29
  217. package/.framework/src/pages/NotFoundPage.tsx +32 -10
  218. package/.framework/src/pages/SetupPage.tsx +32 -12
  219. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
  220. package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
  221. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
  222. package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
  223. package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
  224. package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
  225. package/.framework/src/pages/admin/AppsPage.tsx +49 -2
  226. package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
  227. package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
  228. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
  229. package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
  230. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
  231. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
  232. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
  233. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
  234. package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
  235. package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
  236. package/.framework/src/pages/admin/LogsPage.tsx +422 -75
  237. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
  238. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
  239. package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
  240. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
  241. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
  242. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
  243. package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
  244. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
  245. package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
  246. package/.framework/src/pages/admin/RolesPage.tsx +171 -18
  247. package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
  248. package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
  249. package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
  250. package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
  251. package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
  252. package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
  253. package/.framework/src/pages/admin/TimersPage.tsx +48 -20
  254. package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
  255. package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
  256. package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
  257. package/.framework/src/pages/admin/TypesPage.tsx +48 -20
  258. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
  259. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
  260. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
  261. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
  262. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
  263. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
  264. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
  265. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
  266. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
  267. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  268. package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
  269. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
  270. package/.framework/src/pages/auth/LoginPage.tsx +50 -23
  271. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
  272. package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
  273. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
  274. package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
  275. package/.framework/src/types/auth.ts +128 -71
  276. package/.framework/src/types/types.ts +373 -157
  277. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
  278. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
  279. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
  280. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
  281. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
  282. package/docs/README.md +9 -130
  283. package/netlify.toml +5 -2
  284. package/package.json +13 -25
  285. package/scripts/kb-ingest-docs.ts +203 -0
  286. package/spine.config.json +65 -4
  287. package/.framework/migrations/001_schema.sql +0 -425
  288. package/.framework/migrations/002_rls_and_functions.sql +0 -763
  289. package/.framework/migrations/004_enhancements.sql +0 -43
  290. package/.framework/migrations/005_auth_user_trigger.sql +0 -105
  291. package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
  292. package/.framework/migrations/016_invites.sql +0 -27
  293. package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
  294. package/.framework/migrations/018_apps_required_roles.sql +0 -17
  295. package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
  296. package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
  297. package/.framework/migrations/021_app_domains.sql +0 -112
  298. package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
  299. package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
  300. package/.framework/migrations/024_messages_account_id.sql +0 -9
  301. package/.framework/migrations/025_retype_threads_messages.sql +0 -240
  302. package/.framework/migrations/026_fix_rls_policies.sql +0 -47
  303. package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
  304. package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
  305. package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
  306. package/.framework/migrations/030_messages_updated_by.sql +0 -6
  307. package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
  308. package/docs/APPS.md +0 -232
  309. package/docs/ARCHITECTURE.md +0 -246
  310. package/docs/INSTALL.md +0 -155
  311. package/docs/design-schema-spec.md +0 -1837
  312. package/docs/dev-guides/01-create-an-app.md +0 -183
  313. package/docs/dev-guides/02-create-a-function.md +0 -178
  314. package/docs/dev-guides/03-create-a-component.md +0 -178
  315. package/docs/dev-guides/04-webhook-handlers.md +0 -129
  316. package/docs/dev-guides/05-testing.md +0 -168
  317. package/docs/dev-guides/README.md +0 -40
  318. package/docs/npm-packages-plan.md +0 -288
  319. package/docs/spine-core--api-reference.md +0 -822
@@ -1,10 +1,5 @@
1
- -- Migration 003: System Data
2
- -- Seeds for day-zero operation including system role, system account, spine-core app,
3
- -- runtime types, admin app, and RPC functions.
4
-
5
- -- ============================================
6
- -- 1. SYSTEM ROLE (system_admin)
7
- -- ============================================
1
+ -- Spine v2 consolidated core system data
2
+ -- System roles and essential platform records.
8
3
 
9
4
  INSERT INTO public.roles (id, slug, name, description, permissions, is_system, is_active, is_protected, app_id, account_id)
10
5
  VALUES (
@@ -19,136 +14,25 @@ VALUES (
19
14
  NULL,
20
15
  NULL
21
16
  )
22
- ON CONFLICT (app_id, slug) DO NOTHING;
23
-
24
- -- NOTE: System account inserted after types are seeded (section 5) to satisfy FK constraint.
25
-
26
- -- ============================================
27
- -- 3. SYSTEM APP (spine-core)
28
- -- ============================================
29
-
30
- INSERT INTO public.apps (id, slug, name, description, version, app_type, source, is_active, is_system, renderer, route_prefix)
31
- VALUES (
32
- gen_random_uuid(),
33
- 'spine-core',
34
- 'Spine Core',
35
- 'Core Spine runtime - provides accounts, people, items, threads, messages, links, attachments, watchers',
36
- '1.0.0',
37
- 'system',
38
- 'builtin',
39
- true,
40
- true,
41
- 'none',
42
- NULL
43
- )
44
17
  ON CONFLICT (slug) DO NOTHING;
45
18
 
46
- -- ============================================
47
- -- 4. ADMIN APP
48
- -- ============================================
49
-
50
- INSERT INTO public.apps (
51
- id, slug, name, description, icon, color, version,
52
- app_type, source, config, nav_items, min_role,
53
- is_active, is_system, route_prefix, renderer
54
- )
55
- VALUES (
56
- gen_random_uuid(),
57
- 'admin',
58
- 'Admin',
59
- 'Spine system administration interface',
60
- 'settings',
61
- 'slate',
62
- '1.0.0',
63
- 'system',
64
- 'builtin',
65
- '{}'::jsonb,
66
- '[]'::jsonb,
67
- 'system_admin',
68
- true,
69
- true,
70
- '/admin',
71
- 'custom'
72
- )
73
- ON CONFLICT (slug) DO UPDATE SET
74
- route_prefix = EXCLUDED.route_prefix,
75
- renderer = EXCLUDED.renderer,
76
- min_role = EXCLUDED.min_role,
77
- is_system = EXCLUDED.is_system,
78
- app_type = EXCLUDED.app_type;
79
-
80
- -- ============================================
81
- -- 5. RUNTIME ENTITY TYPES (8 core types)
82
- -- ============================================
83
-
84
- DO $$
85
- DECLARE
86
- v_spine_core_app_id uuid;
87
- v_system_account_id uuid;
88
- BEGIN
89
- SELECT id INTO v_spine_core_app_id FROM public.apps WHERE slug = 'spine-core' LIMIT 1;
90
- SELECT id INTO v_system_account_id FROM public.accounts WHERE slug = 'spine-system' LIMIT 1;
91
-
92
- -- 5.1 accounts type
93
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
94
- VALUES (
95
- gen_random_uuid(),
96
- v_spine_core_app_id,
97
- 'account',
98
- 'account',
99
- 'Account',
100
- 'Organization or tenant account',
101
- jsonb_build_object(
102
- 'scope', 'account',
103
- 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
104
- 'fields', jsonb_build_object(
105
- 'slug', jsonb_build_object('data_type', 'text', 'label', 'Slug', 'required', true, 'system', true, 'validation', null),
106
- 'display_name', jsonb_build_object('data_type', 'text', 'label', 'Display Name', 'required', true, 'system', true, 'validation', null),
107
- 'description', jsonb_build_object('data_type', 'textarea', 'label', 'Description', 'required', false, 'system', true, 'validation', null),
108
- 'is_active', jsonb_build_object('data_type', 'boolean', 'label', 'Active', 'required', true, 'system', true, 'validation', null),
109
- 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
110
- 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
111
- ),
112
- 'views', jsonb_build_object(
113
- 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Accounts',
114
- 'fields', jsonb_build_object(
115
- 'display_name', jsonb_build_object('sortable', true, 'display_type', 'text'),
116
- 'slug', jsonb_build_object('sortable', true, 'display_type', 'text'),
117
- 'is_active', jsonb_build_object('sortable', true, 'display_type', 'badge')
118
- )
119
- ),
120
- 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Account',
121
- 'sections', jsonb_build_array(
122
- jsonb_build_object('title', 'Overview', 'fields', jsonb_build_array('slug', 'display_name', 'description', 'is_active')),
123
- jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
124
- )
125
- )
126
- )
127
- ),
128
- '{}'::jsonb,
129
- 'pack',
130
- true
131
- )
132
-
133
- ON CONFLICT (app_id, kind, slug) DO NOTHING;
134
-
135
- -- 2. MASTER SYSTEM ACCOUNT (inserted here to satisfy FK on type_id)
136
- INSERT INTO public.accounts (id, slug, display_name, description, data, is_active, design_schema, validation_schema, type_id)
137
- SELECT
138
- gen_random_uuid(),
139
- 'spine-system',
140
- 'Spine System',
141
- 'Master system account for internal Spine operations',
142
- '{}'::jsonb,
143
- true,
144
- design_schema,
145
- validation_schema,
146
- id
147
- FROM public.types WHERE slug = 'account' LIMIT 1
148
- ON CONFLICT (slug) DO NOTHING;
19
+ INSERT INTO public.roles (id, slug, name, description, permissions, is_system, is_active, is_protected, app_id, account_id)
20
+ VALUES
21
+ (gen_random_uuid(), 'engineering', 'Engineering', 'Engineering — work tracking, delivery, quality, and code intelligence', '["*"]'::jsonb, true, true, false, NULL, NULL),
22
+ (gen_random_uuid(), 'engineering_admin', 'Engineering Admin', 'Engineering administrator with invitation and configuration privileges', '["*"]'::jsonb, true, true, false, NULL, NULL),
23
+ (gen_random_uuid(), 'product', 'Product', 'Product — discovery, prioritization, and roadmap ownership', '["*"]'::jsonb, true, true, false, NULL, NULL),
24
+ (gen_random_uuid(), 'docs', 'Docs', 'Docs — documentation and knowledge-base authoring', '["*"]'::jsonb, true, true, false, NULL, NULL),
25
+ (gen_random_uuid(), 'qa', 'QA', 'QA — test plans, test runs, and quality gates', '["*"]'::jsonb, true, true, false, NULL, NULL),
26
+ (gen_random_uuid(), 'devops', 'DevOps', 'DevOps — delivery, observability, and incident response', '["*"]'::jsonb, true, true, false, NULL, NULL),
27
+ (gen_random_uuid(), 'management', 'Management', 'Management — cross-team oversight and operational control', '["*"]'::jsonb, true, true, false, NULL, NULL),
28
+ (gen_random_uuid(), 'sales', 'Sales', 'Sales — opportunities, deals, and customer communications', '["*"]'::jsonb, true, true, false, NULL, NULL),
29
+ (gen_random_uuid(), 'csm', 'Customer Success Manager', 'CSM — account health, support, and customer success', '["*"]'::jsonb, true, true, false, NULL, NULL),
30
+ (gen_random_uuid(), 'tam', 'Technical Account Manager', 'TAM — technical account health and technical signals', '["*"]'::jsonb, true, true, false, NULL, NULL),
31
+ (gen_random_uuid(), 'support', 'Support', 'Support — tickets, community moderation, and knowledge base', '["*"]'::jsonb, true, true, false, NULL, NULL),
32
+ (gen_random_uuid(), 'support_admin', 'Support Admin', 'Support administrator — can invite and manage support staff', '["*"]'::jsonb, true, true, false, NULL, NULL)
33
+ ON CONFLICT (slug) DO NOTHING;
149
34
 
150
- -- 5.2 people type
151
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
35
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
152
36
  VALUES (
153
37
  gen_random_uuid(),
154
38
  v_spine_core_app_id,
@@ -194,8 +78,7 @@ BEGIN
194
78
 
195
79
  ON CONFLICT (app_id, kind, slug) DO NOTHING;
196
80
 
197
- -- 5.3 items type
198
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
81
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
199
82
  VALUES (
200
83
  gen_random_uuid(),
201
84
  v_spine_core_app_id,
@@ -238,8 +121,7 @@ BEGIN
238
121
 
239
122
  ON CONFLICT (app_id, kind, slug) DO NOTHING;
240
123
 
241
- -- 5.4 threads type
242
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
124
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
243
125
  VALUES (
244
126
  gen_random_uuid(),
245
127
  v_spine_core_app_id,
@@ -290,8 +172,7 @@ BEGIN
290
172
 
291
173
  ON CONFLICT (app_id, kind, slug) DO NOTHING;
292
174
 
293
- -- 5.5 messages type
294
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
175
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
295
176
  VALUES (
296
177
  gen_random_uuid(),
297
178
  v_spine_core_app_id,
@@ -341,8 +222,7 @@ BEGIN
341
222
 
342
223
  ON CONFLICT (app_id, kind, slug) DO NOTHING;
343
224
 
344
- -- 5.6 links type
345
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
225
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
346
226
  VALUES (
347
227
  gen_random_uuid(),
348
228
  v_spine_core_app_id,
@@ -386,8 +266,7 @@ BEGIN
386
266
 
387
267
  ON CONFLICT (app_id, kind, slug) DO NOTHING;
388
268
 
389
- -- 5.7 attachments type
390
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
269
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
391
270
  VALUES (
392
271
  gen_random_uuid(),
393
272
  v_spine_core_app_id,
@@ -432,8 +311,7 @@ BEGIN
432
311
 
433
312
  ON CONFLICT (app_id, kind, slug) DO NOTHING;
434
313
 
435
- -- 5.8 watchers type
436
- INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
314
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
437
315
  VALUES (
438
316
  gen_random_uuid(),
439
317
  v_spine_core_app_id,
@@ -478,17 +356,12 @@ BEGIN
478
356
 
479
357
  ON CONFLICT (app_id, kind, slug) DO NOTHING;
480
358
 
481
- -- Update the spine-system account with the actual accounts type_id
482
- UPDATE public.accounts
359
+ UPDATE public.accounts
483
360
  SET type_id = (SELECT id FROM public.types WHERE slug = 'account' AND app_id = v_spine_core_app_id LIMIT 1)
484
361
  WHERE slug = 'spine-system';
485
362
 
486
363
  END $$;
487
364
 
488
- -- ============================================
489
- -- 6. RPC FUNCTION: get_account_apps
490
- -- ============================================
491
-
492
365
  CREATE OR REPLACE FUNCTION public.get_account_apps(
493
366
  account_id uuid,
494
367
  include_system boolean DEFAULT true,
@@ -547,4 +420,4 @@ BEGIN
547
420
  a.app_type,
548
421
  a.name;
549
422
  END;
550
- $function$;
423
+ $function$;
@@ -0,0 +1,421 @@
1
+ -- Spine v2 consolidated RPCs and integration broker
2
+ -- Vector search RPC, integration broker schema, and broker RLS/policies.
3
+
4
+ DO $$
5
+ BEGIN
6
+ IF NOT EXISTS (
7
+ SELECT 1 FROM pg_indexes
8
+ WHERE schemaname = 'public'
9
+ AND tablename = 'embeddings'
10
+ AND indexname = 'embeddings_embedding_hnsw_idx'
11
+ ) THEN
12
+ EXECUTE 'CREATE INDEX embeddings_embedding_hnsw_idx
13
+ ON public.embeddings
14
+ USING hnsw (embedding vector_cosine_ops)
15
+ WITH (m = 16, ef_construction = 64)';
16
+ END IF;
17
+ END
18
+ $$;
19
+
20
+ CREATE OR REPLACE FUNCTION public.match_embeddings(
21
+ query_embedding vector(1536),
22
+ match_count int DEFAULT 10,
23
+ filter_account_ids uuid[] DEFAULT NULL,
24
+ filter_vector_type text DEFAULT NULL,
25
+ similarity_threshold float DEFAULT 0.15
26
+ )
27
+ RETURNS TABLE (
28
+ id uuid,
29
+ document_id text,
30
+ content text,
31
+ metadata jsonb,
32
+ account_id uuid,
33
+ similarity float
34
+ )
35
+ LANGUAGE plpgsql
36
+ SECURITY DEFINER
37
+ SET search_path = public
38
+ AS $$
39
+ BEGIN
40
+ RETURN QUERY
41
+ SELECT
42
+ e.id,
43
+ e.document_id,
44
+ e.content,
45
+ e.metadata,
46
+ e.account_id,
47
+ 1 - (e.embedding <=> query_embedding) AS similarity
48
+ FROM public.embeddings e
49
+ WHERE
50
+ (filter_account_ids IS NULL OR e.account_id = ANY(filter_account_ids))
51
+ AND (filter_vector_type IS NULL OR e.metadata->>'vector_type' = filter_vector_type)
52
+ AND (1 - (e.embedding <=> query_embedding)) >= similarity_threshold
53
+ ORDER BY e.embedding <=> query_embedding
54
+ LIMIT match_count;
55
+ END
56
+ $$;
57
+
58
+ GRANT EXECUTE ON FUNCTION public.match_embeddings(vector, int, uuid[], text, float) TO authenticated;
59
+ GRANT EXECUTE ON FUNCTION public.match_embeddings(vector, int, uuid[], text, float) TO service_role;
60
+
61
+ CREATE OR REPLACE FUNCTION public.search_similar_embeddings(
62
+ p_account_id uuid,
63
+ p_model_id text,
64
+ p_query_embedding vector(1536),
65
+ p_limit int DEFAULT 10,
66
+ p_threshold float DEFAULT 0.7
67
+ )
68
+ RETURNS TABLE (
69
+ id uuid,
70
+ document_id text,
71
+ content text,
72
+ metadata jsonb,
73
+ similarity float
74
+ )
75
+ LANGUAGE plpgsql
76
+ SECURITY DEFINER
77
+ SET search_path = public
78
+ AS $$
79
+ BEGIN
80
+ RETURN QUERY
81
+ SELECT
82
+ e.id,
83
+ e.document_id,
84
+ e.content,
85
+ e.metadata,
86
+ 1 - (e.embedding <=> p_query_embedding) AS similarity
87
+ FROM public.embeddings e
88
+ WHERE
89
+ e.account_id = p_account_id
90
+ AND e.model_id = p_model_id
91
+ AND e.approved_at IS NOT NULL
92
+ AND e.revoked_at IS NULL
93
+ AND (1 - (e.embedding <=> p_query_embedding)) >= p_threshold
94
+ ORDER BY e.embedding <=> p_query_embedding
95
+ LIMIT p_limit;
96
+ END
97
+ $$;
98
+
99
+ GRANT EXECUTE ON FUNCTION public.search_similar_embeddings(uuid, text, vector, int, float) TO authenticated;
100
+ GRANT EXECUTE ON FUNCTION public.search_similar_embeddings(uuid, text, vector, int, float) TO service_role;
101
+
102
+ -- ============================================
103
+ -- INTEGRATIONS: restore/augment columns
104
+ -- ============================================
105
+
106
+ ALTER TABLE public.integrations
107
+ ADD COLUMN IF NOT EXISTS slug text,
108
+ ADD COLUMN IF NOT EXISTS integration_type text NOT NULL DEFAULT 'webhook',
109
+ ADD COLUMN IF NOT EXISTS provider text,
110
+ ADD COLUMN IF NOT EXISTS version text,
111
+ ADD COLUMN IF NOT EXISTS credentials jsonb DEFAULT '{}',
112
+ ADD COLUMN IF NOT EXISTS is_configured boolean DEFAULT false,
113
+ ADD COLUMN IF NOT EXISTS created_by uuid,
114
+ ADD COLUMN IF NOT EXISTS ownership text DEFAULT 'tenant';
115
+
116
+ COMMENT ON COLUMN public.integrations.integration_type IS 'Semantic category: webhook, oauth, api, scheduled_sync';
117
+ COMMENT ON COLUMN public.integrations.provider IS 'Provider name: stripe, kibo, make, openai, etc.';
118
+ COMMENT ON COLUMN public.integrations.credentials IS 'Secrets map with source/value pairs: { field: { source: value|env_var, value: string } }';
119
+ COMMENT ON COLUMN public.integrations.is_configured IS 'True when required credentials are present';
120
+
121
+ -- Replace the old unique key with one that scopes by account
122
+ ALTER TABLE public.integrations DROP CONSTRAINT IF EXISTS integrations_app_id_slug_key;
123
+ ALTER TABLE public.integrations ADD CONSTRAINT integrations_app_account_slug_key UNIQUE (app_id, account_id, slug);
124
+
125
+ ALTER TABLE public.integrations ADD CONSTRAINT fk_integrations_created_by
126
+ FOREIGN KEY (created_by) REFERENCES public.people(id) ON DELETE SET NULL;
127
+
128
+ -- ============================================
129
+ -- API KEYS: restore/augment columns
130
+ -- ============================================
131
+
132
+ ALTER TABLE public.api_keys
133
+ ADD COLUMN IF NOT EXISTS app_id uuid,
134
+ ADD COLUMN IF NOT EXISTS slug text,
135
+ ADD COLUMN IF NOT EXISTS integration_id uuid,
136
+ ADD COLUMN IF NOT EXISTS key_prefix text,
137
+ ADD COLUMN IF NOT EXISTS key_hash text,
138
+ ADD COLUMN IF NOT EXISTS key_type text NOT NULL DEFAULT 'inbound',
139
+ ADD COLUMN IF NOT EXISTS permissions jsonb DEFAULT '[]',
140
+ ADD COLUMN IF NOT EXISTS scopes text[] DEFAULT '{}',
141
+ ADD COLUMN IF NOT EXISTS rate_limit integer DEFAULT 100,
142
+ ADD COLUMN IF NOT EXISTS expires_at timestamptz,
143
+ ADD COLUMN IF NOT EXISTS is_internal boolean DEFAULT false,
144
+ ADD COLUMN IF NOT EXISTS machine_type text,
145
+ ADD COLUMN IF NOT EXISTS created_by uuid,
146
+ ADD COLUMN IF NOT EXISTS ownership text DEFAULT 'tenant';
147
+
148
+ COMMENT ON COLUMN public.api_keys.integration_id IS 'The integration this key is bound to';
149
+ COMMENT ON COLUMN public.api_keys.key_prefix IS 'Plaintext first N chars used for key lookup and UI';
150
+ COMMENT ON COLUMN public.api_keys.key_hash IS 'Salted slow hash of the full key';
151
+ COMMENT ON COLUMN public.api_keys.key_type IS 'inbound, outbound, internal, cli';
152
+ COMMENT ON COLUMN public.api_keys.rate_limit IS 'Requests per rate_limit_window_seconds';
153
+
154
+ ALTER TABLE public.api_keys ADD CONSTRAINT fk_api_keys_integration
155
+ FOREIGN KEY (integration_id) REFERENCES public.integrations(id) ON DELETE CASCADE;
156
+ ALTER TABLE public.api_keys ADD CONSTRAINT fk_api_keys_created_by
157
+ FOREIGN KEY (created_by) REFERENCES public.people(id) ON DELETE SET NULL;
158
+
159
+ -- Unique key for key_hash (multiple NULLs allowed)
160
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_api_keys_key_hash ON public.api_keys(key_hash) WHERE key_hash IS NOT NULL;
161
+
162
+ -- Scope api_keys slug by account as well
163
+ ALTER TABLE public.api_keys DROP CONSTRAINT IF EXISTS api_keys_app_id_slug_key;
164
+ ALTER TABLE public.api_keys ADD CONSTRAINT api_keys_app_account_slug_key UNIQUE (app_id, account_id, slug);
165
+
166
+ -- ============================================
167
+ -- API KEY USAGE LOGS
168
+ -- ============================================
169
+
170
+ CREATE TABLE IF NOT EXISTS public.api_key_usage_logs (
171
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
172
+ api_key_id uuid NOT NULL,
173
+ account_id uuid,
174
+ request_method text,
175
+ request_path text,
176
+ request_ip text,
177
+ user_agent text,
178
+ response_status integer,
179
+ response_size integer,
180
+ duration_ms integer,
181
+ success boolean DEFAULT true,
182
+ error_message text,
183
+ metadata jsonb DEFAULT '{}',
184
+ created_at timestamptz DEFAULT now()
185
+ );
186
+
187
+ CREATE INDEX IF NOT EXISTS idx_api_key_usage_logs_api_key_id ON public.api_key_usage_logs(api_key_id);
188
+ CREATE INDEX IF NOT EXISTS idx_api_key_usage_logs_created_at ON public.api_key_usage_logs(created_at);
189
+
190
+ ALTER TABLE public.api_key_usage_logs ADD CONSTRAINT fk_akul_api_key
191
+ FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE CASCADE;
192
+ ALTER TABLE public.api_key_usage_logs ADD CONSTRAINT fk_akul_account
193
+ FOREIGN KEY (account_id) REFERENCES public.accounts(id) ON DELETE SET NULL;
194
+
195
+ -- ============================================
196
+ -- WEBHOOK HANDLERS
197
+ -- ============================================
198
+
199
+ CREATE TABLE IF NOT EXISTS public.webhook_handlers (
200
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
201
+ app_id uuid,
202
+ account_id uuid,
203
+ name text NOT NULL,
204
+ function_name text NOT NULL,
205
+ description text,
206
+ events text[] DEFAULT '{}',
207
+ is_active boolean DEFAULT true,
208
+ is_deleted boolean DEFAULT false,
209
+ deleted_at timestamptz,
210
+ created_at timestamptz DEFAULT now(),
211
+ updated_at timestamptz DEFAULT now(),
212
+ UNIQUE (app_id, account_id, name)
213
+ );
214
+
215
+ CREATE INDEX IF NOT EXISTS idx_webhook_handlers_name ON public.webhook_handlers(name) WHERE is_active = true AND is_deleted = false;
216
+ CREATE INDEX IF NOT EXISTS idx_webhook_handlers_account ON public.webhook_handlers(account_id) WHERE is_deleted = false;
217
+ CREATE INDEX IF NOT EXISTS idx_webhook_handlers_events ON public.webhook_handlers USING GIN(events) WHERE is_active = true;
218
+
219
+ ALTER TABLE public.webhook_handlers ADD CONSTRAINT fk_webhook_handlers_app
220
+ FOREIGN KEY (app_id) REFERENCES public.apps(id) ON DELETE SET NULL;
221
+ ALTER TABLE public.webhook_handlers ADD CONSTRAINT fk_webhook_handlers_account
222
+ FOREIGN KEY (account_id) REFERENCES public.accounts(id) ON DELETE CASCADE;
223
+
224
+ COMMENT ON TABLE public.webhook_handlers IS 'Dynamic registry for webhook handlers. Custom functions self-register here to be discoverable by the integration-routes handler without static imports.';
225
+
226
+ -- ============================================
227
+ -- WEBHOOK DELIVERIES (inbound + outbound ledger)
228
+ -- ============================================
229
+
230
+ CREATE TABLE IF NOT EXISTS public.webhook_deliveries (
231
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
232
+ app_id uuid,
233
+ account_id uuid,
234
+ direction text NOT NULL CHECK (direction IN ('inbound', 'outbound')),
235
+ integration_id uuid,
236
+ api_key_id uuid,
237
+ handler_name text,
238
+ action_slug text,
239
+ record_id uuid,
240
+ external_id text,
241
+ payload jsonb DEFAULT '{}',
242
+ status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'delivered', 'failed', 'cancelled')),
243
+ attempt_count integer DEFAULT 0,
244
+ max_attempts integer DEFAULT 3,
245
+ next_attempt_at timestamptz,
246
+ last_error text,
247
+ response_status integer,
248
+ response_body jsonb,
249
+ duration_ms integer,
250
+ created_at timestamptz DEFAULT now(),
251
+ updated_at timestamptz DEFAULT now()
252
+ );
253
+
254
+ CREATE INDEX IF NOT EXISTS idx_webhook_deliveries_status_next_attempt ON public.webhook_deliveries(status, next_attempt_at);
255
+ CREATE INDEX IF NOT EXISTS idx_webhook_deliveries_integration_external ON public.webhook_deliveries(integration_id, external_id);
256
+ CREATE INDEX IF NOT EXISTS idx_webhook_deliveries_account_created ON public.webhook_deliveries(account_id, created_at);
257
+
258
+ ALTER TABLE public.webhook_deliveries ADD CONSTRAINT fk_webhook_deliveries_integration
259
+ FOREIGN KEY (integration_id) REFERENCES public.integrations(id) ON DELETE SET NULL;
260
+ ALTER TABLE public.webhook_deliveries ADD CONSTRAINT fk_webhook_deliveries_api_key
261
+ FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
262
+
263
+ COMMENT ON TABLE public.webhook_deliveries IS 'Shared delivery/retry ledger for inbound and outbound integration calls.';
264
+
265
+ -- ============================================
266
+ -- DROP UNUSED integration_routes
267
+ -- ============================================
268
+
269
+ DROP TABLE IF EXISTS public.integration_routes CASCADE;
270
+
271
+ -- ============================================
272
+ -- RLS
273
+ -- ============================================
274
+
275
+ ALTER TABLE public.integrations ENABLE ROW LEVEL SECURITY;
276
+ ALTER TABLE public.api_keys ENABLE ROW LEVEL SECURITY;
277
+ ALTER TABLE public.api_key_usage_logs ENABLE ROW LEVEL SECURITY;
278
+ ALTER TABLE public.webhook_handlers ENABLE ROW LEVEL SECURITY;
279
+ ALTER TABLE public.webhook_deliveries ENABLE ROW LEVEL SECURITY;
280
+
281
+ DROP POLICY IF EXISTS integrations_access ON public.integrations;
282
+ CREATE POLICY integrations_access ON public.integrations FOR ALL
283
+ USING (account_id IN (SELECT public.get_accessible_accounts(auth.uid()))
284
+ OR auth.uid() IS NULL);
285
+
286
+ DROP POLICY IF EXISTS api_keys_access ON public.api_keys;
287
+ CREATE POLICY api_keys_access ON public.api_keys FOR ALL
288
+ USING (account_id IN (SELECT public.get_accessible_accounts(auth.uid()))
289
+ OR auth.uid() IS NULL);
290
+
291
+ DROP POLICY IF EXISTS akul_access ON public.api_key_usage_logs;
292
+ CREATE POLICY akul_access ON public.api_key_usage_logs FOR ALL
293
+ USING (account_id IN (SELECT public.get_accessible_accounts(auth.uid()))
294
+ OR auth.uid() IS NULL);
295
+
296
+ DROP POLICY IF EXISTS webhook_handlers_access ON public.webhook_handlers;
297
+ CREATE POLICY webhook_handlers_access ON public.webhook_handlers FOR ALL
298
+ USING (account_id IN (SELECT public.get_accessible_accounts(auth.uid()))
299
+ OR auth.uid() IS NULL);
300
+
301
+ DROP POLICY IF EXISTS webhook_deliveries_access ON public.webhook_deliveries;
302
+ CREATE POLICY webhook_deliveries_access ON public.webhook_deliveries FOR ALL
303
+ USING (account_id IN (SELECT public.get_accessible_accounts(auth.uid()))
304
+ OR auth.uid() IS NULL);
305
+
306
+ -- Service role bypass for all broker tables
307
+ DROP POLICY IF EXISTS integrations_service_role ON public.integrations;
308
+ CREATE POLICY integrations_service_role ON public.integrations FOR ALL TO service_role USING (true) WITH CHECK (true);
309
+
310
+ DROP POLICY IF EXISTS api_keys_service_role ON public.api_keys;
311
+ CREATE POLICY api_keys_service_role ON public.api_keys FOR ALL TO service_role USING (true) WITH CHECK (true);
312
+
313
+ DROP POLICY IF EXISTS akul_service_role ON public.api_key_usage_logs;
314
+ CREATE POLICY akul_service_role ON public.api_key_usage_logs FOR ALL TO service_role USING (true) WITH CHECK (true);
315
+
316
+ DROP POLICY IF EXISTS webhook_handlers_service_role ON public.webhook_handlers;
317
+ CREATE POLICY webhook_handlers_service_role ON public.webhook_handlers FOR ALL TO service_role USING (true) WITH CHECK (true);
318
+
319
+ DROP POLICY IF EXISTS webhook_deliveries_service_role ON public.webhook_deliveries;
320
+ CREATE POLICY webhook_deliveries_service_role ON public.webhook_deliveries FOR ALL TO service_role USING (true) WITH CHECK (true);
321
+
322
+ -- ============================================
323
+ -- updated_at triggers
324
+ -- ============================================
325
+
326
+ CREATE OR REPLACE FUNCTION public.set_updated_at()
327
+ RETURNS TRIGGER AS $$
328
+ BEGIN
329
+ NEW.updated_at = now();
330
+ RETURN NEW;
331
+ END;
332
+ $$ LANGUAGE plpgsql;
333
+
334
+ DROP TRIGGER IF EXISTS set_updated_at_integrations ON public.integrations;
335
+ CREATE TRIGGER set_updated_at_integrations
336
+ BEFORE UPDATE ON public.integrations
337
+ FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
338
+
339
+ DROP TRIGGER IF EXISTS set_updated_at_api_keys ON public.api_keys;
340
+ CREATE TRIGGER set_updated_at_api_keys
341
+ BEFORE UPDATE ON public.api_keys
342
+ FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
343
+
344
+ DROP TRIGGER IF EXISTS set_updated_at_webhook_handlers ON public.webhook_handlers;
345
+ CREATE TRIGGER set_updated_at_webhook_handlers
346
+ BEFORE UPDATE ON public.webhook_handlers
347
+ FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
348
+
349
+ DROP TRIGGER IF EXISTS set_updated_at_webhook_deliveries ON public.webhook_deliveries;
350
+ CREATE TRIGGER set_updated_at_webhook_deliveries
351
+ BEFORE UPDATE ON public.webhook_deliveries
352
+ FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
353
+
354
+ -- ============================================
355
+ -- SEED: webhook_event type, openai integration, generic handler
356
+ -- ============================================
357
+
358
+ INSERT INTO public.types (
359
+ app_id, kind, slug, name, description, icon, color,
360
+ design_schema, validation_schema, ownership, is_active
361
+ )
362
+ VALUES (
363
+ NULL,
364
+ 'item',
365
+ 'webhook_event',
366
+ 'Webhook Event',
367
+ 'Raw or normalized inbound webhook payload captured by the generic adapter for debugging.',
368
+ 'radio-receiver',
369
+ '#6366F1',
370
+ '{"scope":"account","fields":{"provider":{"data_type":"text","label":"Provider","required":false,"system":false},"event":{"data_type":"text","label":"Event","required":false,"system":false},"payload":{"data_type":"json","label":"Payload","required":true,"system":false},"headers":{"data_type":"json","label":"Headers","required":false,"system":false}},"views":{"default_list":{"type":"list","display":"table","label":"Webhook Events","fields":{"provider":{"display_type":"text"},"event":{"display_type":"text"},"created_at":{"display_type":"timestamp"}},"default_sort":{"field":"created_at","direction":"desc"}},"default_detail":{"type":"detail","label":"Webhook Event","sections":[{"title":"Payload","fields":{"provider":{"display_type":"input"},"event":{"display_type":"input"},"payload":{"display_type":"textarea"},"headers":{"display_type":"textarea"}}}]},"record_permissions":{"system-admin":["create","read","update","delete"]},"functionality":null}',
371
+ '{}',
372
+ 'system',
373
+ true
374
+ )
375
+ ON CONFLICT (app_id, kind, slug) DO NOTHING;
376
+
377
+ INSERT INTO public.integrations (
378
+ app_id, account_id, slug, name, description,
379
+ integration_type, provider, version, config, credentials,
380
+ is_active, is_system, is_configured, ownership
381
+ )
382
+ VALUES (
383
+ NULL, NULL, 'openai', 'OpenAI', 'System OpenAI integration for AI agent and embedding calls.', 'api', 'openai', 'v1',
384
+ '{"base_url":"https://api.openai.com/v1","outbound_adapter":"adapters/openai-outbound","models":{"chat":"gpt-4o-mini","embedding":"text-embedding-3-small"}}',
385
+ '{"api_token":{"source":"env_var","value":"OPENAI_API_KEY"}}',
386
+ true, true, true, 'system'
387
+ )
388
+ ON CONFLICT (app_id, account_id, slug) DO NOTHING;
389
+
390
+ INSERT INTO public.webhook_handlers (
391
+ app_id, account_id, name, function_name, description, events, is_active
392
+ )
393
+ VALUES (
394
+ NULL, NULL, 'generic-webhook', 'adapters/generic-webhook-inbound',
395
+ 'Generic pass-through adapter that stores the raw webhook payload as a webhook_event item.',
396
+ '{}', true
397
+ )
398
+ ON CONFLICT (app_id, account_id, name) DO NOTHING;
399
+
400
+ INSERT INTO public.webhook_handlers (
401
+ app_id, account_id, name, function_name, description, events, is_active
402
+ )
403
+ VALUES (
404
+ NULL, NULL, 'portal-signals', 'custom/apps/portal/functions/custom_portal-signals',
405
+ 'Portal funnel signal adapter that transforms portal engagement payloads into funnel_signal records.',
406
+ '{"funnel.signal"}', true
407
+ )
408
+ ON CONFLICT (app_id, account_id, name) DO NOTHING;
409
+
410
+ INSERT INTO public.integrations (
411
+ app_id, account_id, slug, name, description,
412
+ integration_type, provider, version, config, credentials,
413
+ is_active, is_system, is_configured, ownership
414
+ )
415
+ VALUES (
416
+ NULL, NULL, 'generic-http', 'Generic HTTP Webhook', 'System generic outbound webhook for pipeline webhook stages.', 'api', 'generic', 'v1',
417
+ '{"outbound_adapter":"adapters/generic-webhook-outbound"}',
418
+ '{"api_token":{"source":"value","value":""}}',
419
+ true, true, true, 'system'
420
+ )
421
+ ON CONFLICT (app_id, account_id, slug) DO NOTHING;