spine-framework 0.4.4 → 0.5.0-rc.5

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 (305) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/install-app.ts +183 -13
  8. package/.framework/cli/commands/migrate.ts +36 -30
  9. package/.framework/cli/commands/migrations.ts +16 -56
  10. package/.framework/cli/commands/upgrade.ts +35 -0
  11. package/.framework/cli/commands/validate-app.ts +127 -1
  12. package/.framework/cli/commands/validate-schema.ts +147 -0
  13. package/.framework/cli/context.ts +223 -110
  14. package/.framework/cli/index.ts +6 -0
  15. package/.framework/cli/lib/project-files.ts +241 -1
  16. package/.framework/functions/_shared/app-manifest.ts +2 -0
  17. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  18. package/.framework/functions/_shared/logging.ts +562 -224
  19. package/.framework/functions/_shared/middleware.ts +47 -44
  20. package/.framework/functions/_shared/permissions.ts +4 -0
  21. package/.framework/functions/admin-data.ts +51 -28
  22. package/.framework/functions/ai-agents.ts +10 -6
  23. package/.framework/functions/api-keys.ts +301 -122
  24. package/.framework/functions/apps.ts +63 -29
  25. package/.framework/functions/cil-ingest.ts +48 -15
  26. package/.framework/functions/debug-auth.ts +14 -8
  27. package/.framework/functions/deliveries.ts +39 -12
  28. package/.framework/functions/embeddings.ts +149 -78
  29. package/.framework/functions/integration-outbound.ts +67 -27
  30. package/.framework/functions/integrations.ts +254 -127
  31. package/.framework/functions/logs.ts +273 -133
  32. package/.framework/functions/observability.ts +278 -148
  33. package/.framework/functions/pipeline-executions.ts +1 -1
  34. package/.framework/functions/pipelines.ts +14 -9
  35. package/.framework/functions/prompt-configs.ts +7 -4
  36. package/.framework/functions/roles.ts +8 -5
  37. package/.framework/functions/security.ts +30 -17
  38. package/.framework/functions/system-cron.ts +240 -127
  39. package/.framework/functions/tests.ts +7 -6
  40. package/.framework/functions/timers.ts +310 -107
  41. package/.framework/functions/triggers.ts +28 -13
  42. package/.framework/functions/types.ts +13 -10
  43. package/.framework/migrations/069_log_stats_window.sql +54 -0
  44. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  45. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  46. package/.framework/migrations/072_slug_autofill.sql +77 -0
  47. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  48. package/.framework/migrations/074_app_route_prefix_domains.sql +168 -0
  49. package/.framework/migrations/075_security_definer_grants.sql +157 -0
  50. package/.framework/src/apps/admin/index.tsx +1141 -775
  51. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  52. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  53. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  54. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  55. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  56. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  57. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  58. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  59. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  60. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  61. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  62. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  63. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  64. package/.framework/src/components/ui/sheet.tsx +24 -26
  65. package/.framework/src/components/ui/textarea.tsx +74 -48
  66. package/.framework/src/contexts/AppContext.tsx +5 -12
  67. package/.framework/src/contexts/AuthContext.tsx +17 -9
  68. package/.framework/src/hooks/useApps.ts +18 -22
  69. package/.framework/src/hooks/useEntityList.ts +12 -9
  70. package/.framework/src/hooks/useListSchema.ts +108 -58
  71. package/.framework/src/instructions/README.md +74 -0
  72. package/.framework/src/instructions/accounts.md +97 -0
  73. package/.framework/src/instructions/ai-agents.md +69 -0
  74. package/.framework/src/instructions/alerts.md +80 -0
  75. package/.framework/src/instructions/api-keys.md +87 -0
  76. package/.framework/src/instructions/apps.md +77 -0
  77. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  78. package/.framework/src/instructions/concepts/apps-and-renderers.md +228 -0
  79. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  80. package/.framework/src/instructions/concepts/automation.md +186 -0
  81. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  82. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  83. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  84. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  85. package/.framework/src/instructions/concepts/observability.md +116 -0
  86. package/.framework/src/instructions/concepts/permissions.md +150 -0
  87. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  88. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  89. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  90. package/.framework/src/instructions/deliveries.md +59 -0
  91. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  92. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  93. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  94. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  95. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  96. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  97. package/.framework/src/instructions/integrations.md +96 -0
  98. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  99. package/.framework/src/instructions/internal/docs-contract.md +158 -0
  100. package/.framework/src/instructions/invites.md +60 -0
  101. package/.framework/src/instructions/kb.md +80 -0
  102. package/.framework/src/instructions/logs.md +77 -0
  103. package/.framework/src/instructions/notifications.md +77 -0
  104. package/.framework/src/instructions/observability.md +61 -0
  105. package/.framework/src/instructions/operations/deployment.md +115 -0
  106. package/.framework/src/instructions/operations/migrations.md +125 -0
  107. package/.framework/src/instructions/operations/security-checklist.md +170 -0
  108. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  109. package/.framework/src/instructions/operations/upgrade.md +116 -0
  110. package/.framework/src/instructions/people.md +91 -0
  111. package/.framework/src/instructions/pipeline-executions.md +62 -0
  112. package/.framework/src/instructions/pipelines.md +78 -0
  113. package/.framework/src/instructions/prompts.md +95 -0
  114. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  115. package/.framework/src/instructions/reference/api/auth.md +113 -0
  116. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  117. package/.framework/src/instructions/reference/app-manifest.md +184 -0
  118. package/.framework/src/instructions/reference/cli.md +124 -0
  119. package/.framework/src/instructions/reference/database.md +132 -0
  120. package/.framework/src/instructions/reference/design-schema.md +280 -0
  121. package/.framework/src/instructions/reference/env-vars.md +133 -0
  122. package/.framework/src/instructions/reference/frontend-sdk.md +207 -0
  123. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  124. package/.framework/src/instructions/reference/functions/admin-data.md +197 -0
  125. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  126. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  127. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  128. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  129. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  130. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  131. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  132. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  133. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  134. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  135. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  136. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  137. package/.framework/src/instructions/reference/functions/index.md +103 -0
  138. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  139. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  140. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  141. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  142. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  143. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  144. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  145. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  146. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  147. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  148. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  149. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  150. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  151. package/.framework/src/instructions/reference/functions/security.md +140 -0
  152. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  153. package/.framework/src/instructions/reference/functions/system.md +106 -0
  154. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  155. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  156. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  157. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  158. package/.framework/src/instructions/reference/functions/types.md +146 -0
  159. package/.framework/src/instructions/reference/seeds.md +126 -0
  160. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  161. package/.framework/src/instructions/reference/spine-config.md +114 -0
  162. package/.framework/src/instructions/roles.md +80 -0
  163. package/.framework/src/instructions/runtime-collaboration.md +106 -0
  164. package/.framework/src/instructions/runtime-detail.md +70 -0
  165. package/.framework/src/instructions/runtime-list.md +77 -0
  166. package/.framework/src/instructions/security.md +67 -0
  167. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  168. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  169. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  170. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  171. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  172. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  173. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  174. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  175. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  176. package/.framework/src/instructions/tasks/document-your-app.md +117 -0
  177. package/.framework/src/instructions/tasks/package-and-install-an-app.md +136 -0
  178. package/.framework/src/instructions/tasks/register-an-app.md +137 -0
  179. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  180. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  181. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  182. package/.framework/src/instructions/testing.md +59 -0
  183. package/.framework/src/instructions/timers.md +84 -0
  184. package/.framework/src/instructions/triggers.md +69 -0
  185. package/.framework/src/instructions/types.md +93 -0
  186. package/.framework/src/lib/app-mount.ts +88 -0
  187. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  188. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  189. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  190. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  191. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  192. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  193. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  194. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  195. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  196. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  197. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  198. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  199. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  200. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  201. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  202. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  203. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  204. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  205. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  206. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  207. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  208. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  209. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  210. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  211. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  212. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  213. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  214. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  215. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  216. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  217. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  218. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  219. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  220. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  221. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  222. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  223. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  224. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  225. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  226. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  227. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  228. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  229. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  230. package/.framework/src/pages/auth/LoginPage.tsx +3 -2
  231. package/.framework/src/pages/auth/RegisterPage.tsx +16 -8
  232. package/.framework/templates/agent/AGENTS.md +167 -0
  233. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  234. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  235. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  236. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  237. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +79 -0
  238. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  239. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +79 -0
  240. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +71 -0
  241. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +72 -0
  242. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  243. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  244. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  245. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  246. package/.framework/templates/project.json +4 -1
  247. package/.framework/tests/unit/account-scoping-gates.test.ts +394 -0
  248. package/.framework/tests/unit/agent-files.test.ts +355 -0
  249. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  250. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  251. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  252. package/.framework/tests/unit/app-mount.test.ts +80 -0
  253. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  254. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  255. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  256. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  257. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  258. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  259. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  260. package/.framework/tests/unit/security-definer-grants.test.ts +154 -0
  261. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  262. package/.framework/tests/unit/system-cron.test.ts +240 -0
  263. package/.framework/tests/unit/timers.test.ts +159 -0
  264. package/README.md +125 -166
  265. package/config/tsconfig.cli.json +2 -2
  266. package/package.json +15 -4
  267. package/templates/project/package-lock.json +2 -2
  268. package/.framework/docs/admin-routes.md +0 -76
  269. package/.framework/docs/api-docs-progress.md +0 -38
  270. package/.framework/docs/api-governance.md +0 -146
  271. package/.framework/docs/api-testing-results.md +0 -212
  272. package/.framework/docs/assembly-launch-guide.md +0 -138
  273. package/.framework/docs/audit-results.md +0 -590
  274. package/.framework/docs/db-api-inventory.md +0 -95
  275. package/.framework/docs/gap-remediation-backlog.md +0 -103
  276. package/.framework/docs/ui-adoption-verification.md +0 -111
  277. package/.framework/docs/ui-api-coverage.md +0 -84
  278. package/.framework/docs/v2-compatibility-audit.md +0 -228
  279. package/.framework/mcp/index.ts +0 -133
  280. package/.framework/mcp/load-env.ts +0 -60
  281. package/.framework/mcp/shared/app-manifest.ts +0 -275
  282. package/.framework/mcp/shared/db.ts +0 -477
  283. package/.framework/mcp/shared/kb.ts +0 -118
  284. package/.framework/mcp/tools/architect.ts +0 -431
  285. package/.framework/mcp/tools/cil/context.ts +0 -345
  286. package/.framework/mcp/tools/cil/graph.ts +0 -242
  287. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  288. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  289. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  290. package/.framework/mcp/tools/cil/project.ts +0 -791
  291. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  292. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  293. package/.framework/mcp/tools/cil/search.ts +0 -97
  294. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  295. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  296. package/.framework/mcp/tools/kb/delete.ts +0 -139
  297. package/.framework/mcp/tools/kb/index.ts +0 -52
  298. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  299. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  300. package/.framework/mcp/tools/kb/publish.ts +0 -100
  301. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  302. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  303. package/.framework/mcp/tools/kb/search.ts +0 -101
  304. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  305. package/.framework/mcp/tools/observability.ts +0 -510
@@ -0,0 +1,112 @@
1
+ ---
2
+ title: Scope and Accounts
3
+ audience: developers, agents
4
+ kind: concept
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-29
7
+ source_files:
8
+ - .framework/migrations/001_core_schema.sql
9
+ - .framework/migrations/002_core_rls_and_functions.sql
10
+ - .framework/migrations/011_spine_system_account.sql
11
+ - .framework/migrations/013_get_account_apps_role_filter.sql
12
+ - .framework/migrations/015_types_kind_slug_unique.sql
13
+ - .framework/functions/admin-data.ts
14
+ - .framework/functions/apps.ts
15
+ - .framework/functions/_shared/principal.ts
16
+ - .framework/functions/_shared/db.ts
17
+ ---
18
+
19
+ # Scope and Accounts
20
+
21
+ Accounts are Spine's tenancy primitive: every runtime record belongs to
22
+ exactly one `account_id`, and that column is what both RLS and the app layer
23
+ use to partition tenants. `design_schema.scope` is the small lever that decides
24
+ *which* account a record belongs to.
25
+
26
+ ## The tenancy model
27
+
28
+ - **`public.accounts`** — the tenant (organization, workspace, customer).
29
+ Accounts form a hierarchy through `parent_id`; the `account_paths` closure
30
+ table stores every ancestor→descendant pair so subtree lookups are one join.
31
+ Accounts have no `account_id` of their own — the table is the source of
32
+ truth.
33
+ - **`public.people`** — a person belongs to exactly one account
34
+ (`people.account_id NOT NULL`) and holds one `role_id`. A person is *also* a
35
+ runtime record: `type_id`, `data`, and a stamped `design_schema`.
36
+ - **Everything else** — `items`, `threads`, `messages`, `links`,
37
+ `attachments`, `watchers`, `item_progress` — carries
38
+ `account_id NOT NULL` (or via its parent thread for `messages`).
39
+
40
+ ## How scope decides `account_id`
41
+
42
+ `admin-data` create resolves the record's account in order
43
+ (`.framework/functions/admin-data.ts`, `create`):
44
+
45
+ 1. An explicit `account_id` in the request body, else the caller's
46
+ `ctx.accountId`.
47
+ 2. If the record references a parent (`thread_id`, `target_id`, `parent_id`),
48
+ the **parent's** `account_id` wins — and the parent's stamped `scope` is
49
+ inherited into the new record's `design_schema`. A child can never drift
50
+ into a different tenant than its parent.
51
+ 3. `design_schema.scope` then applies: `'account'` (the default) keeps the
52
+ resolved account; `'platform'` replaces it with the **spine-system**
53
+ account's id.
54
+
55
+ So `scope` on a type is really "which tenant owns these records": your
56
+ account's rows, or the platform's shared rows.
57
+
58
+ ## The `spine-system` account
59
+
60
+ Seeded by `.framework/migrations/011_spine_system_account.sql`:
61
+ `accounts.slug = 'spine-system'` — "Master system account for internal Spine
62
+ operations." It is the landing account for `scope: 'platform'` records. The
63
+ `accounts` table itself is the exception to the scoping rule: it has no
64
+ `account_id` column for scope to land on, so for `accounts` records
65
+ `admin-data` instead sets `parent_id` to the creator's account when none is
66
+ given — new accounts are born as *children* of the account that created them.
67
+
68
+ ## How scope affects queries
69
+
70
+ - **Human callers** query through `ctx.db` — a Supabase client created with the
71
+ caller's JWT (`.framework/functions/_shared/principal.ts`,
72
+ `getPrincipalDb`). RLS policies on the tenant tables filter rows to
73
+ `account_id IN (SELECT get_accessible_accounts(current_actor_id()))`
74
+ (`.framework/migrations/002_core_rls_and_functions.sql`).
75
+ `current_actor_id()` maps `auth.uid()` to the `people` row;
76
+ `get_accessible_accounts` returns that person's account **plus every
77
+ descendant** via `account_paths` — a parent-account user sees the whole
78
+ subtree. If the person holds `system_admin`, the function short-circuits and
79
+ returns *all* accounts.
80
+ - **Machine callers** (API keys) use `adminDb`, which bypasses RLS; tenancy is
81
+ enforced only by the key's `account_id` and `scopes` — see
82
+ [Permissions](permissions.md). A `*:*` key reads every tenant.
83
+ - **Platform-scoped rows** carry the `spine-system` `account_id`, so under
84
+ account-based RLS they are visible to the spine-system account subtree and
85
+ to `system_admin` (who sees all accounts) — not to ordinary tenant users
86
+ querying through `ctx.db`. Machine principals on `adminDb` reach them
87
+ regardless, subject to key scopes.
88
+
89
+ ## What is *not* scoped by account
90
+
91
+ - **Types are global.** `public.types` uniqueness is `(kind, slug)`
92
+ (`.framework/migrations/015_types_kind_slug_unique.sql`) — deliberately not
93
+ per-app or per-account, so `resolveTypeRecord(kind, slug)` `.single()`
94
+ lookups stay deterministic and every account shares the same type registry.
95
+ - **Apps are global** rows in `public.apps`, linked to accounts only through
96
+ `owner_account_id` and the `get_account_apps` RPC, which filters by the
97
+ caller's role slugs (`.framework/functions/apps.ts`;
98
+ `.framework/migrations/013_get_account_apps_role_filter.sql`).
99
+ - **Roles** are global slugs matched verbatim by the permission engine.
100
+
101
+ ## Practical consequences
102
+
103
+ - Put `scope: 'platform'` only on types whose records should exist once for the
104
+ whole installation (system config, shared registries) — never on tenant
105
+ data.
106
+ - Child records inherit the parent's account and scope; you cannot re-tenant a
107
+ record by pointing it at a parent in another account — the parent's account
108
+ wins, silently.
109
+ - Because types are global, pick type slugs as if they were API names:
110
+ `kind + slug` must be unique across every app installed in the deployment.
111
+ - Account-scoped tests and seeds must set `account_id` on every record or RLS
112
+ will make them invisible to human-scoped queries.
@@ -0,0 +1,172 @@
1
+ ---
2
+ title: The Spine Way
3
+ audience: developers, agents
4
+ kind: concept
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-29
7
+ source_files:
8
+ - scripts/boundary-check.sh
9
+ - config/vite.config.ts
10
+ - config/tsconfig.json
11
+ - .framework/functions/admin-data.ts
12
+ - .framework/functions/_shared/permissions.ts
13
+ - .framework/functions/_shared/principal.ts
14
+ - .framework/functions/_shared/db.ts
15
+ - .framework/cli/commands/migrate.ts
16
+ - .framework/cli/commands/upgrade.ts
17
+ - .framework/migrations/001_core_schema.sql
18
+ - .framework/migrations/002_core_rls_and_functions.sql
19
+ - .framework/migrations/011_spine_system_account.sql
20
+ - .framework/src/hooks/useEntityRecord.ts
21
+ - .framework/src/components/app-shell/GenericDetailPage.tsx
22
+ ---
23
+
24
+ # The Spine Way
25
+
26
+ Ten rules every app, function, migration, and type must satisfy to stay aligned
27
+ with the framework. Each rule is stated as a quotable invariant, followed by
28
+ why it exists and what actually breaks when you violate it. Deeper treatment of
29
+ each topic lives in the sibling concept pages.
30
+
31
+ ## 1. Core never imports from custom
32
+
33
+ `.framework/` must not import from `custom/`, `custom_*` modules, or hardcode
34
+ custom app slugs.
35
+
36
+ **Why:** `.framework/` is a sealed, upgradeable npm package — it must run
37
+ identically in every project.
38
+
39
+ **Breaks:** `scripts/boundary-check.sh` fails the build (checks 1–3), and the
40
+ next `upgrade` either aborts on locally modified framework files or silently
41
+ overwrites the coupling.
42
+
43
+ ## 2. Custom code imports core through `@core/*`, never relative paths
44
+
45
+ Custom frontend code uses `@core/components/...`, `@core/hooks/...`; custom
46
+ functions import `./_shared/...` after assembly (`@shared/*` in
47
+ `config/tsconfig.functions.json`).
48
+
49
+ **Why:** `@core` maps to `.framework/src` in `config/tsconfig.json` and to the
50
+ assembled tree in `config/vite.config.ts` — the two roots custom code is
51
+ actually built against.
52
+
53
+ **Breaks:** `scripts/boundary-check.sh` check 2b flags relative `../.framework`
54
+ imports in `custom/`, and paths that resolve today break the moment the
55
+ assembly layout changes.
56
+
57
+ ## 3. Apps are registered data, not static imports
58
+
59
+ An app is a `manifest.json` plus a row in `public.apps`; the shell mounts it at
60
+ runtime by `route_prefix` and `renderer`.
61
+
62
+ **Why:** registration is what makes an app discoverable, permissionable
63
+ (`min_role` / `required_roles`), and toggleable (`is_active`) without a core
64
+ redeploy.
65
+
66
+ **Breaks:** statically importing an app component into `.framework/src/`
67
+ violates rule 1 and bypasses the role gate in
68
+ `.framework/src/components/AppWrapper.tsx` — the app is always visible and
69
+ always mounted.
70
+
71
+ ## 4. Runtime record CRUD goes through `/api/admin-data`
72
+
73
+ All creates, reads, updates, and deletes of `items`, `threads`, `messages`,
74
+ `links`, `attachments`, `watchers`, `people`, `accounts` go through the single
75
+ `admin-data` endpoint.
76
+
77
+ **Why:** that endpoint is where type resolution, `design_schema` stamping,
78
+ permission evaluation, audit logging, and trigger dispatch actually live — see
79
+ `.framework/functions/admin-data.ts`.
80
+
81
+ **Breaks:** a custom function wrapper skips record permissions, field-level
82
+ write gates, `validation_schema` sanitization, audit rows, and create/update
83
+ triggers — the record lands in the table but nothing that should have run ran.
84
+
85
+ ## 5. Behavior lives in `design_schema`, not handler branches
86
+
87
+ Fields, views, record permissions, scope, and functionality bindings belong on
88
+ the type's `design_schema`; the runtime stamps a copy onto every record at
89
+ creation.
90
+
91
+ **Why:** the permission engine and generic renderers read the schema off the
92
+ record — `.framework/functions/_shared/permissions.ts` denies outright when a
93
+ record has no stamped `record_permissions`.
94
+
95
+ **Breaks:** hardcoded per-type branches can't be permissioned, can't render in
96
+ the generic UI, and drift from the stamped schema records already carry.
97
+
98
+ ## 6. `record_permissions` is the base grant; field permissions are overrides
99
+
100
+ Start with the most restrictive `record_permissions` per role. A field without
101
+ a `fields.<name>.permissions` entry inherits `read` from `canRead` and `write`
102
+ from `canUpdate`; only add a field-level entry to change that default.
103
+
104
+ **Why:** the merge in `resolveFirstSurfacePermissions` applies the override
105
+ verbatim — `["read"]` on a field removes `write` for that role even when the
106
+ record grant allows it.
107
+
108
+ **Breaks:** re-stating record-level grants per field silently locks fields, and
109
+ leaving `system: true` fields un-overridden lets any record-writer modify
110
+ columns like `status` or `slug`.
111
+
112
+ ## 7. RLS decides which rows you see; design_schema decides what you can do
113
+
114
+ Every tenant table has RLS enabled and policies scope rows through
115
+ `get_accessible_accounts(current_actor_id())`. Human requests query through
116
+ `ctx.db` (JWT-scoped); `adminDb` bypasses RLS and is reserved for service-role
117
+ work.
118
+
119
+ **Why:** this is the second, independent layer of authorization — RLS cannot
120
+ express per-type, per-role, per-field grants.
121
+
122
+ **Breaks:** a table without RLS leaks every tenant's rows to every caller; a
123
+ handler that uses `adminDb` "for convenience" turns your permission model into
124
+ decoration.
125
+
126
+ ## 8. Migrations are idempotent and ordered
127
+
128
+ Filenames are `NNN_description.sql`; every statement must be safe to re-run
129
+ (`CREATE ... IF NOT EXISTS`, `DROP POLICY IF EXISTS`, `ON CONFLICT DO NOTHING`,
130
+ guarded `DO $$` blocks). `migrate` applies `.framework/migrations` first, then
131
+ `custom/migrations`, each sorted by name.
132
+
133
+ **Why:** the same migration set runs against fresh and existing databases, and
134
+ later migrations legitimately depend on earlier objects.
135
+
136
+ **Breaks:** a non-idempotent migration fails on second run and wedges every
137
+ environment that already applied it; unordered migrations crash on missing
138
+ dependencies.
139
+
140
+ ## 9. `system: true` fields live on the record; everything else lives in `data`
141
+
142
+ Fields declared `system: true` read and write top-level record columns
143
+ (`record.title`); all other fields live inside `record.data.<field>`.
144
+
145
+ **Why:** the split is how the platform separates framework-owned columns from
146
+ app-defined data — `.framework/src/hooks/useEntityRecord.ts` splits form data
147
+ by `fieldDef.system` on every save, and
148
+ `.framework/src/components/app-shell/GenericDetailPage.tsx` reads the same way.
149
+
150
+ **Breaks:** sending a non-system field as a top-level key writes it outside the
151
+ field-permission gate's `data` object (invisible to renderers); sending a
152
+ system field inside `data` never reaches its column.
153
+
154
+ ## 10. Secrets and service keys stay on the backend
155
+
156
+ Browser code may use `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` only.
157
+ `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_DB_PASSWORD`, and app secrets appear
158
+ only in `.framework/functions/`, `.framework/cli/`, and uncommitted env files.
159
+
160
+ **Why:** `adminDb` is a service-role client — whoever holds the service key
161
+ holds an RLS bypass for the entire database.
162
+
163
+ **Breaks:** a service key bundled into frontend code is a credential leak with
164
+ full read/write on every tenant's data; committed env files leak it to every
165
+ clone of the repo.
166
+
167
+ ## Applying the rules
168
+
169
+ Before shipping a change, walk the list and check each rule that could apply.
170
+ When a rule genuinely must bend, prefer the weakest violation (data over code,
171
+ config over core) and document it — most "exceptions" turn out to be a missing
172
+ `design_schema` section or a missing app manifest entry.
@@ -0,0 +1,59 @@
1
+ ---
2
+ title: Deliveries
3
+ audience: both
4
+ kind: entity
5
+ verified_against: e13127d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/functions/deliveries.ts
9
+ - .framework/functions/integration-outbound.ts
10
+ - .framework/functions/_shared/retry-deliveries.ts
11
+ - .framework/src/pages/admin/DeliveriesPage.tsx
12
+ ---
13
+
14
+ ## What this is for
15
+
16
+ **Deliveries** is the outbound delivery log — every webhook/integration delivery attempt, its status, retries, and response. It is primarily a diagnostic, read-mostly page: use it to confirm an event left Spine, to debug a failing endpoint, and to see retry behavior.
17
+
18
+ ## Fields and settings
19
+
20
+ - **Direction** — `inbound` (external webhook into Spine) or `outbound` (Spine calling an integration).
21
+ - **Status** — `pending`, `processing`, `delivered`, or `failed`. Pending rows with a future `next_attempt_at` are scheduled retries.
22
+ - **Integration** — the `integration_id` the delivery ran through.
23
+ - **Handler / Action** — `handler_name` (inbound webhook handler) or `action_slug` that produced it.
24
+ - **Attempts** — `attempt_count / max_attempts`. `max_attempts` defaults to 3, overridable per call (`action_config.max_attempts`) or per integration (`config.retry_policy.max_attempts`).
25
+ - **Next Attempt / Created** — scheduled retry time and queue time. `response_status` and `last_error` on the row capture the last attempt's result.
26
+
27
+ **Downstream effects**
28
+
29
+ - A `failed` row means the endpoint rejected or timed out and `attempt_count` reached `max_attempts` — fix the endpoint or credentials, then retry via the API (`deliveries?action=retry`, outbound only) or re-fire the event.
30
+ - Retries reuse the same row: `attempt_count` increments and `next_attempt_at` follows exponential backoff (30s × 2^attempt, capped at 1h, +20% jitter). `system-cron` sweeps due `pending` rows each tick.
31
+ - Deliveries are produced by `integration-outbound` (outbound) and `integration-routes` (inbound) — an empty list with active webhooks usually means no events matched, not a broken delivery layer.
32
+ - Rows are append-only diagnostics; there is nothing to create or edit on this page.
33
+
34
+ ## Minimal configuration
35
+
36
+ N/A — deliveries are generated by outbound calls, not authored. To produce one: create an `integration-routes`/webhook integration (or a trigger with an outbound stage), then emit its event.
37
+
38
+ ## Full configuration
39
+
40
+ N/A — see `integrations` for endpoint/credential configuration, `triggers`/`pipelines` for what fires deliveries.
41
+
42
+ ## Example
43
+
44
+ A support app's `customer-webhooks` integration posts every `ticket.closed` event to the customer's endpoint; a `failed` delivery with response `401` points at an expired token — rotate it in the integration's `credentials`, not here.
45
+
46
+ ## Core files
47
+
48
+ - `.framework/functions/deliveries.ts` — API (list/get/`action=retry`)
49
+ - `.framework/functions/integration-outbound.ts` — outbound broker that writes delivery rows
50
+ - `.framework/functions/integration-routes.ts` — inbound webhook path that writes inbound rows
51
+ - `.framework/functions/_shared/retry-deliveries.ts` — scheduled sweep of due `pending` rows
52
+ - `.framework/src/pages/admin/DeliveriesPage.tsx` — admin UI
53
+ - Table: `public.webhook_deliveries`
54
+
55
+ ## Agent notes
56
+
57
+ - Debug order: delivery row → integration config/credentials → the event producer (trigger/pipeline). The delivery row is the *symptom*, not the cause.
58
+ - Repeated failures across one endpoint usually mean credentials or URL drift; failures across many endpoints point at the outbound broker or networking.
59
+ - Delivery volume doubles as an activity signal for integrations — a silent integration shows up here first.
@@ -0,0 +1,106 @@
1
+ ---
2
+ title: Orientation — what Spine Framework is
3
+ audience: developers, agents
4
+ kind: guide
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-29
7
+ source_files:
8
+ - package.json
9
+ - netlify.toml
10
+ - .env.example
11
+ - .framework/cli/commands/init.ts
12
+ - .framework/templates/project.json
13
+ - .framework/src/components/admin/PageInstructions.tsx
14
+ - .framework/src/instructions/README.md
15
+ ---
16
+
17
+ # Orientation
18
+
19
+ Spine Framework is a multi-tenant application platform you install into an npm
20
+ project. It gives you the "boring 80%" of a SaaS product — the infrastructure
21
+ every app needs and nobody wants to rebuild — so your code can be the
22
+ interesting 20%.
23
+
24
+ ## What you get out of the box
25
+
26
+ - **A typed runtime data layer.** Accounts, people, and typed records (items,
27
+ threads, messages, links, attachments, watchers) stored in Supabase Postgres,
28
+ all reachable through one CRUD/permissions API (`.framework/functions/admin-data.ts`).
29
+ - **Auth and tenancy.** Supabase Auth for sign-in, an invite/registration
30
+ pipeline (`.framework/functions/invites.ts`), hierarchical accounts, and a
31
+ first-user bootstrap that seeds a system administrator.
32
+ - **RBAC.** Roles plus per-type `record_permissions` evaluated on every request
33
+ (`.framework/functions/_shared/permissions.ts`).
34
+ - **Automation.** Declarative pipelines, event triggers, timers, integrations,
35
+ and AI agents — all database rows, all driven by the same runtime
36
+ (`.framework/functions/_shared/pipeline-runner.ts`,
37
+ `.framework/functions/_shared/trigger-engine.ts`).
38
+ - **An admin UI.** A schema-driven admin surface at `/spine-framework/admin`
39
+ built from `.framework/src/apps/admin/index.tsx`, plus generic list/detail
40
+ pages that render directly from each type's views.
41
+ - **Operations.** API keys for machine principals, delivery tracking, logs,
42
+ metrics, and pipeline execution history.
43
+
44
+ The stack is deliberately conventional: a React + Vite frontend, Netlify
45
+ Functions as the API layer, and Supabase (Postgres + Auth) as the database.
46
+ `netlify.toml` points functions at `.assembled/netlify/functions` and publishes
47
+ `dist`; `.env.example` lists the Supabase keys the app needs.
48
+
49
+ ## What `npm install spine-framework` + `npx spine-framework init` gave you
50
+
51
+ `init` copies a framework-owned file set — declared in
52
+ `.framework/templates/project.json` — into your project: the `.framework/`
53
+ tree (frontend source, Netlify functions, migrations, CLI, seeds, schemas),
54
+ `config/` build files, root `scripts/`, `bin/`, a neutral `spine.config.json`,
55
+ a merged `package.json`, `netlify.toml`, `.gitignore`, and a frozen
56
+ `.spine-manifest.json` recording the hash of every protected file. It also
57
+ creates an empty `custom/` workspace — the one place your code lives.
58
+
59
+ Two consequences follow:
60
+
61
+ 1. **`.framework/` (plus `config/` and `scripts/`) is sealed.** Every file is
62
+ hashed into `.spine-manifest.json`; `npx spine-framework upgrade` refuses to
63
+ overwrite a locally modified tree unless you pass `--force`.
64
+ 2. **`custom/` is yours.** Apps, functions, components, and migrations you
65
+ write go there; the framework never touches it.
66
+
67
+ See [02-project-map.md](./02-project-map.md) for the full anatomy.
68
+
69
+ ## How this instruction book is organized
70
+
71
+ This book ships inside the package at `.framework/src/instructions/` and is
72
+ also rendered inside the admin UI — admin pages mount a
73
+ `PageInstructions` sheet that loads these files as raw markdown and renders
74
+ them with `react-markdown` + `remark-gfm`
75
+ (`.framework/src/components/admin/PageInstructions.tsx`). Diagrams are plain
76
+ ASCII; the renderer does not load mermaid.
77
+
78
+ | Section | Kind | Contents |
79
+ |---|---|---|
80
+ | `guide/` | guide | End-to-end walkthroughs — you are here. |
81
+ | `concepts/` | concept | Mental models (tenancy, permissions, schema). |
82
+ | `tasks/` | task | Single-goal procedures with verification steps. |
83
+ | `reference/` | reference | Exhaustive lookups (env vars, CLI, endpoints). |
84
+ | `operations/` | ui | Admin-UI surfaces and operational runbooks. |
85
+ | `internal/` | mixed | Repo-only notes; exempt from shipped-doc rules. |
86
+ | book root | entity | One file per Spine entity — [types](../types.md), [apps](../apps.md), [roles](../roles.md), [pipelines](../pipelines.md), [triggers](../triggers.md), [timers](../timers.md), [integrations](../integrations.md), [ai-agents](../ai-agents.md), [prompts](../prompts.md), [api-keys](../api-keys.md), [deliveries](../deliveries.md). |
87
+
88
+ Entity files all use the same seven sections — *What this is for → Fields and
89
+ settings → Minimal configuration → Full configuration → Example → Core files →
90
+ Agent notes* — so once you have read one, you know the shape of all of them.
91
+
92
+ ## How to read it
93
+
94
+ - **Developers:** read this guide section in order
95
+ ([install](./01-install-and-first-run.md) →
96
+ [project map](./02-project-map.md) →
97
+ [domain model](./03-domain-model.md) →
98
+ [first app](./04-first-app.md)), then the entity file for whatever you are
99
+ building, then `reference/` for exact spellings.
100
+ - **Agents:** [03-domain-model.md](./03-domain-model.md) gives you the
101
+ primitives and how they compose; each entity file's *Agent notes* section
102
+ lists the mistakes that actually break things; [05-glossary.md](./05-glossary.md)
103
+ pins down terminology.
104
+ - Every page is verified against the code at the `verified_against` commit in
105
+ its frontmatter. Where the docs disagree with code, code wins — treat that as
106
+ a bug and check `Core files` on the relevant entity page.