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,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.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Invites & Access
|
|
3
|
+
audience: both
|
|
4
|
+
kind: entity
|
|
5
|
+
verified_against: e13127d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/src/pages/admin/InvitesPage.tsx
|
|
9
|
+
- .framework/src/components/shared/InviteManager.tsx
|
|
10
|
+
- .framework/functions/invites.ts
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What this is for
|
|
14
|
+
|
|
15
|
+
**Invites & Access** (`/spine-framework/admin/access/invites`) manages how people join the account: generating invite links, tracking their status, re-sending or revoking them, and approving access requests. The admin page is scoped to the `system_admin` role; the shared `InviteManager` component underneath supports other role sets.
|
|
16
|
+
|
|
17
|
+
## Fields and settings
|
|
18
|
+
|
|
19
|
+
- **Generate invite form** — name, email, and role picker (shown only when more than one role is allowed; here it is fixed to `system_admin`). Produces an `invite_url` copied to the clipboard: `{APP_BASE_URL}/register?t=<invite_token>`.
|
|
20
|
+
- **Invites table** — the person's name/email, assigned role, status, and actions: reinvite (new link), revoke, approve (access requests), block.
|
|
21
|
+
- **Status semantics** — `invited`/`pending` (link issued or request awaiting approval), `approved`, `active`/`claimed` (registered), `revoked` (`inactive`), `expired`, `blocked`. `kind` distinguishes `invite` from `access_request`.
|
|
22
|
+
- **Search + sortable columns** over the list from `action=list-invites` (filtered to the allowed role slugs).
|
|
23
|
+
|
|
24
|
+
**Downstream effects**
|
|
25
|
+
|
|
26
|
+
- `create-invite` inserts a stub `people` row carrying `invite_token` (16 chars) and `invite_expires_at` (7 days); the register flow consumes the token via `complete-registration` → `complete_registration_placement` RPC.
|
|
27
|
+
- Only `system_admin` (or an `*_admin` role on the account) can create invites; creating an invite for `role_slug: system_admin` is refused unless the caller is already `system_admin`.
|
|
28
|
+
- `revoke-invite` marks the person `inactive`, killing the unclaimed link; `reinvite` mints a fresh token/link. `block-invite`/`deny` handle abusive requests.
|
|
29
|
+
- Registration and account-creation calls are rate-limited per person and per IP.
|
|
30
|
+
|
|
31
|
+
## Minimal configuration
|
|
32
|
+
|
|
33
|
+
Fill name + email → Generate → the invite URL lands on your clipboard; send it out of band. The invitee registers within 7 days or you reinvite.
|
|
34
|
+
|
|
35
|
+
## Full configuration
|
|
36
|
+
|
|
37
|
+
The backing API (`/.netlify/functions/invites?action=`) also covers the public registration path and member management:
|
|
38
|
+
|
|
39
|
+
- `check-first-user`, `check-domain`, `validate-token`, `complete-registration` — anonymous signup flow
|
|
40
|
+
- `create-invite`, `list-invites`, `revoke-invite`, `reinvite`, `block-invite`
|
|
41
|
+
- `approve`, `deny` — access-request review
|
|
42
|
+
- `list-members`, `update-member`, `deactivate-member` — existing members
|
|
43
|
+
|
|
44
|
+
## Example
|
|
45
|
+
|
|
46
|
+
An admin generates a `system_admin` invite for a new hire, pastes the link into chat. Until they register, the row shows `pending`; if the link is lost, Reinvite mints a new URL and invalidates the old token; if they never join, Revoke marks the stub `inactive`.
|
|
47
|
+
|
|
48
|
+
## Core files
|
|
49
|
+
|
|
50
|
+
- `.framework/src/pages/admin/InvitesPage.tsx` — this page (scopes InviteManager to `system_admin`)
|
|
51
|
+
- `.framework/src/components/shared/InviteManager.tsx` — invite list/form/actions (reusable in other apps)
|
|
52
|
+
- `.framework/functions/invites.ts` — API (all actions above)
|
|
53
|
+
- Table: `public.people` (invite stub rows carry `invite_token`/`invite_expires_at`)
|
|
54
|
+
|
|
55
|
+
## Agent notes
|
|
56
|
+
|
|
57
|
+
- The invite URL is shown/copied **once** at create/reinvite — the API never returns it again; a lost link means Reinvite, not retrieve.
|
|
58
|
+
- Invites expire after 7 days (`invite_expires_at`); expired rows show `expired` until reinvited or revoked.
|
|
59
|
+
- This admin page is hardcoded to `system_admin` invites; app-level member invites use the same `InviteManager` with a different `allowedRoles` set.
|
|
60
|
+
- Stub invite rows are real `people` rows — they are excluded from normal principal resolution until registration completes.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Knowledge Base
|
|
3
|
+
audience: both
|
|
4
|
+
kind: entity
|
|
5
|
+
verified_against: e13127d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/src/pages/admin/kb/KBAdminPage.tsx
|
|
9
|
+
- .framework/src/components/kb/KBArticleList.tsx
|
|
10
|
+
- .framework/src/components/kb/KBArticleEditor.tsx
|
|
11
|
+
- .framework/src/pages/admin/EmbeddingsPage.tsx
|
|
12
|
+
- .framework/src/pages/admin/EmbeddingDetailPage.tsx
|
|
13
|
+
- .framework/functions/kb.ts
|
|
14
|
+
- .framework/functions/embeddings.ts
|
|
15
|
+
- .framework/functions/admin-data.ts
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## What this is for
|
|
19
|
+
|
|
20
|
+
The **KB** section (`/spine-framework/admin/kb/*`) covers three surfaces that share this doc:
|
|
21
|
+
|
|
22
|
+
- `kb/:typeSlug` — the article admin list/editor (`KBAdminPage`) for the KB item types `kb-spine-admin`, `kb-spine-internal`, `kb-spine-public`, `kb-account`. Articles are `items` records created/edited via `admin-data` and published via `kb`.
|
|
23
|
+
- `kb/embeddings` — the embedding record browser (`EmbeddingsPage`): every generated embedding row with its approval state.
|
|
24
|
+
- `kb/embeddings/:id` — single embedding detail (`EmbeddingDetailPage`): content, vector type, chunk index, model, approval/revocation timestamps, optional raw vector.
|
|
25
|
+
|
|
26
|
+
## Fields and settings
|
|
27
|
+
|
|
28
|
+
**Articles** (`KBArticleList` / `KBArticleEditor`)
|
|
29
|
+
|
|
30
|
+
- **Type slug tabs** — the four KB type slugs above; articles are `items` records of that type.
|
|
31
|
+
- **List** — title, status, created date; search hits `/api/kb?action=search` (sources `['kb']`).
|
|
32
|
+
- **Editor** — schema-driven form from the type's `design_schema` (main fields + metadata sidebar); Save writes `admin-data` create/update; **Publish** additionally calls `/api/kb?action=publish`; Delete uses `admin-data` remove.
|
|
33
|
+
- **Modes** — `view` (read-only), `edit`, `new` via route (`:id`, `:id/edit`, `new`).
|
|
34
|
+
|
|
35
|
+
**Embeddings** (`EmbeddingsPage` / `EmbeddingDetailPage`)
|
|
36
|
+
|
|
37
|
+
- **List** — content/document/model search + sortable columns; status badge: `Revoked` (revoked_at set) > `Approved` (approved_at set) > `Pending`.
|
|
38
|
+
- **Detail** — document_id, vector_type, chunk_index, model_id, token count, content preview, approved/revoked timestamps, and a show-vector toggle for the raw embedding.
|
|
39
|
+
|
|
40
|
+
**Downstream effects**
|
|
41
|
+
|
|
42
|
+
- Articles are plain `items` records — they inherit the type's `record_permissions` and `validation_schema`; `kb?action=publish` handles the publishing step (ingest/indexing) on top.
|
|
43
|
+
- Embeddings are generated per type `design_schema.vector_types` (default `['semantic','structure']`) and feed `match_embeddings`/semantic search used by agents and `search_knowledge` pipeline stages.
|
|
44
|
+
- `embeddings` actions: list/get/create/update + `generate`, `revoke`, `approve`, `stats`, `batch-create`, `delete-document`, `cleanup`, `search-similar`, `search-semantic`. `revoke` stamps `revoked_at` (excluded from search); `approve` stamps `approved_at` and clears revocation.
|
|
45
|
+
|
|
46
|
+
## Minimal configuration
|
|
47
|
+
|
|
48
|
+
Pick a KB type slug tab → New → fill the schema form → Save → Publish. The article is now searchable via `kb?action=search`.
|
|
49
|
+
|
|
50
|
+
## Full configuration
|
|
51
|
+
|
|
52
|
+
```jsonc
|
|
53
|
+
// article write — POST /api/admin-data?entity=items
|
|
54
|
+
{ "type_id": "kb-account", "title": "Refund policy", "data": { "body": "..." } }
|
|
55
|
+
// publish — POST /api/kb?action=publish { "id": "<article uuid>" }
|
|
56
|
+
// regenerate vectors — POST /api/embeddings?action=generate { "item_id": "<article uuid>" }
|
|
57
|
+
// curate — POST /api/embeddings?action=approve|revoke { "id": "<embedding uuid>" }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Example
|
|
61
|
+
|
|
62
|
+
A support team writes refund-policy articles under `kb-account`, publishes them, then checks `kb/embeddings` — the new chunks show `Pending` until reviewed; approving the good ones and revoking a stale `semantic` chunk changes what `search_knowledge` returns to the reply-drafting agent.
|
|
63
|
+
|
|
64
|
+
## Core files
|
|
65
|
+
|
|
66
|
+
- `.framework/src/pages/admin/kb/KBAdminPage.tsx` — article page shell (list vs editor by mode)
|
|
67
|
+
- `.framework/src/components/kb/KBArticleList.tsx` / `KBArticleEditor.tsx` — list + schema-driven editor, publish call
|
|
68
|
+
- `.framework/src/pages/admin/EmbeddingsPage.tsx` / `EmbeddingDetailPage.tsx` — embedding browser/detail
|
|
69
|
+
- `.framework/functions/kb.ts` — `search`, `publish`, and KB pipeline actions
|
|
70
|
+
- `.framework/functions/embeddings.ts` — embedding CRUD + generate/approve/revoke/search
|
|
71
|
+
- `.framework/functions/admin-data.ts` — the underlying record CRUD
|
|
72
|
+
- Tables: `public.items` (articles), `public.embeddings` (vectors)
|
|
73
|
+
|
|
74
|
+
## Agent notes
|
|
75
|
+
|
|
76
|
+
- `instructionKeyFor` maps every `kb/*` route to this doc — there is no separate `embeddings` page key.
|
|
77
|
+
- Articles are records, not files — edit them through this UI or `admin-data`, never direct table writes that skip validation/triggers.
|
|
78
|
+
- `Pending` embeddings still count toward `stats`; only `revoked_at` removes a vector from similarity search.
|
|
79
|
+
- Deleting an article does not cascade to its embedding rows — use `embeddings?action=delete-document` to clean up vectors for a removed document.
|
|
80
|
+
- Re-publish after large edits: publishing re-ingests; stale chunks otherwise linger until `generate`/`cleanup` runs.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Logs
|
|
3
|
+
audience: both
|
|
4
|
+
kind: entity
|
|
5
|
+
verified_against: e13127d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/src/pages/admin/LogsPage.tsx
|
|
9
|
+
- .framework/functions/logs.ts
|
|
10
|
+
- .framework/functions/_shared/logging.ts
|
|
11
|
+
- .framework/functions/system-cron.ts
|
|
12
|
+
- .framework/migrations/069_log_stats_window.sql
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What this is for
|
|
16
|
+
|
|
17
|
+
**Logs** (`/spine-framework/admin/observability/logs`) is the account's audit-trail and event-history viewer — every `emitLog`/`emitAudit`/`emitSpan`/`emitActivity` write lands in the `logs` table and shows up here. Use it to trace a request end-to-end (via `trace_id`), answer "who did what when", and debug trigger/pipeline/delivery failures.
|
|
18
|
+
|
|
19
|
+
## Fields and settings
|
|
20
|
+
|
|
21
|
+
- **Stats cards** — Total Events, Event Types, Errors, User Actions over the current filter window (`/api/logs?action=stats`).
|
|
22
|
+
- **Search** — free text over message/actor fields; debounced 300ms.
|
|
23
|
+
- **Level** — `event_type` of the log row (error/audit/span/activity categories surface as selectable values from the stats payload).
|
|
24
|
+
- **Source / Source Type** — `action` and `target_type` of the row (e.g. `type.updated`, `item`).
|
|
25
|
+
- **Source ID / Actor ID / Trace ID** — UUID/prefix filters: `target_id`, `actor_id`, `trace_id`.
|
|
26
|
+
- **From / To dates** — `date_from`/`date_to`; defaults to the last 24h. Stats default to a 7-day window when no `date_from` is given.
|
|
27
|
+
- **Row click** — expands the row to show `details`, `metadata`, span info (`span_name`, `span_id`, `parent_span_id`, `duration_ms`, `outcome`).
|
|
28
|
+
- **Trace button** — clicking a `trace_id` filters the whole grid to that trace (all spans of one request).
|
|
29
|
+
- Paged at 100 rows per page; sortable columns (Time, Trace, Level, Source, Source Type, Source ID, Person, Message).
|
|
30
|
+
|
|
31
|
+
**Downstream effects**
|
|
32
|
+
|
|
33
|
+
- What gets written is gated by `system_settings` key `logging`: levels `off | timing | warnings | errors | all` (default `['timing','errors']`). Rows at unconfigured levels are dropped at write time — they never reach this page.
|
|
34
|
+
- Retention is `cleanup` with `days_to_keep` (default 30); `system-cron` runs `cleanup_old_logs` at 00:00 UTC. Debugging a week-old issue? Check before it ages out.
|
|
35
|
+
- `logs` is also a queryable `admin-data` entity, so pipelines and agents can read the same rows.
|
|
36
|
+
- The Observability dashboard and Security page both read this table (`threshold.breached` events, security signals).
|
|
37
|
+
|
|
38
|
+
## Minimal configuration
|
|
39
|
+
|
|
40
|
+
Nothing to configure on the page itself. To see useful data, ensure the account's `system_settings.logging.levels` includes the level you need (e.g. `errors`), then filter:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Level = error · From = <incident date> · Trace ID = <trace from a failed request>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Full configuration
|
|
47
|
+
|
|
48
|
+
Combine all filters for a forensic query — e.g. every log row for one record by one person in a window:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
query = "ticket"
|
|
52
|
+
target_type = "items" · source_id = "<record uuid>"
|
|
53
|
+
actor_id = "<person uuid>" · trace_id = "<trace uuid>"
|
|
54
|
+
date_from = 2026-10-01 · date_to = 2026-10-30
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
API equivalents: `/api/logs?action=account` (paged rows), `action=stats`, plus `target`, `person`, `search`, `cleanup` actions server-side.
|
|
58
|
+
|
|
59
|
+
## Example
|
|
60
|
+
|
|
61
|
+
A user reports a failed save at 14:03. Open Logs, set From to that day, paste the `trace_id` from the error toast into Trace ID — the grid now shows the request's full span tree (`api.request` → `db.update` → `trigger.fired`), and the red `error` row's expanded `details` names the failing stage.
|
|
62
|
+
|
|
63
|
+
## Core files
|
|
64
|
+
|
|
65
|
+
- `.framework/src/pages/admin/LogsPage.tsx` — this page
|
|
66
|
+
- `.framework/functions/logs.ts` — API (`account`, `target`, `person`, `stats`, `search`, `cleanup` actions)
|
|
67
|
+
- `.framework/functions/_shared/logging.ts` — `emitLog`, level resolution from `system_settings`
|
|
68
|
+
- `.framework/functions/_shared/audit.ts` / `.framework/functions/_shared/tracing.ts` — `emitAudit`/`emitSpan` writers, W3C trace context
|
|
69
|
+
- `.framework/functions/system-cron.ts` — daily `cleanup_old_logs` at 00:00 UTC
|
|
70
|
+
- Table: `public.logs`
|
|
71
|
+
|
|
72
|
+
## Agent notes
|
|
73
|
+
|
|
74
|
+
- Empty page with active traffic almost always means log **levels** filter writes, not that nothing happened — check `system_settings.logging` first.
|
|
75
|
+
- `trace_id` is the fastest debugging primitive: every function request shares one, so one click reconstructs the whole call including trigger dispatch.
|
|
76
|
+
- System admins query across accounts via `adminDb`; everyone else sees only their account's rows.
|
|
77
|
+
- Cleanup is destructive and daily — export anything worth keeping before the 30-day default window closes.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Observability Dashboard
|
|
3
|
+
audience: both
|
|
4
|
+
kind: entity
|
|
5
|
+
verified_against: e13127d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/src/pages/admin/ObservabilityDashboard.tsx
|
|
9
|
+
- .framework/functions/observability.ts
|
|
10
|
+
- .framework/functions/logs.ts
|
|
11
|
+
- .framework/functions/_shared/logging.ts
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What this is for
|
|
15
|
+
|
|
16
|
+
The **Observability Dashboard** (`/spine-framework/admin/observability`, also `/observability/dashboard`) is the account's health console: event volume, error rate, latency percentiles, per-pipeline run stats, top actors, and recent threshold-alert breaches — all computed from the `logs` table and refreshed on an interval.
|
|
17
|
+
|
|
18
|
+
## Fields and settings
|
|
19
|
+
|
|
20
|
+
- **Time range** — Last Hour / Last 24 Hours / Last 7 Days (`from`/`to` sent to every query; the volume chart buckets by minute/hour/day respectively).
|
|
21
|
+
- **Refresh interval** — auto-refetch every 10s / 30s / 1m, plus a manual Refresh Now button.
|
|
22
|
+
- **Stats cards** — Total Events, Error Rate (%), P95 Latency (ms, red above 2000ms), Pipelines with runs.
|
|
23
|
+
- **Charts** — Event Volume line chart (bucketed counts), error rate, latency percentiles (p50/p95/p99), per-pipeline success/failure/avg-duration, Top Actors (limit 5).
|
|
24
|
+
- **Recent alerts** — last 5 `threshold.breached` log events in the window (metric, threshold, actual value, time).
|
|
25
|
+
|
|
26
|
+
**Downstream effects**
|
|
27
|
+
|
|
28
|
+
- Everything derives from `public.logs` rows written by `emitLog`/`emitAudit`/`emitSpan` — if log levels drop a category (`system_settings.logging.levels`), it disappears from these charts too.
|
|
29
|
+
- Queries are account-scoped for normal users; `system_admin` principals get cross-account reads (`adminDb`).
|
|
30
|
+
- The metrics here are exactly what threshold alerts compare against (`error_rate`, `latency_percentiles`, `pipeline_stats` actions).
|
|
31
|
+
- This page is read-only — it writes nothing.
|
|
32
|
+
|
|
33
|
+
## Minimal configuration
|
|
34
|
+
|
|
35
|
+
Open the page — defaults (24h range, 30s refresh) are sane for monitoring. There is nothing to configure.
|
|
36
|
+
|
|
37
|
+
## Full configuration
|
|
38
|
+
|
|
39
|
+
The backing API exposes more than the charts use:
|
|
40
|
+
|
|
41
|
+
- `GET /api/observability?action=event_volume&from=&to=&bucket=minute|hour|day`
|
|
42
|
+
- `action=error_rate` · `action=latency_percentiles` · `action=pipeline_stats` · `action=top_actors&limit=` · `action=ai_support_metrics` · `action=cleanup` (POST)
|
|
43
|
+
|
|
44
|
+
## Example
|
|
45
|
+
|
|
46
|
+
After deploying a new pipeline, set the range to Last Hour and refresh to 10s: Event Volume climbs with each run, the pipeline stats panel shows success vs failure counts and average duration, and a spike in the error-rate card correlates to the `error`-level rows you can drill into under Logs.
|
|
47
|
+
|
|
48
|
+
## Core files
|
|
49
|
+
|
|
50
|
+
- `.framework/src/pages/admin/ObservabilityDashboard.tsx` — this page (recharts)
|
|
51
|
+
- `.framework/functions/observability.ts` — metrics API (all `action=` queries above)
|
|
52
|
+
- `.framework/functions/logs.ts` — the `threshold.breached` alert feed (`action=account&event=`)
|
|
53
|
+
- `.framework/functions/_shared/logging.ts` — the emit path and level gating that decides what reaches `logs`
|
|
54
|
+
- Table: `public.logs` (source of all charts)
|
|
55
|
+
|
|
56
|
+
## Agent notes
|
|
57
|
+
|
|
58
|
+
- Flat charts with healthy traffic = log-level filtering, not broken metrics — the dashboard can only chart what `system_settings.logging.levels` allowed to be written.
|
|
59
|
+
- `system_admin` sees cross-account aggregates here; account members see only their own account.
|
|
60
|
+
- The 10s refresh is client-side polling — each tick re-runs all five metric queries; don't leave it open on a metered connection.
|
|
61
|
+
- Breach alerts shown here are read from `logs`, not from the alert records — see Threshold Alerts for the rules themselves.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Netlify Deployment
|
|
3
|
+
audience: both
|
|
4
|
+
kind: reference
|
|
5
|
+
verified_against: e13127d
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- netlify.toml
|
|
9
|
+
- .framework/public/_redirects
|
|
10
|
+
- scripts/assemble.sh
|
|
11
|
+
- scripts/assemble-frontend.sh
|
|
12
|
+
- scripts/assemble-functions.sh
|
|
13
|
+
- config/vite.config.ts
|
|
14
|
+
- .env.example
|
|
15
|
+
- .framework/functions/system.ts
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Netlify Deployment
|
|
19
|
+
|
|
20
|
+
Spine deploys as a single Netlify site: a Vite-built SPA in `dist/` plus a
|
|
21
|
+
flat directory of functions in `.assembled/netlify/functions`, backed by a
|
|
22
|
+
Supabase (Postgres) project. Both halves are produced by the same build
|
|
23
|
+
command — there is no separate function deploy step.
|
|
24
|
+
|
|
25
|
+
## `netlify.toml` anatomy
|
|
26
|
+
|
|
27
|
+
The root `netlify.toml` is partly framework-owned (regenerated on
|
|
28
|
+
`npx spine-framework upgrade`, preserving `[functions."custom_*"]` sections):
|
|
29
|
+
|
|
30
|
+
| Block | Contents |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `[build]` | `command = "npm run assemble && npm run build"`, `publish = "dist"`, `functions = ".assembled/netlify/functions"` |
|
|
33
|
+
| `[build.environment]` | `SECRETS_SCAN_OMIT_KEYS` whitelists the intentionally-public vars (`VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY`, `APP_BASE_URL`, `SITE_URL`, …) so Netlify's secrets scanner does not flag them; `SECRETS_SCAN_OMIT_PATHS` covers `.framework/.xenv*` |
|
|
34
|
+
| `[functions]` | `directory = ".assembled/netlify/functions"`, `included_files` for `_shared/**`, `node_bundler = "esbuild"`, `external_node_modules = ["typescript"]` (the esbuild printer panic workaround — typescript.js ships unbundled) |
|
|
35
|
+
| `[dev]` | `netlify dev` runs `scripts/netlify-dev-wrapper.sh`, site on `8888`, Vite `targetPort` `3001`, `startTimeout 300` |
|
|
36
|
+
| `[functions."<name>"]` | per-function config: `trigger-scheduler` gets `schedule = "* * * * *"`; `cil-ingest`, `cil-embeddings`, `cil-callmap`, `cil-agent`, `ai-agents`, `kb` get `timeout` overrides |
|
|
37
|
+
| `[[redirects]]` | `/* → /index.html` with status `200` (SPA fallback) |
|
|
38
|
+
| `[[headers]]` | `X-Frame-Options DENY`, `nosniff`, HSTS, `Referrer-Policy`, `Permissions-Policy`, and a CSP that allows `*.supabase.co` (https+wss) and `challenges.cloudflare.com` (Turnstile) |
|
|
39
|
+
|
|
40
|
+
Dispatched trigger pipelines run as Netlify **background functions**
|
|
41
|
+
(`pipeline-runner-background`): the dispatcher gets a `202` immediately and
|
|
42
|
+
each run gets the fixed 15-minute background budget — which is why no
|
|
43
|
+
`timeout` entry exists for it.
|
|
44
|
+
|
|
45
|
+
## How `.assembled/` is produced
|
|
46
|
+
|
|
47
|
+
`npm run assemble` (`scripts/assemble.sh`) runs before every dev start
|
|
48
|
+
(`predev:netlify`) and every build (`prebuild`). It wipes stale `dist/`,
|
|
49
|
+
then:
|
|
50
|
+
|
|
51
|
+
1. `scripts/assemble-functions.sh` flattens `.framework/functions` plus
|
|
52
|
+
`custom/functions` and `custom/apps/*/functions` into
|
|
53
|
+
`.assembled/netlify/functions`. Basename collisions are a **hard error**
|
|
54
|
+
naming both sources — Netlify needs one flat dir, so last-wins overwrite
|
|
55
|
+
is forbidden. `_quarantine` and `*-test.ts`/`*.test.ts` are excluded.
|
|
56
|
+
2. `scripts/assemble-frontend.sh` copies `.framework/src` as the base layer,
|
|
57
|
+
each `custom/apps/<slug>` verbatim to `.assembled/src/<slug>/`, fixes up
|
|
58
|
+
`index.html`, merges `.framework/public` + app `public/` dirs into the
|
|
59
|
+
project `public/` (same-path collisions are a hard error), copies
|
|
60
|
+
`_redirects` into `.assembled/src/` for `netlify dev`, and stages the
|
|
61
|
+
project `spine.config.json` into `public/`.
|
|
62
|
+
|
|
63
|
+
`config/vite.config.ts` then builds with `root: .assembled/src`,
|
|
64
|
+
`publicDir: public/`, `build.outDir: dist/` — matching `publish = "dist"`.
|
|
65
|
+
Never edit `.assembled/`; it is regenerated freely.
|
|
66
|
+
|
|
67
|
+
## The `/api/*` URL space
|
|
68
|
+
|
|
69
|
+
Requests to `/api/*` are rewritten to `/.netlify/functions/:splat`:
|
|
70
|
+
|
|
71
|
+
- **Production:** the published `_redirects` file — sourced from
|
|
72
|
+
`.framework/public/_redirects`, merged into `public/` at assemble time —
|
|
73
|
+
carries `/api/* → /.netlify/functions/:splat 200`, plus
|
|
74
|
+
`/spine.config.json` passthrough and the `/* → /index.html` fallback.
|
|
75
|
+
- **Dev:** the Vite proxy in `config/vite.config.ts` maps `/api/*` to
|
|
76
|
+
`localhost:8888` with the same rewrite.
|
|
77
|
+
|
|
78
|
+
Because the SPA fallback is `/* → /index.html 200`, **any unmatched URL
|
|
79
|
+
returns HTTP 200 with HTML** — including typos under `/api/`. A probe that
|
|
80
|
+
gets HTML instead of JSON is hitting the SPA fallback, not a function.
|
|
81
|
+
|
|
82
|
+
## Environment variables in production
|
|
83
|
+
|
|
84
|
+
Set these in the Netlify site environment (not in `netlify.toml`).
|
|
85
|
+
The full annotated list is [Environment Variables](../reference/env-vars.md);
|
|
86
|
+
|
|
87
|
+
| Variable | Needed for |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY` | browser bundle (public by design) |
|
|
90
|
+
| `SUPABASE_URL`, `SUPABASE_ANON_KEY`, `SUPABASE_SERVICE_ROLE_KEY` | all functions — service-role key is server-only, never `VITE_`-prefixed |
|
|
91
|
+
| `INTERNAL_INVOKE_SECRET` | trigger-dispatched pipelines — unset means `queued` rows that never run |
|
|
92
|
+
| `APP_BASE_URL` | invite links, auth redirects, `base_url` allowlist |
|
|
93
|
+
| `SCHEDULER_API_KEY` | key-gated `system-cron`/`trigger-scheduler` invocation |
|
|
94
|
+
| `SITE_URL` | CORS `Access-Control-Allow-Origin`; falls back to Netlify's auto-set `URL` |
|
|
95
|
+
| `RESEND_API_KEY`, `EMAIL_FROM` | outbound email (invites, notification stages) |
|
|
96
|
+
| `OPENAI_API_KEY` | AI stage types, agents, embeddings |
|
|
97
|
+
| `NETLIFY_ACCESS_TOKEN`, `NETLIFY_SITE_ID` | optional — push banned IPs to the edge firewall (security function skips silently without them) |
|
|
98
|
+
|
|
99
|
+
`SUPABASE_DB_PASSWORD` is **not** a function env var — it is used locally by
|
|
100
|
+
`npx spine-framework migrate` to connect to Postgres directly.
|
|
101
|
+
|
|
102
|
+
## Deploy checklist
|
|
103
|
+
|
|
104
|
+
- [ ] Supabase project exists; `SUPABASE_*` + `VITE_SUPABASE_*` vars set in Netlify.
|
|
105
|
+
- [ ] `INTERNAL_INVOKE_SECRET` generated (`openssl rand -hex 32`) if triggers are used; `APP_BASE_URL`/`SITE_URL` set to the production origin.
|
|
106
|
+
- [ ] Migrations applied: `npx spine-framework migrate` against the production DB (see [Migrations](migrations.md)).
|
|
107
|
+
- [ ] Deploy via git push or `netlify deploy --prod` — the build command runs `assemble` then `vite build` automatically.
|
|
108
|
+
- [ ] Post-deploy smoke: `/api/system?action=health` and `?action=manifest` answer; first registration grants `system_admin` (see [Install and first run](../guide/01-install-and-first-run.md)).
|
|
109
|
+
- [ ] If timers/triggers are used: `trigger-scheduler` ticks appear in function logs within a minute; a test record write produces a `trigger.fired` log row.
|
|
110
|
+
|
|
111
|
+
## Related
|
|
112
|
+
|
|
113
|
+
- [Migrations](migrations.md) · [Upgrade](upgrade.md) · [Troubleshooting](troubleshooting.md)
|
|
114
|
+
- [Environment Variables](../reference/env-vars.md) · [CLI Reference](../reference/cli.md)
|
|
115
|
+
- [Anatomy of an installed project](../guide/02-project-map.md) — sealed vs customer trees
|