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,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Build your first app
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: guide
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-29
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/functions/types.ts
|
|
9
|
+
- .framework/functions/apps.ts
|
|
10
|
+
- .framework/functions/admin-data.ts
|
|
11
|
+
- .framework/functions/_shared/trigger-engine.ts
|
|
12
|
+
- .framework/functions/_shared/schema-utils.ts
|
|
13
|
+
- .framework/src/components/app-shell/GenericAppShell.tsx
|
|
14
|
+
- .framework/src/components/app-shell/GenericListPage.tsx
|
|
15
|
+
- .framework/src/components/app-shell/GenericDetailPage.tsx
|
|
16
|
+
- .framework/src/components/CustomAppLoader.tsx
|
|
17
|
+
- .framework/src/contexts/AppContext.tsx
|
|
18
|
+
- .framework/src/lib/api.ts
|
|
19
|
+
- .framework/cli/commands/create-app.ts
|
|
20
|
+
- .framework/cli/commands/generate.ts
|
|
21
|
+
- .framework/cli/commands/install-app.ts
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Build your first app
|
|
25
|
+
|
|
26
|
+
The smallest useful Spine app is one type + one app row — no code at all.
|
|
27
|
+
This walkthrough builds a `task` tracker end to end, then adds a custom page
|
|
28
|
+
and a pipeline. You need a `system_admin` login (see
|
|
29
|
+
[01-install-and-first-run.md](./01-install-and-first-run.md)) — app creation
|
|
30
|
+
is restricted to system admins (`.framework/functions/apps.ts`).
|
|
31
|
+
|
|
32
|
+
## Step 1 — define the type
|
|
33
|
+
|
|
34
|
+
Admin UI → **Configs → Types → New** (or `POST /api/types`). Set:
|
|
35
|
+
|
|
36
|
+
- **Kind**: `item` — records land in `public.items`.
|
|
37
|
+
- **Slug**: `task` — unique within `kind`; callers resolve types by it.
|
|
38
|
+
- **Design schema** — the fields, views, and permissions below.
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"scope": "account",
|
|
43
|
+
"fields": {
|
|
44
|
+
"title": { "data_type": "text", "label": "Title", "required": true, "system": true },
|
|
45
|
+
"status": { "data_type": "select", "label": "Status", "required": true,
|
|
46
|
+
"options": ["todo", "doing", "done"] },
|
|
47
|
+
"priority": { "data_type": "select", "label": "Priority", "required": false,
|
|
48
|
+
"options": ["low", "normal", "high"] },
|
|
49
|
+
"notes": { "data_type": "textarea", "label": "Notes", "required": false }
|
|
50
|
+
},
|
|
51
|
+
"views": {
|
|
52
|
+
"default_list": {
|
|
53
|
+
"type": "list", "display": "table", "label": "Tasks",
|
|
54
|
+
"fields": {
|
|
55
|
+
"title": { "sortable": true, "display_type": "text" },
|
|
56
|
+
"status": { "sortable": true, "display_type": "badge" },
|
|
57
|
+
"priority": { "sortable": true, "display_type": "badge" },
|
|
58
|
+
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
59
|
+
},
|
|
60
|
+
"default_sort": { "field": "created_at", "direction": "desc" }
|
|
61
|
+
},
|
|
62
|
+
"default_detail": {
|
|
63
|
+
"type": "detail", "label": "Task",
|
|
64
|
+
"sections": [
|
|
65
|
+
{ "title": "Core",
|
|
66
|
+
"fields": {
|
|
67
|
+
"title": { "display_type": "input" },
|
|
68
|
+
"status": { "display_type": "select" },
|
|
69
|
+
"priority": { "display_type": "select" },
|
|
70
|
+
"notes": { "display_type": "textarea" }
|
|
71
|
+
} }
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"record_permissions": {
|
|
76
|
+
"system_admin": ["create", "read", "update", "delete"],
|
|
77
|
+
"engineering": ["create", "read", "update"]
|
|
78
|
+
},
|
|
79
|
+
"functionality": null
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
On save, `validation_schema` is regenerated from `design_schema` by the types
|
|
84
|
+
API (`.framework/functions/types.ts`,
|
|
85
|
+
`.framework/functions/_shared/schema-utils.ts`) — you never write it yourself.
|
|
86
|
+
The rules that matter here: `select` fields need `options`; `title` is
|
|
87
|
+
`system: true` so it maps to the `items.title` column while `status`,
|
|
88
|
+
`priority`, and `notes` live in `items.data`; `record_permissions` is the base
|
|
89
|
+
grant evaluated on every `/api/admin-data` call, and its keys are matched
|
|
90
|
+
**verbatim** against `roles.slug` — so use real seeded slugs (`system_admin`,
|
|
91
|
+
`engineering`, `support`, …); a nonexistent or misspelled slug silently grants
|
|
92
|
+
nothing (`.framework/functions/_shared/permissions.ts`).
|
|
93
|
+
|
|
94
|
+
## Step 2 — register the app
|
|
95
|
+
|
|
96
|
+
Admin UI → **Configs → Apps → New** (or `POST /api/apps`):
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"slug": "taskboard",
|
|
101
|
+
"name": "Taskboard",
|
|
102
|
+
"route_prefix": "/taskboard",
|
|
103
|
+
"renderer": "generic",
|
|
104
|
+
"min_role": "engineering",
|
|
105
|
+
"is_active": true,
|
|
106
|
+
"nav_items": [
|
|
107
|
+
{ "id": "tasks", "label": "Tasks", "path": "tasks", "type_slug": "task" }
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`route_prefix` mounts the app at `/taskboard`; `renderer: "generic"` tells the
|
|
113
|
+
router to use `GenericAppShell`; each `nav_items` entry with a `type_slug`
|
|
114
|
+
gets list, `new`, and `:id` routes rendered from the type's views
|
|
115
|
+
(`.framework/src/components/app-shell/GenericAppShell.tsx`,
|
|
116
|
+
`GenericListPage.tsx`, `GenericDetailPage.tsx`). An app is routable when it
|
|
117
|
+
has a `route_prefix` and a renderer other than `none`
|
|
118
|
+
(`.framework/src/contexts/AppContext.tsx`).
|
|
119
|
+
|
|
120
|
+
Sign out/in (or wait for the apps registry refetch) and `/taskboard` renders
|
|
121
|
+
the Tasks list — create, edit, sort, and detail all work with zero code.
|
|
122
|
+
|
|
123
|
+
## Step 3 — add custom UI
|
|
124
|
+
|
|
125
|
+
When the generic views are not enough, switch `renderer` to `custom` and put
|
|
126
|
+
your code where the loader looks for it:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx spine-framework create-app taskboard --role engineering
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This scaffolds `custom/apps/taskboard/` with `manifest.json`, `index.tsx`
|
|
133
|
+
(a React Router stub), and `components/`, and registers the `apps` row with
|
|
134
|
+
`renderer: 'custom'` (`.framework/cli/commands/create-app.ts` — if the row
|
|
135
|
+
already exists it skips the insert). `CustomAppLoader` lazy-loads
|
|
136
|
+
`custom/apps/taskboard/index.tsx` via `import.meta.glob`
|
|
137
|
+
(`.framework/src/components/CustomAppLoader.tsx`), so edit the component, then:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm run dev:netlify # assemble runs automatically; or: npm run assemble && netlify dev
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Your app is a normal React app under the `/taskboard/*` route, inside
|
|
144
|
+
`AppWrapper`. Custom functions go in `custom/functions/` (prefix filenames
|
|
145
|
+
`custom_` — assembly hard-fails on basename collisions with framework
|
|
146
|
+
functions; see [02-project-map.md](./02-project-map.md)).
|
|
147
|
+
|
|
148
|
+
## Step 4 — CRUD via `/api/admin-data`
|
|
149
|
+
|
|
150
|
+
Custom pages use the same endpoint as the generic renderer — never write a
|
|
151
|
+
bespoke CRUD function:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { apiFetch } from '@core/lib/api' // assembled alias → .framework/src
|
|
155
|
+
|
|
156
|
+
// list
|
|
157
|
+
await apiFetch('/api/admin-data?action=list&entity=items&type_slug=task&limit=50')
|
|
158
|
+
|
|
159
|
+
// create — type_slug resolves the type; non-system fields go in `data`
|
|
160
|
+
await apiFetch('/api/admin-data?action=create', {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
headers: { 'Content-Type': 'application/json' },
|
|
163
|
+
body: JSON.stringify({
|
|
164
|
+
entity: 'items',
|
|
165
|
+
type_slug: 'task',
|
|
166
|
+
title: 'Ship the docs',
|
|
167
|
+
data: { status: 'todo', priority: 'high' }
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// update — entity + id are query params; the body is the field patch
|
|
172
|
+
await apiFetch('/api/admin-data?action=update&entity=items&id=<uuid>', {
|
|
173
|
+
method: 'PATCH',
|
|
174
|
+
headers: { 'Content-Type': 'application/json' },
|
|
175
|
+
body: JSON.stringify({ data: { status: 'doing' } })
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// remove — soft-deletes (is_active = false) unless soft=false is passed
|
|
179
|
+
await apiFetch(`/api/admin-data?action=remove&entity=items&id=<uuid>`, { method: 'DELETE' })
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`apiFetch` (`.framework/src/lib/api.ts`) attaches the Supabase Bearer token and
|
|
183
|
+
the `X-Account-Id` header; `admin-data` resolves `task` → its `type_id`,
|
|
184
|
+
stamps `design_schema`/`validation_schema` onto the new record, evaluates
|
|
185
|
+
`record_permissions` for the caller's role, writes, and fires
|
|
186
|
+
`item_created` triggers (`.framework/functions/admin-data.ts`).
|
|
187
|
+
|
|
188
|
+
## Step 5 — wire a pipeline
|
|
189
|
+
|
|
190
|
+
1. Admin UI → **Configs → Pipelines → New**: name it, `trigger_type` =
|
|
191
|
+
`event`, `stages` = e.g. a `send_notification` stage
|
|
192
|
+
(`.framework/functions/_shared/pipeline-runner.ts` has the built-in
|
|
193
|
+
`stage_type` list).
|
|
194
|
+
2. Admin UI → **Configs → Triggers → New**: `event_type` = `item_created`,
|
|
195
|
+
`pipeline_id` = the pipeline from step 1, `config.type_slug` = `task` to
|
|
196
|
+
scope it (`.framework/functions/_shared/trigger-engine.ts`).
|
|
197
|
+
3. Ensure `INTERNAL_INVOKE_SECRET` is set — trigger dispatch POSTs to the
|
|
198
|
+
`pipeline-runner-background` function and silently no-ops without it.
|
|
199
|
+
4. Create a task → the trigger queues a `pipeline_executions` row and the
|
|
200
|
+
background runner executes the stages; watch it under
|
|
201
|
+
**Observability → Executions**.
|
|
202
|
+
|
|
203
|
+
## Gaps
|
|
204
|
+
|
|
205
|
+
- **`npx spine-framework generate` was removed.** The old scaffold wrote
|
|
206
|
+
stubs to a `v2-custom/` tree with `../v2-core/...` imports and a legacy
|
|
207
|
+
`design_schema` shape (`type`/`layout` instead of `data_type`/`views`). It
|
|
208
|
+
now prints migration guidance and exits 1
|
|
209
|
+
(`.framework/cli/commands/generate.ts`). Author types in the admin UI or via
|
|
210
|
+
`/api/types` instead.
|
|
211
|
+
- **`create-app` defaults `--role member`.** `member` and `member_admin`
|
|
212
|
+
are seeded by `.framework/migrations/073_seed_member_roles.sql` (003
|
|
213
|
+
seeds `system_admin`, `engineering`, `engineering_admin`, `product`,
|
|
214
|
+
`docs`, `qa`, `devops`, `management`, `sales`, `csm`, `tam`, `support`,
|
|
215
|
+
`support_admin`), so the default is valid on current installs. On a
|
|
216
|
+
database that predates 073, pass `--role` a slug that exists in your
|
|
217
|
+
`roles` table or create the role first.
|
|
218
|
+
- **`create-app` scaffold is minimal** — a `Routes` stub only. There is no
|
|
219
|
+
generated CRUD page, `admin-data` hook, or seed block in the manifest it
|
|
220
|
+
writes; the pattern in Step 4 is the integration contract.
|
|
221
|
+
- **Generic renderer is list/detail only.** `GenericAppShell` generates routes
|
|
222
|
+
solely for nav items carrying `type_slug`; a nav item without one renders a
|
|
223
|
+
sidebar button that navigates nowhere routable. Dashboards, wizards, or
|
|
224
|
+
bespoke layouts require `renderer: 'custom'`.
|
|
225
|
+
- **No packaged example app ships in the npm package** — `custom/` is created
|
|
226
|
+
empty by `init`, so there is no reference implementation to copy inside an
|
|
227
|
+
installed project.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Glossary
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: guide
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-29
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/migrations/001_core_schema.sql
|
|
9
|
+
- .framework/migrations/004_core_rpc_and_broker.sql
|
|
10
|
+
- .framework/migrations/011_spine_system_account.sql
|
|
11
|
+
- .framework/migrations/020_schema_reconciliation.sql
|
|
12
|
+
- .framework/functions/admin-data.ts
|
|
13
|
+
- .framework/functions/_shared/principal.ts
|
|
14
|
+
- .framework/functions/_shared/permissions.ts
|
|
15
|
+
- .framework/functions/_shared/trigger-engine.ts
|
|
16
|
+
- .framework/functions/_shared/pipeline-runner.ts
|
|
17
|
+
- .framework/functions/system-cron.ts
|
|
18
|
+
- .framework/cli/lib/project-files.ts
|
|
19
|
+
- .framework/src/components/CustomAppLoader.tsx
|
|
20
|
+
- .framework/src/components/app-shell/GenericAppShell.tsx
|
|
21
|
+
- scripts/assemble.sh
|
|
22
|
+
- scripts/assemble-frontend.sh
|
|
23
|
+
- scripts/assemble-functions.sh
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Glossary
|
|
27
|
+
|
|
28
|
+
The Spine vocabulary, in dependency order. Terms in **bold** are defined
|
|
29
|
+
elsewhere on this page or in the [domain model](./03-domain-model.md).
|
|
30
|
+
|
|
31
|
+
## Identity
|
|
32
|
+
|
|
33
|
+
**account** — a tenant boundary (`public.accounts`). Every runtime record is
|
|
34
|
+
scoped to an `account_id`; accounts nest via `parent_id` with the
|
|
35
|
+
`account_paths` closure table for descendant lookups. The seeded `spine-system`
|
|
36
|
+
account is the platform root (see **scope**).
|
|
37
|
+
|
|
38
|
+
**person** — a human user (`public.people`), linked to Supabase `auth.users`
|
|
39
|
+
by `auth_uid` and placed in one account with one role. Non-first,
|
|
40
|
+
non-invited signups have no account until registration placement assigns one.
|
|
41
|
+
|
|
42
|
+
**principal** — the resolved identity attached to a request (`ctx.principal`),
|
|
43
|
+
computed per call by `.framework/functions/_shared/principal.ts`. One of:
|
|
44
|
+
`human` (Bearer JWT → person), `machine` (`x-api-key` header → API key, or
|
|
45
|
+
internal cron/trigger principal), `system` (internal invoke), or `anonymous`.
|
|
46
|
+
Carries `id`, `type`, `accountId`, `roles`, `scopes`, and provenance.
|
|
47
|
+
|
|
48
|
+
**role** — a named permission set (`public.roles`, unique `slug`) assigned to
|
|
49
|
+
a person. Roles are referenced throughout `design_schema.record_permissions`.
|
|
50
|
+
`system_admin` is the seeded superuser role; roles ending in `_admin` can
|
|
51
|
+
manage invites/members within their own account.
|
|
52
|
+
|
|
53
|
+
## Schema
|
|
54
|
+
|
|
55
|
+
**type** — the schema definition for a record kind (`public.types`), unique
|
|
56
|
+
per `(kind, slug)`. Carries `design_schema` (generated into
|
|
57
|
+
`validation_schema`), `ownership` (`system` | `app` | `tenant`), `icon`,
|
|
58
|
+
`color`, `is_active`.
|
|
59
|
+
|
|
60
|
+
**design_schema** — the authoring-format JSON on a type: `fields`, `views`,
|
|
61
|
+
`record_permissions`, `scope`, `functionality`. See [types](../types.md) and
|
|
62
|
+
the worked example in [04-first-app.md](./04-first-app.md).
|
|
63
|
+
|
|
64
|
+
**validation_schema** — the runtime-format schema derived from
|
|
65
|
+
`design_schema` on every save by `.framework/functions/types.ts` /
|
|
66
|
+
`.framework/functions/_shared/schema-utils.ts`. Read-only; used to validate
|
|
67
|
+
record writes.
|
|
68
|
+
|
|
69
|
+
**kind** — which runtime table a type governs: `item`, `thread`, `message`,
|
|
70
|
+
`link`, `attachment`, `watcher`, `account`, `person` (the `ENTITY_TO_KIND`
|
|
71
|
+
map in `.framework/functions/admin-data.ts`).
|
|
72
|
+
|
|
73
|
+
**runtime record** — a row in one of the typed tables (`items`, `threads`,
|
|
74
|
+
`messages`, `links`, `attachments`, `watchers`, `accounts`, `people`). Always
|
|
75
|
+
has `type_id`, `account_id`, `data` jsonb, and the `design_schema`/
|
|
76
|
+
`validation_schema` stamped at creation.
|
|
77
|
+
|
|
78
|
+
**system field** — a `design_schema` field flagged `system: true`, stored as
|
|
79
|
+
a real table column and read as `record.<field>` (e.g. `title` →
|
|
80
|
+
`items.title`). Non-system fields live in `data` and read as
|
|
81
|
+
`record.data.<field>` (split implemented in
|
|
82
|
+
`.framework/src/components/app-shell/GenericDetailPage.tsx`).
|
|
83
|
+
|
|
84
|
+
## Apps
|
|
85
|
+
|
|
86
|
+
**app** — a registered application (`public.apps`): `slug`, `route_prefix`,
|
|
87
|
+
`renderer`, `nav_items`, `min_role`/`required_roles`, `config`, `is_active`,
|
|
88
|
+
`is_system`. Appears in the authenticated router when it has a
|
|
89
|
+
`route_prefix` and `renderer != 'none'`
|
|
90
|
+
(`.framework/src/contexts/AppContext.tsx`).
|
|
91
|
+
|
|
92
|
+
**renderer** — how an app's UI is produced. `generic` = schema-driven shell
|
|
93
|
+
(`GenericAppShell` renders `nav_items` → list/detail pages from type views).
|
|
94
|
+
`custom` = lazy-loaded React entry (`custom/apps/<slug>/index.tsx`, falling
|
|
95
|
+
back to `.framework/src/apps/<slug>/index.tsx`) via
|
|
96
|
+
`.framework/src/components/CustomAppLoader.tsx`. `none` = registry-only, not
|
|
97
|
+
routed.
|
|
98
|
+
|
|
99
|
+
**manifest** — two meanings, both frozen JSON contracts: (a) an app
|
|
100
|
+
`manifest.json` in `custom/apps/<slug>/` declaring routes, `nav_items`,
|
|
101
|
+
`required_roles`, `registration`, and a `seed` block consumed by
|
|
102
|
+
`install-app`/`seed-app`/`update-db-app`
|
|
103
|
+
(`.framework/cli/commands/install-app.ts`); (b) `.spine-manifest.json`, the
|
|
104
|
+
project's frozen integrity manifest of per-file sha256 hashes
|
|
105
|
+
(`.framework/cli/lib/project-files.ts`).
|
|
106
|
+
|
|
107
|
+
## Automation
|
|
108
|
+
|
|
109
|
+
**pipeline** — a multi-step workflow (`public.pipelines`, `stages` jsonb)
|
|
110
|
+
executed by `runPipeline` in
|
|
111
|
+
`.framework/functions/_shared/pipeline-runner.ts`. Each stage's `stage_type`
|
|
112
|
+
maps to a `public.actions` row or a built-in handler (`http_request`,
|
|
113
|
+
`send_notification`, `agent_inference`, `query_items`, …).
|
|
114
|
+
|
|
115
|
+
**trigger** — an event subscription (`public.triggers`): `event_type` +
|
|
116
|
+
`pipeline_id` + optional `config` filters. `admin-data` emits
|
|
117
|
+
`<entity>_<created|updated|deleted>` events (e.g. `item_created`); matching
|
|
118
|
+
triggers enqueue an execution and dispatch the pipeline via the
|
|
119
|
+
`pipeline-runner-background` function (requires `INTERNAL_INVOKE_SECRET`).
|
|
120
|
+
|
|
121
|
+
**timer** — a schedule (`public.timers`): `timer_type`
|
|
122
|
+
(`interval` | `cron` | `once`) + `pipeline_id`. The `trigger-scheduler`
|
|
123
|
+
Netlify scheduled function (every minute, `netlify.toml`) runs `system-cron`,
|
|
124
|
+
which runs due timers through `runPipeline` under a `timer:*` principal.
|
|
125
|
+
|
|
126
|
+
**integration** — a named external connection (`public.integrations`):
|
|
127
|
+
adapter slug + `config` + `credentials` (`env_var` reference or literal
|
|
128
|
+
`value`). Inbound webhooks arrive via `integration-routes`; outbound calls
|
|
129
|
+
via `integration-outbound` write **deliveries**.
|
|
130
|
+
|
|
131
|
+
## AI
|
|
132
|
+
|
|
133
|
+
**prompt config** — a named, versioned prompt template
|
|
134
|
+
(`public.prompt_configs`) referenced by AI agents and pipeline stages.
|
|
135
|
+
|
|
136
|
+
**AI agent** — a reusable model + prompt + tool configuration
|
|
137
|
+
(`public.ai_agents`), invocable via `/api/ai-agents?action=run` or the
|
|
138
|
+
`agent_inference` pipeline stage.
|
|
139
|
+
|
|
140
|
+
**embedding** — a pgvector embedding (`public.embeddings`) queried through
|
|
141
|
+
the `match_embeddings`/`search_similar_embeddings` RPCs; backs semantic
|
|
142
|
+
search and knowledge stages.
|
|
143
|
+
|
|
144
|
+
## Access and delivery
|
|
145
|
+
|
|
146
|
+
**API key** — a machine credential (`public.api_keys`) presented as the
|
|
147
|
+
`x-api-key` header; resolved by prefix and verified against a stored hash
|
|
148
|
+
(`.framework/functions/_shared/principal.ts`,
|
|
149
|
+
`.framework/functions/_shared/hash-api-key.ts`). Has `rate_limit` and usage
|
|
150
|
+
logged in `api_key_usage_logs`.
|
|
151
|
+
|
|
152
|
+
**delivery** — an outbound delivery attempt record
|
|
153
|
+
(`public.webhook_deliveries`) written by `integration-outbound`; retried by
|
|
154
|
+
`retry-deliveries` inside `system-cron`. See [deliveries](../deliveries.md).
|
|
155
|
+
|
|
156
|
+
**execution** — a run record: `pipeline_executions` for pipelines,
|
|
157
|
+
`trigger_executions` for trigger fires, `schedule_executions` for scheduled
|
|
158
|
+
actions. Statuses progress `queued` → `running` → `completed`/`failed`.
|
|
159
|
+
|
|
160
|
+
**audit log** — privileged-action events written by `emitAudit`
|
|
161
|
+
(`.framework/functions/_shared/audit.ts`) plus the `public.logs` stream —
|
|
162
|
+
e.g. `trigger.fired`, `app.created`, `app.version_updated`.
|
|
163
|
+
|
|
164
|
+
## Project layout
|
|
165
|
+
|
|
166
|
+
**scope** — `design_schema.scope`: `account` (records belong to the caller's
|
|
167
|
+
tenant, the default) or `platform` (`admin-data` re-anchors created records
|
|
168
|
+
to the `spine-system` account).
|
|
169
|
+
|
|
170
|
+
**assembled** — `.assembled/`, the generated build tree:
|
|
171
|
+
`.assembled/src` (framework frontend + verbatim `custom/apps/<slug>/`) and
|
|
172
|
+
`.assembled/netlify/functions` (flattened functions for Netlify), produced by
|
|
173
|
+
`npm run assemble` (`scripts/assemble.sh`).
|
|
174
|
+
|
|
175
|
+
**`.framework/`** — the sealed, framework-owned tree vendored into your
|
|
176
|
+
project. Checksummed in `.spine-manifest.json`; overwritten by
|
|
177
|
+
`npx spine-framework upgrade`. See
|
|
178
|
+
[02-project-map.md](./02-project-map.md).
|
|
179
|
+
|
|
180
|
+
**CIL** — the Code Intelligence Layer: Spine's code-intelligence subsystem
|
|
181
|
+
(ingested code chunks, embeddings, and a searchable project graph) surfaced
|
|
182
|
+
under the admin `cil` pages (`.framework/src/pages/admin/cil/`). Optional;
|
|
183
|
+
your apps do not depend on it.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Integrations
|
|
3
|
+
audience: both
|
|
4
|
+
kind: entity
|
|
5
|
+
verified_against: e13127d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/functions/integrations.ts
|
|
9
|
+
- .framework/functions/integration-outbound.ts
|
|
10
|
+
- .framework/functions/integration-routes.ts
|
|
11
|
+
- .framework/functions/_shared/resolve-credentials.ts
|
|
12
|
+
- .framework/src/pages/admin/IntegrationsPage.tsx
|
|
13
|
+
- .framework/src/pages/admin/IntegrationDetailPage.tsx
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## What this is for
|
|
17
|
+
|
|
18
|
+
An **integration** connects Spine to an external service (OpenAI, Resend, a generic HTTP endpoint, a database, ...). The record stores the provider, runtime `config` (including which adapter handles calls), and `credentials`. Pipelines and app code reference the integration by slug.
|
|
19
|
+
|
|
20
|
+
## Fields and settings
|
|
21
|
+
|
|
22
|
+
- **Name** *(required)* — display name. The slug is **derived from it** server-side (`OpenAI` → `openai`); pass `slug` in the body only to override.
|
|
23
|
+
- **Type** *(required)* — select: `webhook`, `api`, `database`, `file`, `custom`. Categorizes the integration; the create form pre-fills sensible `config`/`credentials` templates per type.
|
|
24
|
+
- **Provider** *(required)* — free-text provider name (e.g. `openai`, `resend`, `postgres`).
|
|
25
|
+
- **Version** — string, default `1.0.0`.
|
|
26
|
+
- **Config (JSON)** — adapter and runtime settings. The adapter is named **here**, not as a top-level field: `config.outbound_adapter` (or `config.inbound_adapter` for inbound webhooks) points at an adapter module such as `adapters/openai-outbound`.
|
|
27
|
+
- **Credentials (JSON)** — secrets keyed by field name, each `{ "source": "env_var" | "value", "value": "..." }`. `source: "env_var"` resolves the named env var inside the function runtime; `source: "value"` stores the literal secret in the DB. The credential field callers read defaults to `api_token`.
|
|
28
|
+
- **Configured** — computed, read-only. `is_configured` is re-derived on every save from `credentials` (all entries must resolve); the UI shows it as Configured/Pending.
|
|
29
|
+
- **App ID** — select, optional. Owning app; blank = account-scoped.
|
|
30
|
+
- **Active** — boolean. Inactive integrations fail closed — callers get an error, not a fallback.
|
|
31
|
+
- **Description / Metadata** — optional notes and free-form data.
|
|
32
|
+
|
|
33
|
+
**Downstream effects**
|
|
34
|
+
|
|
35
|
+
- `env_var` credentials are resolved inside the function runtime — the variable must exist in the deployed env or calls fail at request time (`credential_env_missing`), not at save time. `source: "value"` persists the literal secret — prefer `env_var` for anything real.
|
|
36
|
+
- An absent or explicitly-empty (`source: "value"`, `value: ""`) credential entry means "call without auth" — the outbound broker sends no credential and the adapter decides whether one is required (the seeded `generic-http` integration works unauthenticated out of the box this way).
|
|
37
|
+
- Built-in outbound adapters: `adapters/openai-outbound`, `adapters/generic-webhook-outbound`, `adapters/resend-outbound`. Any other adapter path is dynamically imported — a typo saves fine but fails on first call.
|
|
38
|
+
- Outbound calls create a `webhook_deliveries` row (`pending`, `max_attempts` default 3 or `config.retry_policy.max_attempts`) and show up under Deliveries.
|
|
39
|
+
- Apps declare `integration_deps`; installing an app without its integrations leaves features broken until the records exist.
|
|
40
|
+
- The list/detail APIs use `adminDb` for system admins — integrations exist per account and per system scope.
|
|
41
|
+
|
|
42
|
+
## Minimal configuration
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"name": "OpenAI",
|
|
47
|
+
"integration_type": "api",
|
|
48
|
+
"provider": "openai",
|
|
49
|
+
"is_active": true,
|
|
50
|
+
"config": {
|
|
51
|
+
"outbound_adapter": "adapters/openai-outbound",
|
|
52
|
+
"model": "gpt-4o"
|
|
53
|
+
},
|
|
54
|
+
"credentials": { "api_token": { "source": "env_var", "value": "OPENAI_API_KEY" } }
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Full configuration
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"name": "Outbound webhook",
|
|
63
|
+
"integration_type": "api",
|
|
64
|
+
"provider": "custom",
|
|
65
|
+
"version": "1.2.0",
|
|
66
|
+
"is_active": true,
|
|
67
|
+
"config": {
|
|
68
|
+
"outbound_adapter": "adapters/generic-webhook-outbound",
|
|
69
|
+
"base_url": "https://hooks.example.com",
|
|
70
|
+
"timeout_ms": 10000,
|
|
71
|
+
"retry_policy": { "max_attempts": 5 }
|
|
72
|
+
},
|
|
73
|
+
"credentials": { "api_token": { "source": "env_var", "value": "ACME_HOOK_TOKEN" } },
|
|
74
|
+
"metadata": { "owner": "platform" }
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Example
|
|
79
|
+
|
|
80
|
+
A support app lists `integration_deps: ["openai"]` — the AI agents resolve the `openai` integration by slug for model calls (credential field `api_token`), and a second integration (`config.outbound_adapter: "adapters/generic-webhook-outbound"`) delivers outbound ticket events, each attempt logged under Deliveries.
|
|
81
|
+
|
|
82
|
+
## Core files
|
|
83
|
+
|
|
84
|
+
- `.framework/functions/integrations.ts` — API (list/get/create/update; `is_configured` computed on write; non-admin reads are sanitized)
|
|
85
|
+
- `.framework/functions/integration-outbound.ts` — outbound broker (adapter registry, delivery rows, retry math)
|
|
86
|
+
- `.framework/functions/integration-routes.ts` — inbound webhook entry
|
|
87
|
+
- `.framework/functions/_shared/resolve-credentials.ts` — `env_var`/`value` credential resolution
|
|
88
|
+
- `.framework/src/pages/admin/IntegrationsPage.tsx` / `IntegrationDetailPage.tsx` — admin UI (per-type config templates on the detail form)
|
|
89
|
+
- Table: `public.integrations`
|
|
90
|
+
|
|
91
|
+
## Agent notes
|
|
92
|
+
|
|
93
|
+
- Credentials shape is `{ "api_token": { "source": "env_var", "value": "OPENAI_API_KEY" } }` — nested `source`/`value` objects, not `{ "env_var": "..." }`. The latter saves but never resolves.
|
|
94
|
+
- Never put real secrets in `credentials.*.value` with `source: "value"` in seeds or docs — always `env_var`.
|
|
95
|
+
- There is no top-level `adapter` or `configuration` column — the field is `config`, and the adapter lives at `config.outbound_adapter` / `config.inbound_adapter`.
|
|
96
|
+
- After changing credentials, the broker picks them up on the next call — no cache flush needed.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "CIL markers and generated doc tags"
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: reference
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-29
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/functions/_shared/pipeline-runner.ts
|
|
9
|
+
- .framework/scripts/cil-migrate-markers.ts
|
|
10
|
+
- AGENTS.md
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# CIL markers and generated doc tags
|
|
14
|
+
|
|
15
|
+
Files throughout `.framework/` — `src`, `functions`, `cli`, `migrations` —
|
|
16
|
+
carry dense comment blocks that look like this:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// CIL[BEGIN stable_id="~/.framework/functions/_shared/pipeline-runner.ts:isuuid:function" type="function" identity="isUuid" parent="~/.framework/functions/_shared/pipeline-runner.ts"]
|
|
20
|
+
// CIL[DOC-MACRO purpose="isUuid function"]
|
|
21
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
|
|
22
|
+
function isUuid(v: string | undefined | null): v is string { ... }
|
|
23
|
+
// CIL[END stable_id="~/.framework/functions/_shared/pipeline-runner.ts:isuuid:function"]
|
|
24
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
and generated JSDoc like this:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
/**
|
|
31
|
+
* Validates whether a given string is a properly formatted UUID.
|
|
32
|
+
* @inputSpec - v: string — the value to be checked
|
|
33
|
+
* @outputSpec v is string — true if the value is a valid UUID
|
|
34
|
+
* @sideEffects none
|
|
35
|
+
* @stability stable
|
|
36
|
+
* @calls UUID_RE.test
|
|
37
|
+
* @cil-generated
|
|
38
|
+
*/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## What they are
|
|
42
|
+
|
|
43
|
+
**CIL** (Code Intelligence Layer) is the repository's internal
|
|
44
|
+
code-indexing tooling — it chunks the codebase into addressable units,
|
|
45
|
+
attaches generated documentation, and keeps embeddings in sync for semantic
|
|
46
|
+
search inside the monorepo. The comments are its on-disk metadata:
|
|
47
|
+
|
|
48
|
+
- `// CIL[BEGIN ...]` / `// CIL[END ...]` — delimit one tracked code chunk.
|
|
49
|
+
`stable_id` is the chunk's durable identity
|
|
50
|
+
(`<file>:<slug>:<kind>`); `type`, `identity`, and `parent` describe it.
|
|
51
|
+
- `// CIL[DOC-* …]` — generated or curated facts about the chunk:
|
|
52
|
+
`DOC-MACRO` (purpose), `DOC-RESPONSIBILITY`, `DOC-CONTEXT`
|
|
53
|
+
(module/layer/related files), `DOC-CONTRACT` (inputs/outputs/errors/
|
|
54
|
+
side_effects), `DOC-MICRO` (logic summary, notable decisions),
|
|
55
|
+
`DOC-CONFIDENCE` (pass + score), `DOC-STABILITY`, `DOC-AUDIENCE`,
|
|
56
|
+
`DOC-PARAM`, `DOC-NOTE`, and `DOC-LEARNING`.
|
|
57
|
+
- `// CIL[DOC-VECTOR type="…" content="…" status="…"]` — the payload that
|
|
58
|
+
becomes a search embedding (types include `context`, `blast_radius`,
|
|
59
|
+
`constraint`, `configuration`, `implementation_pattern`, `user_journey`).
|
|
60
|
+
`status="ready"` means it was generated; **`status="pending_human_input"`
|
|
61
|
+
means the field is intentionally blank until an author fills it** — it is
|
|
62
|
+
not an error and not a warning about the code itself.
|
|
63
|
+
- JSDoc tags `@macro`, `@micro`, `@inputSpec`, `@outputSpec`, `@sideEffects`,
|
|
64
|
+
`@calls`, `@seeAlso`, `@errorHandling`, `@stability`, `@module`, `@layer`,
|
|
65
|
+
`@audience`, `@cil-generated` mirror the same metadata in human-readable
|
|
66
|
+
form; `@cil-generated` marks text written by the pipeline rather than a
|
|
67
|
+
person.
|
|
68
|
+
|
|
69
|
+
## What they mean for you
|
|
70
|
+
|
|
71
|
+
- **Safe to ignore.** They are comments; they have no runtime effect, no API
|
|
72
|
+
surface, and no effect on how you build apps on Spine. CIL is maintainer
|
|
73
|
+
tooling, not a framework feature.
|
|
74
|
+
- **Read them as hints, not truth.** `DOC-*` summaries and JSDoc are
|
|
75
|
+
generated interpretation — usually accurate, occasionally stale. The code
|
|
76
|
+
is the authority; treat the tags like any other doc comment.
|
|
77
|
+
- **In framework files, leave them in place.** Editing or deleting markers by
|
|
78
|
+
hand is harmless locally but gets rebuilt/renumbered the next time the
|
|
79
|
+
repo's marker tooling runs (see `cil:migrate-markers` /
|
|
80
|
+
`.framework/scripts/cil-migrate-markers.ts`). In your own `custom/` code
|
|
81
|
+
you're free to add or omit them — nothing requires them.
|
|
82
|
+
- The contributor-facing conventions live in the repo's `AGENTS.md`; this
|
|
83
|
+
page is only the legend for readers who meet the markers in shipped source.
|