spine-framework 0.4.3 → 0.5.0-rc.4
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/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-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/agent-runner.ts +1000 -81
- package/.framework/functions/_shared/cil.ts +2 -1
- package/.framework/functions/_shared/db.ts +3 -6
- package/.framework/functions/_shared/hash-api-key.ts +183 -79
- package/.framework/functions/_shared/kb.ts +61 -7
- package/.framework/functions/_shared/logging.ts +562 -224
- package/.framework/functions/_shared/message-sequence.ts +53 -0
- package/.framework/functions/_shared/middleware.ts +47 -44
- package/.framework/functions/_shared/pipeline-runner.ts +150 -37
- package/.framework/functions/_shared/principal.ts +9 -6
- package/.framework/functions/_shared/trigger-engine.ts +149 -40
- package/.framework/functions/admin-data.ts +48 -31
- package/.framework/functions/ai-agents.ts +103 -33
- package/.framework/functions/api-keys.ts +301 -122
- package/.framework/functions/apps.ts +43 -26
- 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 +145 -76
- 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 +277 -147
- package/.framework/functions/pipeline-executions.ts +1 -1
- package/.framework/functions/pipeline-runner-background.ts +120 -0
- 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 +250 -128
- package/.framework/functions/tests.ts +7 -6
- package/.framework/functions/timers.ts +310 -107
- package/.framework/functions/trigger-scheduler.ts +65 -5
- package/.framework/functions/triggers.ts +28 -13
- package/.framework/functions/types.ts +13 -10
- package/.framework/migrations/064_episode_leases.sql +196 -0
- package/.framework/migrations/065_execution_tables_updated_at.sql +20 -0
- package/.framework/migrations/066_episode_steal_thread_merge.sql +148 -0
- package/.framework/migrations/067_episode_lease_stale_steal.sql +93 -0
- package/.framework/migrations/068_cron_schedule_timer_rpcs.sql +251 -0
- 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/schemas/spine.config.schema.json +62 -0
- package/.framework/src/App.tsx +3 -1
- 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 +92 -81
- package/.framework/src/components/admin/EntitySelect.tsx +181 -0
- package/.framework/src/components/admin/PageInstructions.tsx +86 -127
- package/.framework/src/components/app-shell/GenericAppShell.tsx +3 -1
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
- package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
- package/.framework/src/components/auth/TurnstileWidget.tsx +9 -6
- package/.framework/src/components/kb/KBArticleEditor.tsx +49 -6
- package/.framework/src/components/layout/Layout.tsx +4 -2
- package/.framework/src/components/layout/Sidebar.tsx +304 -179
- 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/hooks/useBranding.ts +47 -0
- package/.framework/src/hooks/useEntityList.ts +12 -9
- package/.framework/src/hooks/useListSchema.ts +108 -58
- package/.framework/src/instructions/README.md +57 -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 +162 -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/invites.md +60 -0
- package/.framework/src/instructions/kb.md +80 -0
- package/.framework/src/instructions/logs.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 +148 -0
- package/.framework/src/instructions/operations/troubleshooting.md +170 -0
- package/.framework/src/instructions/operations/upgrade.md +116 -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 +150 -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/functions/account-nodes.md +75 -0
- package/.framework/src/instructions/reference/functions/admin-data.md +195 -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-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/package-and-install-an-app.md +127 -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 +82 -0
- package/.framework/src/instructions/triggers.md +69 -0
- package/.framework/src/instructions/types.md +93 -0
- package/.framework/src/lib/branding.ts +128 -0
- package/.framework/src/pages/NoAppPage.tsx +3 -1
- package/.framework/src/pages/NotFoundPage.tsx +62 -31
- package/.framework/src/pages/SetupPage.tsx +5 -2
- 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/AuthConfirmPage.tsx +3 -1
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +3 -1
- package/.framework/src/pages/auth/LoginPage.tsx +4 -2
- package/.framework/src/pages/auth/RegisterPage.tsx +3 -1
- package/.framework/templates/agent/AGENTS.md +150 -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 +72 -0
- package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
- package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
- package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
- package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -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 +5 -1
- package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
- package/.framework/tests/unit/agent-files.test.ts +355 -0
- package/.framework/tests/unit/agent-runner.test.ts +496 -47
- 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/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/episode-lease.test.ts +695 -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/kb-ingest-lease.test.ts +19 -0
- package/.framework/tests/unit/logging-app-id.test.ts +75 -0
- package/.framework/tests/unit/pipeline-runner-background.test.ts +120 -0
- package/.framework/tests/unit/pipeline-runner.test.ts +153 -1
- package/.framework/tests/unit/principal-cache.test.ts +15 -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/.framework/tests/unit/trigger-engine.test.ts +278 -91
- package/.framework/tests/unit/trigger-scheduler.test.ts +78 -0
- package/README.md +125 -166
- package/config/tsconfig.cli.json +2 -2
- package/netlify.toml +5 -0
- 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,280 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Design Schema Reference
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: reference
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/src/types/types.ts
|
|
9
|
+
- .framework/functions/_shared/schema-utils.ts
|
|
10
|
+
- .framework/functions/_shared/permissions.ts
|
|
11
|
+
- .framework/functions/admin-data.ts
|
|
12
|
+
- .framework/functions/types.ts
|
|
13
|
+
- .framework/cli/commands/validate-schema.ts
|
|
14
|
+
- .framework/src/components/shared/FieldRenderer.tsx
|
|
15
|
+
- .framework/src/components/app-shell/GenericListPage.tsx
|
|
16
|
+
- .framework/src/components/app-shell/GenericDetailPage.tsx
|
|
17
|
+
- .framework/src/hooks/useForm.ts
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Design Schema Reference
|
|
21
|
+
|
|
22
|
+
Exhaustive field-level spec for `public.types.design_schema` — the JSON every
|
|
23
|
+
type carries and every runtime record is stamped with at creation. The mental
|
|
24
|
+
model is in [Design Schema](../concepts/design-schema.md); this page is the
|
|
25
|
+
lookup table. The TypeScript source of truth is `DesignSchema`,
|
|
26
|
+
`FieldDefinition`, `ViewFieldConfig`, `ListView`, `DetailView`, and
|
|
27
|
+
`FunctionalityBindings` in `.framework/src/types/types.ts`.
|
|
28
|
+
|
|
29
|
+
## Top-level shape
|
|
30
|
+
|
|
31
|
+
| Key | Type | Required | Purpose |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `fields` | `Record<string, FieldDefinition>` | yes | Flat map of `snake_case` field names to definitions |
|
|
34
|
+
| `views` | `Record<string, View>` | yes for generic apps | `default_list` and `default_detail` drive the generic UI |
|
|
35
|
+
| `record_permissions` | `Record<string, string[]>` | yes | Base CRUD grant per role slug |
|
|
36
|
+
| `scope` | `"account" \| "platform"` | no (default `"account"`) | Which account owns records of this type at create |
|
|
37
|
+
| `functionality` | `FunctionalityBindings` or extensions | no | Automation bindings; `null` until a binding is confirmed live |
|
|
38
|
+
| `display_field` | `string` | no | Field used for record titles in detail pages |
|
|
39
|
+
|
|
40
|
+
`validate-schema` enforces: `fields` non-empty; every field has `data_type`,
|
|
41
|
+
`label`, `required`; `record_permissions` grants at least `system-admin` or
|
|
42
|
+
`system_admin`; `scope` is `account` or `platform`
|
|
43
|
+
(`.framework/cli/commands/validate-schema.ts`).
|
|
44
|
+
|
|
45
|
+
## `fields.<name>` — FieldDefinition
|
|
46
|
+
|
|
47
|
+
| Key | Type | Notes |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `data_type` | enum, see below | required |
|
|
50
|
+
| `label` | string | required |
|
|
51
|
+
| `required` | boolean | required; enforced client-side by `useForm` (`.framework/src/hooks/useForm.ts`), propagated into `validation_schema` |
|
|
52
|
+
| `system` | boolean | `true` → top-level record column; absent/`false` → `record.data.<name>` |
|
|
53
|
+
| `placeholder` | string | input hint |
|
|
54
|
+
| `description` | string | help text |
|
|
55
|
+
| `name` | string | optional field alias |
|
|
56
|
+
| `rows` | number | textarea height hint |
|
|
57
|
+
| `min`, `max`, `step` | number | range input bounds |
|
|
58
|
+
| `readonly`, `disabled` | boolean | form-state hints |
|
|
59
|
+
| `validation` | object | constraint keys, see below |
|
|
60
|
+
| `options` | `(string \| {value, label})[]` | required for `select`, `multiselect`, `radio` |
|
|
61
|
+
| `permissions` | `Record<string, string[]>` | per-role field overrides, `read`/`write` only |
|
|
62
|
+
|
|
63
|
+
### `data_type` values
|
|
64
|
+
|
|
65
|
+
The authoritative dispatch is `sanitizeFieldData` in
|
|
66
|
+
`.framework/functions/_shared/schema-utils.ts`. Unknown types are **not
|
|
67
|
+
rejected** — the value passes through unsanitized and unvalidated.
|
|
68
|
+
|
|
69
|
+
**Where the sanitizer runs.** `sanitizeFieldData` executes only on the
|
|
70
|
+
`admin-data` **update** path, only for `data.*` (non-system) fields, and only
|
|
71
|
+
for **non-system-admin** principals. `create` performs no field sanitization —
|
|
72
|
+
the request body is inserted as-is — and system columns (`system: true`,
|
|
73
|
+
including `select` fields like `status`) are never option-validated
|
|
74
|
+
server-side. `required` is enforced client-side by `useForm` only. So
|
|
75
|
+
"sanitizer behavior throws" below means: on a `data.*` update by a non-admin
|
|
76
|
+
caller. The trust boundary is the client + field permissions, not
|
|
77
|
+
`validation_schema` — treat API writes as unvalidated input.
|
|
78
|
+
|
|
79
|
+
| `data_type` | Stored as | Sanitizer behavior |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `text` | string | trim, strip control chars; `minLength` throws, `maxLength` truncates, `pattern` throws |
|
|
82
|
+
| `textarea` | string | trim, strip control chars; `minLength`/`maxLength` |
|
|
83
|
+
| `rich_text` | HTML string | tag allowlist (`p br strong em u ol ul li a h1–h6`), strips `<script>` and `on*=` handlers; `minLength`/`maxLength` |
|
|
84
|
+
| `email` | string | lowercase + trim; must match `^[^\s@]+@[^\s@]+\.[^\s@]+$` |
|
|
85
|
+
| `phone` | string | strips non-`0-9+` chars; optional `pattern` |
|
|
86
|
+
| `url` | string | parses URL; `http:`/`https:` only; normalized via `URL.toString()` |
|
|
87
|
+
| `number` | number | `Number()` coercion; `min`/`max` throw; `step` snaps down to step |
|
|
88
|
+
| `currency` | number | `Number()` coercion rounded to 2 decimals; `min`/`max` throw |
|
|
89
|
+
| `range` | number | same as `number` |
|
|
90
|
+
| `date` | `"YYYY-MM-DD"` | parses any `Date()` input, stores ISO date; `min`/`max` bounds |
|
|
91
|
+
| `datetime` | ISO string | parses any `Date()` input, stores `toISOString()`; `min`/`max` bounds |
|
|
92
|
+
| `boolean` | boolean | `true`/`false` pass through; strings `"true" "1" "yes" "on"` → `true`, `"false" "0" "no" "off"` → `false`; anything else throws |
|
|
93
|
+
| `checkbox` | boolean | alias of `boolean` |
|
|
94
|
+
| `select` | string | trim; when `options` are declared the value must match an option (`value` for `{label,value}` entries) or it throws |
|
|
95
|
+
| `multiselect` | string[] | accepts an array or comma-separated string; dedupes; each element must match an option; `validation.max` truncates the list |
|
|
96
|
+
| `radio` | string | same sanitizer as `select` |
|
|
97
|
+
| `color` | string | must match `#rgb`/`#rrggbb`; normalized to 6-digit uppercase hex |
|
|
98
|
+
| `file` | object | must be an object with `.name`; `maxSize` and `allowedTypes` (MIME) enforced; filename sanitized to `[a-zA-Z0-9.-]` |
|
|
99
|
+
| `image` | object | same sanitizer as `file` (`maxWidth`/`maxHeight` are declared but not enforced) |
|
|
100
|
+
| `json` | any JSON value | string input is `JSON.parse`d; rejects script tags, `javascript:`, `eval(`/`function(`, `on*=` handlers, and `__proto__` keys; arbitrary nesting allowed under `data.<name>` |
|
|
101
|
+
| `reference` | string (uuid) | must match the UUID regex; `validation.reference_kind`/`reference_type` describe the target |
|
|
102
|
+
| `address` | object | must be an object; string values are text-sanitized |
|
|
103
|
+
|
|
104
|
+
`formatFieldData` (display formatting) covers only `json`, `date`, `datetime`,
|
|
105
|
+
`currency`, `phone`, `url`, `reference`, `address`, `multiselect`, `boolean` —
|
|
106
|
+
all other types render raw.
|
|
107
|
+
|
|
108
|
+
### `validation.*` keys
|
|
109
|
+
|
|
110
|
+
Declared on `FieldDefinition.validation`; copied verbatim into the generated
|
|
111
|
+
`validation_schema` by `generateValidationSchema`
|
|
112
|
+
(`.framework/functions/_shared/schema-utils.ts`).
|
|
113
|
+
|
|
114
|
+
| Key | Applies to | Effect |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| `pattern` | `text`, `phone` | regex must match or the write throws |
|
|
117
|
+
| `minLength`, `maxLength` | `text`, `textarea`, `rich_text` | min throws; max truncates |
|
|
118
|
+
| `min`, `max` | `number`, `currency`, `range`, `date`, `datetime` | bounds; out-of-range throws |
|
|
119
|
+
| `step` | `number`, `range` | value snapped down to step multiple |
|
|
120
|
+
| `integer` | `number` | declared; not enforced by the server sanitizer |
|
|
121
|
+
| `precision` | `number` | declared decimal precision; not enforced server-side |
|
|
122
|
+
| `maxSize` | `file`, `image` | byte-size limit, enforced server-side |
|
|
123
|
+
| `allowedTypes` | `file`, `image` | MIME allowlist, enforced server-side |
|
|
124
|
+
| `maxWidth`, `maxHeight` | `image` | declared; not enforced server-side |
|
|
125
|
+
| `max` | `multiselect` | truncates the list to `max` entries |
|
|
126
|
+
| `currency_code` | `currency` | display currency (e.g. `USD`) |
|
|
127
|
+
| `reference_kind` | `reference` | runtime table of the target (`item`, `person`, `account`, …) |
|
|
128
|
+
| `reference_type` | `reference` | type slug of the target record |
|
|
129
|
+
|
|
130
|
+
### `options` formats
|
|
131
|
+
|
|
132
|
+
Required for `select`/`multiselect`/`radio`; validated non-empty by
|
|
133
|
+
`validate-schema`. Both forms accepted:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
"options": ["todo", "done"]
|
|
137
|
+
"options": [{ "label": "Bug", "value": "bug" }]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### `permissions` (field-level overrides)
|
|
141
|
+
|
|
142
|
+
`record_permissions` is the **base, most restrictive** grant: when a role can
|
|
143
|
+
`read`/`update` a record, every field defaults to `read`/`write` unless the
|
|
144
|
+
field declares a `permissions` entry for that role. Field-level actions are
|
|
145
|
+
`read` and `write` only; `create`/`delete` are record-level
|
|
146
|
+
(`.framework/functions/_shared/permissions.ts`, `resolveFirstSurfacePermissions`
|
|
147
|
+
step 5–6). Use field permissions to **loosen** one field beyond the record
|
|
148
|
+
grant or to re-restrict a `system: true` field.
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
"fields": {
|
|
152
|
+
"cost": {
|
|
153
|
+
"data_type": "currency", "label": "Cost", "required": false,
|
|
154
|
+
"permissions": { "member": ["read"], "finance": ["read", "write"] }
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `system` flag semantics
|
|
160
|
+
|
|
161
|
+
`system: true` fields are stored as top-level record columns (`record.title`),
|
|
162
|
+
all others under `record.data.<name>` — see
|
|
163
|
+
[Runtime Records](../concepts/runtime-records.md). Writers split payloads the
|
|
164
|
+
same way (`useEntityRecord` / the update path). Conventionally `title` is
|
|
165
|
+
system; flag `system: true` fields that humans must not edit with a
|
|
166
|
+
`permissions` override restricting `write` to `system_admin`.
|
|
167
|
+
|
|
168
|
+
## `views`
|
|
169
|
+
|
|
170
|
+
`views` is a map of view names to `ListView | DetailView`. Generic apps
|
|
171
|
+
(`apps.renderer = "generic"`) need `default_list` and `default_detail`; a
|
|
172
|
+
custom app may omit views but loses the generic admin/runtime fallback.
|
|
173
|
+
|
|
174
|
+
### `default_list` — ListView
|
|
175
|
+
|
|
176
|
+
| Key | Type | Purpose |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| `type` | `"list"` | required discriminator |
|
|
179
|
+
| `display` | `"table" \| "card" \| "board"` | layout in `GenericListPage` |
|
|
180
|
+
| `label` | string | view title |
|
|
181
|
+
| `fields` | `Record<string, ViewFieldConfig>` | column map, keyed by field name (may include `created_at`/`updated_at`). Non-system fields resolve automatically — key `priority` reads `record.data.priority`; the explicit `data.priority` form also works and filters on `data.<field>` are translated server-side |
|
|
182
|
+
| `default_sort` | `{field, direction: "asc"\|"desc"}` | initial ordering |
|
|
183
|
+
| `filters` | `(string \| EntityFilter)[]` | filter affordances — a bare field-name string is normalized from the field def (`select` → enum with its option values, `boolean` → boolean, else search); or pass full `{key, label, type: "search"\|"enum"\|"boolean", options?: string[]}` objects |
|
|
184
|
+
| `stats` | `{title, type: "count"\|"filter_count", icon?, color?, filter?}[]` | stat cards above the list; `filter` is a `{<field>: <value>}` map matched per row (e.g. `{"status": "todo"}`) |
|
|
185
|
+
| `group_by` | string | field to group rows by (board display) |
|
|
186
|
+
|
|
187
|
+
### `default_detail` — DetailView
|
|
188
|
+
|
|
189
|
+
| Key | Type | Purpose |
|
|
190
|
+
|---|---|---|
|
|
191
|
+
| `type` | `"detail"` | required discriminator |
|
|
192
|
+
| `label` | string | page title |
|
|
193
|
+
| `sections` | `DetailViewSection[]` | ordered sections of `{title, fields: Record<string, ViewFieldConfig>}` |
|
|
194
|
+
|
|
195
|
+
### `ViewFieldConfig` — `display_type`
|
|
196
|
+
|
|
197
|
+
Each view field is `{display_type, sortable?, searchable?}`. Implemented
|
|
198
|
+
`display_type` values — enforced by `validate-schema` and rendered by
|
|
199
|
+
`.framework/src/components/shared/FieldRenderer.tsx`:
|
|
200
|
+
|
|
201
|
+
| `display_type` | Context |
|
|
202
|
+
|---|---|
|
|
203
|
+
| `text` | read-only text (list/detail) |
|
|
204
|
+
| `badge` | status pill (list) |
|
|
205
|
+
| `timestamp` | formatted date/time (list/detail) |
|
|
206
|
+
| `currency` | formatted amount |
|
|
207
|
+
| `number` | formatted number |
|
|
208
|
+
| `input` | single-line edit input (detail) |
|
|
209
|
+
| `textarea` | multi-line edit |
|
|
210
|
+
| `rich_text` | rich-text editor |
|
|
211
|
+
| `select`, `multiselect`, `radio` | option pickers |
|
|
212
|
+
| `checkbox`, `switch` | boolean toggles |
|
|
213
|
+
| `date_picker`, `datetime_picker` | date/time pickers |
|
|
214
|
+
| `color_picker` | color input |
|
|
215
|
+
| `file_upload`, `image_upload` | upload widgets |
|
|
216
|
+
| `range_slider` | numeric slider |
|
|
217
|
+
|
|
218
|
+
Reserved in `ViewFieldConfig` but not yet implemented by `FieldRenderer`:
|
|
219
|
+
`rating`, `autocomplete`, `address_form`, `reference_picker` (the type union
|
|
220
|
+
admits them in `.framework/src/types/types.ts`; treat as forward-compatible
|
|
221
|
+
placeholders).
|
|
222
|
+
|
|
223
|
+
## `record_permissions`
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
"record_permissions": {
|
|
227
|
+
"system_admin": ["create", "read", "update", "delete"],
|
|
228
|
+
"admin": ["create", "read", "update"],
|
|
229
|
+
"member": ["read"]
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
- Actions are `create`, `read`, `update`, `delete` — evaluated per request
|
|
234
|
+
against the caller's role slug.
|
|
235
|
+
- `"all"` is a wildcard role granted to every authenticated principal that
|
|
236
|
+
passed RLS; always evaluated when present
|
|
237
|
+
(`.framework/functions/_shared/permissions.ts`).
|
|
238
|
+
- Evaluation happens against the schema **stamped on the record**, not the
|
|
239
|
+
type row — records created before a schema edit keep the old grant.
|
|
240
|
+
- If a type's `design_schema` omits `record_permissions`, `admin-data` create
|
|
241
|
+
merges a permissive default `{all: [create,read,update,delete]}` before
|
|
242
|
+
stamping (`.framework/functions/admin-data.ts`, `PERMISSIONS_ALL`). An
|
|
243
|
+
explicit empty object denies everything downstream — always author
|
|
244
|
+
deliberately.
|
|
245
|
+
|
|
246
|
+
## `scope`
|
|
247
|
+
|
|
248
|
+
Read at create time as `designSchema.scope ?? 'account'`
|
|
249
|
+
(`.framework/functions/admin-data.ts`). `"platform"` stamps new records with
|
|
250
|
+
the `spine-system` account id; records created against a parent
|
|
251
|
+
(`thread_id`, `target_id`, `parent_id`) inherit the parent's stamped scope.
|
|
252
|
+
See [Scope and Accounts](../concepts/scope-and-accounts.md).
|
|
253
|
+
|
|
254
|
+
## `functionality`
|
|
255
|
+
|
|
256
|
+
`FunctionalityBindings` (`.framework/src/types/types.ts`) declares optional
|
|
257
|
+
automation:
|
|
258
|
+
|
|
259
|
+
| Binding | Shape |
|
|
260
|
+
|---|---|
|
|
261
|
+
| `pipelines[]` | `{pipeline_id, trigger: manual\|on_create\|on_update\|on_field_change\|on_delete\|scheduled, field?, condition?, roles[]}` |
|
|
262
|
+
| `ai_agents[]` | `{agent_id, capabilities: (read\|summarize\|suggest\|update)[], trigger, roles[]}` |
|
|
263
|
+
| `embeddings[]` | `{slug, fields[], model, vector_column, trigger}` |
|
|
264
|
+
| `integrations[]` | `{integration_id, sync: bidirectional\|inbound\|outbound, field_map, trigger}` |
|
|
265
|
+
| `constraints[]` | `{type: unique\|conditional_required\|immutable, fields?/field?, condition?, message, after?: create\|update}` |
|
|
266
|
+
|
|
267
|
+
`admin-data` also reads `functionality.lineage`
|
|
268
|
+
(`{parent_fields: string[], link_type: string, children: {[slug]: field}}`)
|
|
269
|
+
on `items` get/list to attach `parents`/`children` — declared per type in the
|
|
270
|
+
seed, interpreted by `attachLineage` in `.framework/functions/admin-data.ts`.
|
|
271
|
+
Set `functionality` to `null` until the binding you need is confirmed live.
|
|
272
|
+
|
|
273
|
+
## `validation_schema` (generated, never authored)
|
|
274
|
+
|
|
275
|
+
`generateValidationSchema` derives `{fields: {name: {data_type, required,
|
|
276
|
+
...validation, options, reference_kind?, reference_type?}}}` from
|
|
277
|
+
`design_schema.fields` on every type create and on every update that touches
|
|
278
|
+
`design_schema` (`.framework/functions/types.ts`,
|
|
279
|
+
`.framework/cli/commands/install-app.ts` seed path). Never hand-edit — change
|
|
280
|
+
`design_schema` and let the writer regenerate it.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Environment Variables
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: reference
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .env.example
|
|
9
|
+
- .framework/functions/_shared/principal.ts
|
|
10
|
+
- .framework/functions/_shared/db.ts
|
|
11
|
+
- .framework/functions/_shared/middleware.ts
|
|
12
|
+
- .framework/functions/_shared/trigger-engine.ts
|
|
13
|
+
- .framework/functions/_shared/resolve-credentials.ts
|
|
14
|
+
- .framework/functions/system-cron.ts
|
|
15
|
+
- .framework/functions/pipeline-runner-background.ts
|
|
16
|
+
- .framework/functions/security.ts
|
|
17
|
+
- .framework/functions/invites.ts
|
|
18
|
+
- .framework/functions/adapters/resend-outbound.ts
|
|
19
|
+
- .framework/cli/context.ts
|
|
20
|
+
- .framework/cli/commands/migrate.ts
|
|
21
|
+
- .framework/cli/commands/install-app.ts
|
|
22
|
+
- .framework/src/lib/supabase.ts
|
|
23
|
+
- .framework/src/App.tsx
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Environment Variables
|
|
27
|
+
|
|
28
|
+
Every variable read across `.framework/` — where it's read, whether it's
|
|
29
|
+
required, and whether it is browser-exposed. `VITE_*` vars are compiled into
|
|
30
|
+
the frontend bundle and are **public by definition**; all others are
|
|
31
|
+
server-only (Netlify functions, CLI, MCP tooling). `.env` at the project root
|
|
32
|
+
is preloaded by the CLI and dev tooling.
|
|
33
|
+
|
|
34
|
+
> **Security rule:** never set `VITE_SUPABASE_SERVICE_ROLE_KEY` or put any
|
|
35
|
+
> secret behind a `VITE_*` name. The service-role key bypasses RLS entirely;
|
|
36
|
+
> shipping it to the browser hands full database access to every visitor.
|
|
37
|
+
> Only `VITE_SUPABASE_ANON_KEY` belongs in the client bundle.
|
|
38
|
+
|
|
39
|
+
## Required — server
|
|
40
|
+
|
|
41
|
+
| Variable | Read by | Purpose |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `SUPABASE_URL` | `.framework/functions/_shared/db.ts`, `.framework/functions/_shared/principal.ts`, CLI (`context.ts`, `install-app.ts`, `migrate.ts`, `status.ts`, `system.ts`) | Supabase project URL for service + user clients |
|
|
44
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | `.framework/functions/_shared/db.ts` (`adminDb`), `.framework/cli/context.ts`, `install-app.ts`, `status.ts` | Service-role client; bypasses RLS. **Server-only** |
|
|
45
|
+
| `SUPABASE_ANON_KEY` | `.framework/functions/_shared/principal.ts`, `.framework/functions/_shared/db.ts` (`getUserDb`) | JWT verification and user-scoped PostgREST clients inside functions |
|
|
46
|
+
|
|
47
|
+
Missing `SUPABASE_URL`/`SUPABASE_SERVICE_ROLE_KEY` fails CLI commands that
|
|
48
|
+
touch the DB and leaves `adminDb` on placeholder credentials — function
|
|
49
|
+
calls then fail at query time.
|
|
50
|
+
|
|
51
|
+
> **Key naming:** all three values are under Supabase Dashboard → Project
|
|
52
|
+
> Settings → API Keys (older dashboards: Settings → API / Data API).
|
|
53
|
+
> Current dashboards issue the anon key as a **Publishable key**
|
|
54
|
+
> (`sb_publishable_…`) and the service-role key as a **Secret key**
|
|
55
|
+
> (`sb_secret_…`) — set `*_ANON_KEY` / `SUPABASE_SERVICE_ROLE_KEY` to them
|
|
56
|
+
> directly; they work everywhere the legacy JWTs did.
|
|
57
|
+
|
|
58
|
+
## Required for specific features — server
|
|
59
|
+
|
|
60
|
+
| Variable | Read by | Required for |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `SUPABASE_DB_PASSWORD` | `.framework/cli/commands/migrate.ts`, `install-app.ts` | Direct Postgres connection for `migrate`/`install-app` (from Supabase Dashboard → Database) |
|
|
63
|
+
| `SUPABASE_DB_URL` | `.framework/cli/commands/migrate.ts` | Optional full connection string overriding host/user/port — use the **Session Pooler** (`postgres://postgres.<ref>:<pw>@aws-0-<region>.pooler.supabase.com:5432/postgres`) when `db.<ref>.supabase.co:5432` is unreachable (direct connections are IPv6-only on most Supabase projects) |
|
|
64
|
+
| `INTERNAL_INVOKE_SECRET` | `.framework/functions/_shared/principal.ts` (`isInternalInvokeAuthorized`), `.framework/functions/_shared/trigger-engine.ts`, `.framework/functions/pipeline-runner-background.ts` | Authenticates function-to-function invocation via `x-internal-secret`. **Required for trigger dispatch** — without it, `dispatchTriggerPipeline` cannot invoke `pipeline-runner-background` and `x-cron-id`/`x-trigger-id`/`x-internal-secret` headers are never honored. Generate with `openssl rand -hex 32` |
|
|
65
|
+
| `SCHEDULER_API_KEY` | `.framework/functions/system-cron.ts` | `?api_key=`/`?scheduler_key=` on the scheduler endpoint; unset disables key-gated scheduling |
|
|
66
|
+
| `APP_BASE_URL` | `.framework/functions/invites.ts` | Base URL for invite links, auth redirects, and the allowlist for client-supplied `base_url` params |
|
|
67
|
+
| `RESEND_API_KEY` | resolved via `env_var` credentials on the `transactional-email`/`resend` integration (`.framework/functions/_shared/resolve-credentials.ts`) | Outbound email (invites, notification stages). Unset → invites fall back to copyable links, email stages skip |
|
|
68
|
+
| `EMAIL_FROM` | `.framework/functions/adapters/resend-outbound.ts` | Sender identity for outbound email |
|
|
69
|
+
| `OPENAI_API_KEY` | resolved via `env_var` credentials on the `openai` integration; `.framework/functions/_shared/agent-runner.ts` mocks responses when absent | LLM chat/embeddings for agents, pipelines, KB |
|
|
70
|
+
| `LLM_DEFAULT_MODEL` | `.framework/functions/_shared/agent-runner.ts`, `.framework/functions/embeddings.ts` | Default model slug when prompts don't pin one |
|
|
71
|
+
| `NETLIFY_ACCESS_TOKEN`, `NETLIFY_SITE_ID` | `.framework/functions/security.ts` | Push banned IPs to Netlify edge Firewall rules; unset skips the edge layer |
|
|
72
|
+
|
|
73
|
+
Integration credentials generally use `source: 'env_var'` +
|
|
74
|
+
`value: '<VAR_NAME>'` in `integrations.config.credentials` —
|
|
75
|
+
`resolveCredentials` reads `process.env[value]` server-side
|
|
76
|
+
(`.framework/functions/_shared/resolve-credentials.ts`). Any env var name is
|
|
77
|
+
permitted there.
|
|
78
|
+
|
|
79
|
+
## Optional — server behavior tuning
|
|
80
|
+
|
|
81
|
+
| Variable | Read by | Default |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| `SITE_URL` | `.framework/functions/_shared/middleware.ts` | `Access-Control-Allow-Origin` header; falls back to Netlify's `URL`, then `*` |
|
|
84
|
+
| `URL` | `.framework/functions/_shared/middleware.ts`, `.framework/mcp/` | Netlify auto-set site URL; CORS and MCP base-URL fallback |
|
|
85
|
+
| `ALLOWED_ORIGINS` | `.framework/functions/invites.ts` | extra CORS origins for invite endpoints |
|
|
86
|
+
| `SPINE_IP_RATE_LIMIT` | `.framework/functions/_shared/principal.ts` | per-IP request ceiling for API-key auth; default `300`/60s |
|
|
87
|
+
| `REPO_PATH` | `.framework/functions/_shared/app-manifest.ts`, `.framework/mcp/` | project root for manifest discovery; defaults to `process.cwd()` |
|
|
88
|
+
| `DB_SCHEMA` | `.framework/functions/_shared/db.ts` | PostgREST schema; default `public` (multi-instance installs only) |
|
|
89
|
+
| `EMAIL_WEBHOOK_URL` | outbound adapters | optional inbound-email relay endpoint |
|
|
90
|
+
|
|
91
|
+
## Client-exposed (`VITE_*`, browser bundle)
|
|
92
|
+
|
|
93
|
+
| Variable | Read by | Purpose |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `VITE_SUPABASE_URL` | `.framework/src/lib/supabase.ts` | Supabase URL for the browser client — required |
|
|
96
|
+
| `VITE_SUPABASE_ANON_KEY` | `.framework/src/lib/supabase.ts` | anon key for the browser client — required, RLS-scoped, safe |
|
|
97
|
+
| `VITE_ENVIRONMENT` | `.framework/src/contexts/AppContext.tsx`, `.framework/src/hooks/useApps.ts` | environment badge (`dev`/`staging`/`prod`) |
|
|
98
|
+
| `VITE_SETUP_MODE` | `.framework/src/App.tsx` | setup-mode UI flag |
|
|
99
|
+
| `VITE_TURNSTILE_SITE_KEY` | `.framework/src/components/auth/TurnstileWidget.tsx` | Cloudflare Turnstile site key on auth pages — public by design |
|
|
100
|
+
| `VITE_APP_NAME` | `.env.example` (branding) | app name for UI/localStorage/webhook headers — prefer `branding.app_name` in `spine.config.json` |
|
|
101
|
+
| `VITE_DB_SCHEMA` | `.env.example` | deprecated multi-instance knob; leave unset |
|
|
102
|
+
|
|
103
|
+
## CLI / local tooling
|
|
104
|
+
|
|
105
|
+
| Variable | Read by | Purpose |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `SPINE_CLI_API_KEY` | `.framework/cli/context.ts` | API-key auth for remote CLI commands (`items`, `pipelines`, `agents`, `system`) |
|
|
108
|
+
| `SPINE_CLI_JWT` | `.framework/cli/context.ts` | JWT auth alternative for the same commands |
|
|
109
|
+
| `SPINE_CLI_ACCOUNT_ID` | `.framework/cli/context.ts` | default account scope; `--account` overrides |
|
|
110
|
+
| `SPINE_CLI_DEBUG` | `dev.ts`, `init.ts`, `install-app.ts`, `migrate.ts`, `upgrade.ts` | verbose CLI diagnostics |
|
|
111
|
+
| `SPINE_URL`, `SPINE_API_KEY`, `SPINE_FRAMEWORK_API_KEY` | `.framework/mcp/` | MCP server endpoint + key |
|
|
112
|
+
| `OPENAI_BASE_URL`, `LLM_API_KEY`, `OPENAI_API_KEY` | `.framework/mcp/` | MCP-side LLM provider config |
|
|
113
|
+
|
|
114
|
+
## Consumer-side conventions
|
|
115
|
+
|
|
116
|
+
Not read by framework runtime code — a convention for agent/tooling
|
|
117
|
+
integrations so the same credential location works everywhere:
|
|
118
|
+
|
|
119
|
+
| Variable | Read by | Purpose |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `SPINE_API_KEY` | agent tooling (`.framework/mcp/` honors it too) | the `sk_…` key an agent sends as `x-api-key` on `/api/*` requests; the user creates a scoped key in Admin → Configs → API Keys |
|
|
122
|
+
|
|
123
|
+
## Test-only
|
|
124
|
+
|
|
125
|
+
`SPINE_DEV_URL`, `SPINE_DEV_JWT`, `SPINE_TEST_API_KEY`, `SPINE_TEST_ACCOUNT_ID`,
|
|
126
|
+
`ACCOUNT_ID`, `SERVICE_KEY` — used by `.framework/tests/` fixtures and
|
|
127
|
+
integration suites; never required at runtime.
|
|
128
|
+
|
|
129
|
+
## Related
|
|
130
|
+
|
|
131
|
+
- `.env.example` — annotated starter file
|
|
132
|
+
- [Authentication](api/auth.md) — how `x-api-key`/`x-internal-secret`/Bearer resolve
|
|
133
|
+
- [Shared Modules](shared-modules.md)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: account-nodes
|
|
3
|
+
audience: both
|
|
4
|
+
kind: reference
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/functions/account-nodes.ts
|
|
9
|
+
- .framework/functions/_shared/middleware.ts
|
|
10
|
+
- .framework/public/_redirects
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# account-nodes
|
|
14
|
+
|
|
15
|
+
## What it does
|
|
16
|
+
|
|
17
|
+
Returns one account ("node") plus its position in the account hierarchy:
|
|
18
|
+
ancestors, direct children, and full descendants. Used to render account
|
|
19
|
+
trees and breadcrumb navigation.
|
|
20
|
+
|
|
21
|
+
## Route and methods
|
|
22
|
+
|
|
23
|
+
`/.netlify/functions/account-nodes`, reachable as
|
|
24
|
+
`GET /api/account-nodes?node_id=<uuid>` (`/api/*` →
|
|
25
|
+
`/.netlify/functions/:splat`). The handler performs no method check — any
|
|
26
|
+
HTTP method with the query parameter works.
|
|
27
|
+
|
|
28
|
+
## Authentication
|
|
29
|
+
|
|
30
|
+
Standard `createHandler`: `x-api-key`, internal secret, or
|
|
31
|
+
`Bearer <jwt>` required; anonymous is rejected with 401. Queries run on
|
|
32
|
+
`ctx.db`, so human callers see only what row-level security allows; machine
|
|
33
|
+
and system principals use the service role.
|
|
34
|
+
|
|
35
|
+
## Request contract
|
|
36
|
+
|
|
37
|
+
One query parameter:
|
|
38
|
+
|
|
39
|
+
- `node_id` — required, the `accounts.id` to center the lookup on.
|
|
40
|
+
|
|
41
|
+
## Response contract
|
|
42
|
+
|
|
43
|
+
`{ node, ancestors, children, descendants }` inside the standard
|
|
44
|
+
`{ data, error, meta }` envelope:
|
|
45
|
+
|
|
46
|
+
- `node` — the account row's embedded `type` (`{ type: { id, slug, name,
|
|
47
|
+
icon, color } }`); the account's own columns are not selected.
|
|
48
|
+
- `ancestors` — rows returned by the `get_account_ancestors` RPC, else `[]`.
|
|
49
|
+
- `children` — active `accounts` rows with `parent_id = node_id`, each
|
|
50
|
+
shaped `{ type: {...} }`, ordered by `display_name`.
|
|
51
|
+
- `descendants` — rows returned by the `get_account_descendants` RPC, else `[]`.
|
|
52
|
+
|
|
53
|
+
## Side effects
|
|
54
|
+
|
|
55
|
+
None — read-only. A `request.get` span is emitted by the middleware like
|
|
56
|
+
every `createHandler` call.
|
|
57
|
+
|
|
58
|
+
## Errors
|
|
59
|
+
|
|
60
|
+
| Condition | HTTP | Message |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| Missing `node_id` | 500 | `node_id is required` |
|
|
63
|
+
| No active account with that id | 500 | `Account node not found` |
|
|
64
|
+
| RPC/query failure | 500 | underlying PostgREST message |
|
|
65
|
+
|
|
66
|
+
## Agent notes
|
|
67
|
+
|
|
68
|
+
- The `select` on `node` and `children` contains only the embedded `type`
|
|
69
|
+
relation — do not expect `display_name`, `slug`, or other account
|
|
70
|
+
columns on those payloads; fetch the account itself via
|
|
71
|
+
`/api/admin-data?entity=accounts&id=…` when you need them.
|
|
72
|
+
- `ancestors`/`descendants` come from database functions; their row shape
|
|
73
|
+
is whatever the RPC returns, not the `{ type }` shape used for `node`.
|
|
74
|
+
- Inactive accounts are filtered from `node` and `children`
|
|
75
|
+
(`is_active = true`) but RPC results are whatever the functions return.
|