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.
- package/.env.example +13 -3
- package/.framework/cli/commands/bootstrap.ts +392 -0
- package/.framework/cli/commands/dev.ts +91 -218
- package/.framework/cli/commands/doctor.ts +132 -26
- package/.framework/cli/commands/generate.ts +38 -298
- package/.framework/cli/commands/init.ts +20 -1
- package/.framework/cli/commands/install-app.ts +183 -13
- package/.framework/cli/commands/migrate.ts +36 -30
- package/.framework/cli/commands/migrations.ts +16 -56
- package/.framework/cli/commands/upgrade.ts +35 -0
- package/.framework/cli/commands/validate-app.ts +127 -1
- package/.framework/cli/commands/validate-schema.ts +147 -0
- package/.framework/cli/context.ts +223 -110
- package/.framework/cli/index.ts +6 -0
- package/.framework/cli/lib/project-files.ts +241 -1
- package/.framework/functions/_shared/app-manifest.ts +2 -0
- package/.framework/functions/_shared/hash-api-key.ts +183 -79
- package/.framework/functions/_shared/logging.ts +562 -224
- package/.framework/functions/_shared/middleware.ts +47 -44
- package/.framework/functions/_shared/permissions.ts +4 -0
- package/.framework/functions/admin-data.ts +51 -28
- package/.framework/functions/ai-agents.ts +10 -6
- package/.framework/functions/api-keys.ts +301 -122
- package/.framework/functions/apps.ts +63 -29
- package/.framework/functions/cil-ingest.ts +48 -15
- package/.framework/functions/debug-auth.ts +14 -8
- package/.framework/functions/deliveries.ts +39 -12
- package/.framework/functions/embeddings.ts +149 -78
- package/.framework/functions/integration-outbound.ts +67 -27
- package/.framework/functions/integrations.ts +254 -127
- package/.framework/functions/logs.ts +273 -133
- package/.framework/functions/observability.ts +278 -148
- package/.framework/functions/pipeline-executions.ts +1 -1
- package/.framework/functions/pipelines.ts +14 -9
- package/.framework/functions/prompt-configs.ts +7 -4
- package/.framework/functions/roles.ts +8 -5
- package/.framework/functions/security.ts +30 -17
- package/.framework/functions/system-cron.ts +240 -127
- package/.framework/functions/tests.ts +7 -6
- package/.framework/functions/timers.ts +310 -107
- package/.framework/functions/triggers.ts +28 -13
- package/.framework/functions/types.ts +13 -10
- package/.framework/migrations/069_log_stats_window.sql +54 -0
- package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
- package/.framework/migrations/071_timer_interval_keys.sql +96 -0
- package/.framework/migrations/072_slug_autofill.sql +77 -0
- package/.framework/migrations/073_seed_member_roles.sql +26 -0
- package/.framework/migrations/074_app_route_prefix_domains.sql +168 -0
- package/.framework/migrations/075_security_definer_grants.sql +157 -0
- package/.framework/src/apps/admin/index.tsx +1141 -775
- package/.framework/src/components/ErrorBoundary.tsx +136 -0
- package/.framework/src/components/admin/AdminListPage.tsx +81 -73
- package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
- package/.framework/src/components/admin/EntitySelect.tsx +181 -0
- package/.framework/src/components/admin/PageInstructions.tsx +86 -127
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
- package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
- package/.framework/src/components/layout/Sidebar.tsx +300 -177
- package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
- package/.framework/src/components/runtime/DataHeader.tsx +96 -48
- package/.framework/src/components/runtime/DataListPage.tsx +3 -26
- package/.framework/src/components/runtime/DataStats.tsx +10 -10
- package/.framework/src/components/runtime/DataTable.tsx +12 -10
- package/.framework/src/components/ui/sheet.tsx +24 -26
- package/.framework/src/components/ui/textarea.tsx +74 -48
- package/.framework/src/contexts/AppContext.tsx +5 -12
- package/.framework/src/contexts/AuthContext.tsx +17 -9
- package/.framework/src/hooks/useApps.ts +18 -22
- package/.framework/src/hooks/useEntityList.ts +12 -9
- package/.framework/src/hooks/useListSchema.ts +108 -58
- package/.framework/src/instructions/README.md +74 -0
- package/.framework/src/instructions/accounts.md +97 -0
- package/.framework/src/instructions/ai-agents.md +69 -0
- package/.framework/src/instructions/alerts.md +80 -0
- package/.framework/src/instructions/api-keys.md +87 -0
- package/.framework/src/instructions/apps.md +77 -0
- package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
- package/.framework/src/instructions/concepts/apps-and-renderers.md +228 -0
- package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
- package/.framework/src/instructions/concepts/automation.md +186 -0
- package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
- package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
- package/.framework/src/instructions/concepts/design-schema.md +152 -0
- package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
- package/.framework/src/instructions/concepts/observability.md +116 -0
- package/.framework/src/instructions/concepts/permissions.md +150 -0
- package/.framework/src/instructions/concepts/runtime-records.md +111 -0
- package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
- package/.framework/src/instructions/concepts/spine-way.md +172 -0
- package/.framework/src/instructions/deliveries.md +59 -0
- package/.framework/src/instructions/guide/00-orientation.md +106 -0
- package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
- package/.framework/src/instructions/guide/02-project-map.md +147 -0
- package/.framework/src/instructions/guide/03-domain-model.md +223 -0
- package/.framework/src/instructions/guide/04-first-app.md +227 -0
- package/.framework/src/instructions/guide/05-glossary.md +183 -0
- package/.framework/src/instructions/integrations.md +96 -0
- package/.framework/src/instructions/internal/cil-markers.md +83 -0
- package/.framework/src/instructions/internal/docs-contract.md +158 -0
- package/.framework/src/instructions/invites.md +60 -0
- package/.framework/src/instructions/kb.md +80 -0
- package/.framework/src/instructions/logs.md +77 -0
- package/.framework/src/instructions/notifications.md +77 -0
- package/.framework/src/instructions/observability.md +61 -0
- package/.framework/src/instructions/operations/deployment.md +115 -0
- package/.framework/src/instructions/operations/migrations.md +125 -0
- package/.framework/src/instructions/operations/security-checklist.md +170 -0
- package/.framework/src/instructions/operations/troubleshooting.md +170 -0
- package/.framework/src/instructions/operations/upgrade.md +116 -0
- package/.framework/src/instructions/people.md +91 -0
- package/.framework/src/instructions/pipeline-executions.md +62 -0
- package/.framework/src/instructions/pipelines.md +78 -0
- package/.framework/src/instructions/prompts.md +95 -0
- package/.framework/src/instructions/reference/api/admin-data.md +162 -0
- package/.framework/src/instructions/reference/api/auth.md +113 -0
- package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
- package/.framework/src/instructions/reference/app-manifest.md +184 -0
- package/.framework/src/instructions/reference/cli.md +124 -0
- package/.framework/src/instructions/reference/database.md +132 -0
- package/.framework/src/instructions/reference/design-schema.md +280 -0
- package/.framework/src/instructions/reference/env-vars.md +133 -0
- package/.framework/src/instructions/reference/frontend-sdk.md +207 -0
- package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
- package/.framework/src/instructions/reference/functions/admin-data.md +197 -0
- package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
- package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
- package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
- package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
- package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
- package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
- package/.framework/src/instructions/reference/functions/apps.md +140 -0
- package/.framework/src/instructions/reference/functions/auth.md +99 -0
- package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
- package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
- package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
- package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
- package/.framework/src/instructions/reference/functions/index.md +103 -0
- package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
- package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
- package/.framework/src/instructions/reference/functions/integrations.md +130 -0
- package/.framework/src/instructions/reference/functions/invites.md +182 -0
- package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
- package/.framework/src/instructions/reference/functions/kb.md +166 -0
- package/.framework/src/instructions/reference/functions/logs.md +141 -0
- package/.framework/src/instructions/reference/functions/observability.md +105 -0
- package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
- package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
- package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
- package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
- package/.framework/src/instructions/reference/functions/roles.md +121 -0
- package/.framework/src/instructions/reference/functions/security.md +140 -0
- package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
- package/.framework/src/instructions/reference/functions/system.md +106 -0
- package/.framework/src/instructions/reference/functions/tests.md +97 -0
- package/.framework/src/instructions/reference/functions/timers.md +117 -0
- package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
- package/.framework/src/instructions/reference/functions/triggers.md +140 -0
- package/.framework/src/instructions/reference/functions/types.md +146 -0
- package/.framework/src/instructions/reference/seeds.md +126 -0
- package/.framework/src/instructions/reference/shared-modules.md +127 -0
- package/.framework/src/instructions/reference/spine-config.md +114 -0
- package/.framework/src/instructions/roles.md +80 -0
- package/.framework/src/instructions/runtime-collaboration.md +106 -0
- package/.framework/src/instructions/runtime-detail.md +70 -0
- package/.framework/src/instructions/runtime-list.md +77 -0
- package/.framework/src/instructions/security.md +67 -0
- package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
- package/.framework/src/instructions/tasks/add-a-role.md +96 -0
- package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
- package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
- package/.framework/src/instructions/tasks/add-a-type.md +151 -0
- package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
- package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
- package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
- package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
- package/.framework/src/instructions/tasks/document-your-app.md +117 -0
- package/.framework/src/instructions/tasks/package-and-install-an-app.md +136 -0
- package/.framework/src/instructions/tasks/register-an-app.md +137 -0
- package/.framework/src/instructions/tasks/test-your-code.md +108 -0
- package/.framework/src/instructions/tasks/write-a-function.md +132 -0
- package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
- package/.framework/src/instructions/testing.md +59 -0
- package/.framework/src/instructions/timers.md +84 -0
- package/.framework/src/instructions/triggers.md +69 -0
- package/.framework/src/instructions/types.md +93 -0
- package/.framework/src/lib/app-mount.ts +88 -0
- package/.framework/src/pages/NotFoundPage.tsx +62 -31
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
- package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
- package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
- package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
- package/.framework/src/pages/admin/AppsPage.tsx +104 -66
- package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
- package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
- package/.framework/src/pages/admin/LogsPage.tsx +144 -76
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
- package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
- package/.framework/src/pages/admin/RolesPage.tsx +86 -43
- package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
- package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
- package/.framework/src/pages/admin/TimersPage.tsx +90 -62
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
- package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
- package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
- package/.framework/src/pages/admin/TypesPage.tsx +90 -48
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
- package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
- package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
- package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
- package/.framework/src/pages/auth/LoginPage.tsx +3 -2
- package/.framework/src/pages/auth/RegisterPage.tsx +16 -8
- package/.framework/templates/agent/AGENTS.md +167 -0
- package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
- package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
- package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
- package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
- package/.framework/templates/agent/skills/spine-install-app/SKILL.md +79 -0
- package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
- package/.framework/templates/agent/skills/spine-new-app/SKILL.md +79 -0
- package/.framework/templates/agent/skills/spine-new-function/SKILL.md +71 -0
- package/.framework/templates/agent/skills/spine-new-type/SKILL.md +72 -0
- package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
- package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
- package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
- package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
- package/.framework/templates/project.json +4 -1
- package/.framework/tests/unit/account-scoping-gates.test.ts +394 -0
- package/.framework/tests/unit/agent-files.test.ts +355 -0
- package/.framework/tests/unit/agent-runner.test.ts +479 -44
- package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
- package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
- package/.framework/tests/unit/app-mount.test.ts +80 -0
- package/.framework/tests/unit/bootstrap.test.ts +242 -0
- package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
- package/.framework/tests/unit/debug-auth.test.ts +38 -0
- package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
- package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
- package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
- package/.framework/tests/unit/logging-app-id.test.ts +75 -0
- package/.framework/tests/unit/security-definer-grants.test.ts +154 -0
- package/.framework/tests/unit/system-context-denial.test.ts +145 -0
- package/.framework/tests/unit/system-cron.test.ts +240 -0
- package/.framework/tests/unit/timers.test.ts +159 -0
- package/README.md +125 -166
- package/config/tsconfig.cli.json +2 -2
- package/package.json +15 -4
- package/templates/project/package-lock.json +2 -2
- package/.framework/docs/admin-routes.md +0 -76
- package/.framework/docs/api-docs-progress.md +0 -38
- package/.framework/docs/api-governance.md +0 -146
- package/.framework/docs/api-testing-results.md +0 -212
- package/.framework/docs/assembly-launch-guide.md +0 -138
- package/.framework/docs/audit-results.md +0 -590
- package/.framework/docs/db-api-inventory.md +0 -95
- package/.framework/docs/gap-remediation-backlog.md +0 -103
- package/.framework/docs/ui-adoption-verification.md +0 -111
- package/.framework/docs/ui-api-coverage.md +0 -84
- package/.framework/docs/v2-compatibility-audit.md +0 -228
- package/.framework/mcp/index.ts +0 -133
- package/.framework/mcp/load-env.ts +0 -60
- package/.framework/mcp/shared/app-manifest.ts +0 -275
- package/.framework/mcp/shared/db.ts +0 -477
- package/.framework/mcp/shared/kb.ts +0 -118
- package/.framework/mcp/tools/architect.ts +0 -431
- package/.framework/mcp/tools/cil/context.ts +0 -345
- package/.framework/mcp/tools/cil/graph.ts +0 -242
- package/.framework/mcp/tools/cil/ingest.ts +0 -1217
- package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
- package/.framework/mcp/tools/cil/pipeline.ts +0 -767
- package/.framework/mcp/tools/cil/project.ts +0 -791
- package/.framework/mcp/tools/cil/retrieval.ts +0 -336
- package/.framework/mcp/tools/cil/search-core.ts +0 -454
- package/.framework/mcp/tools/cil/search.ts +0 -97
- package/.framework/mcp/tools/cil/suggest.ts +0 -186
- package/.framework/mcp/tools/cil/validate.ts +0 -1369
- package/.framework/mcp/tools/kb/delete.ts +0 -139
- package/.framework/mcp/tools/kb/index.ts +0 -52
- package/.framework/mcp/tools/kb/ingest.ts +0 -84
- package/.framework/mcp/tools/kb/list-types.ts +0 -102
- package/.framework/mcp/tools/kb/publish.ts +0 -100
- package/.framework/mcp/tools/kb/reindex.ts +0 -86
- package/.framework/mcp/tools/kb/revoke.ts +0 -85
- package/.framework/mcp/tools/kb/search.ts +0 -101
- package/.framework/mcp/tools/kb/upsert.ts +0 -125
- 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.
|