spine-framework 0.4.4 → 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/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/admin-data.ts +39 -28
- package/.framework/functions/ai-agents.ts +10 -6
- 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/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/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/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/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/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 +4 -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 +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/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/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,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Orientation — what Spine Framework is
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: guide
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-29
|
|
7
|
+
source_files:
|
|
8
|
+
- package.json
|
|
9
|
+
- netlify.toml
|
|
10
|
+
- .env.example
|
|
11
|
+
- .framework/cli/commands/init.ts
|
|
12
|
+
- .framework/templates/project.json
|
|
13
|
+
- .framework/src/components/admin/PageInstructions.tsx
|
|
14
|
+
- .framework/src/instructions/README.md
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Orientation
|
|
18
|
+
|
|
19
|
+
Spine Framework is a multi-tenant application platform you install into an npm
|
|
20
|
+
project. It gives you the "boring 80%" of a SaaS product — the infrastructure
|
|
21
|
+
every app needs and nobody wants to rebuild — so your code can be the
|
|
22
|
+
interesting 20%.
|
|
23
|
+
|
|
24
|
+
## What you get out of the box
|
|
25
|
+
|
|
26
|
+
- **A typed runtime data layer.** Accounts, people, and typed records (items,
|
|
27
|
+
threads, messages, links, attachments, watchers) stored in Supabase Postgres,
|
|
28
|
+
all reachable through one CRUD/permissions API (`.framework/functions/admin-data.ts`).
|
|
29
|
+
- **Auth and tenancy.** Supabase Auth for sign-in, an invite/registration
|
|
30
|
+
pipeline (`.framework/functions/invites.ts`), hierarchical accounts, and a
|
|
31
|
+
first-user bootstrap that seeds a system administrator.
|
|
32
|
+
- **RBAC.** Roles plus per-type `record_permissions` evaluated on every request
|
|
33
|
+
(`.framework/functions/_shared/permissions.ts`).
|
|
34
|
+
- **Automation.** Declarative pipelines, event triggers, timers, integrations,
|
|
35
|
+
and AI agents — all database rows, all driven by the same runtime
|
|
36
|
+
(`.framework/functions/_shared/pipeline-runner.ts`,
|
|
37
|
+
`.framework/functions/_shared/trigger-engine.ts`).
|
|
38
|
+
- **An admin UI.** A schema-driven admin surface at `/spine-framework/admin`
|
|
39
|
+
built from `.framework/src/apps/admin/index.tsx`, plus generic list/detail
|
|
40
|
+
pages that render directly from each type's views.
|
|
41
|
+
- **Operations.** API keys for machine principals, delivery tracking, logs,
|
|
42
|
+
metrics, and pipeline execution history.
|
|
43
|
+
|
|
44
|
+
The stack is deliberately conventional: a React + Vite frontend, Netlify
|
|
45
|
+
Functions as the API layer, and Supabase (Postgres + Auth) as the database.
|
|
46
|
+
`netlify.toml` points functions at `.assembled/netlify/functions` and publishes
|
|
47
|
+
`dist`; `.env.example` lists the Supabase keys the app needs.
|
|
48
|
+
|
|
49
|
+
## What `npm install spine-framework` + `npx spine-framework init` gave you
|
|
50
|
+
|
|
51
|
+
`init` copies a framework-owned file set — declared in
|
|
52
|
+
`.framework/templates/project.json` — into your project: the `.framework/`
|
|
53
|
+
tree (frontend source, Netlify functions, migrations, CLI, seeds, schemas),
|
|
54
|
+
`config/` build files, root `scripts/`, `bin/`, a neutral `spine.config.json`,
|
|
55
|
+
a merged `package.json`, `netlify.toml`, `.gitignore`, and a frozen
|
|
56
|
+
`.spine-manifest.json` recording the hash of every protected file. It also
|
|
57
|
+
creates an empty `custom/` workspace — the one place your code lives.
|
|
58
|
+
|
|
59
|
+
Two consequences follow:
|
|
60
|
+
|
|
61
|
+
1. **`.framework/` (plus `config/` and `scripts/`) is sealed.** Every file is
|
|
62
|
+
hashed into `.spine-manifest.json`; `npx spine-framework upgrade` refuses to
|
|
63
|
+
overwrite a locally modified tree unless you pass `--force`.
|
|
64
|
+
2. **`custom/` is yours.** Apps, functions, components, and migrations you
|
|
65
|
+
write go there; the framework never touches it.
|
|
66
|
+
|
|
67
|
+
See [02-project-map.md](./02-project-map.md) for the full anatomy.
|
|
68
|
+
|
|
69
|
+
## How this instruction book is organized
|
|
70
|
+
|
|
71
|
+
This book ships inside the package at `.framework/src/instructions/` and is
|
|
72
|
+
also rendered inside the admin UI — admin pages mount a
|
|
73
|
+
`PageInstructions` sheet that loads these files as raw markdown and renders
|
|
74
|
+
them with `react-markdown` + `remark-gfm`
|
|
75
|
+
(`.framework/src/components/admin/PageInstructions.tsx`). Diagrams are plain
|
|
76
|
+
ASCII; the renderer does not load mermaid.
|
|
77
|
+
|
|
78
|
+
| Section | Kind | Contents |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `guide/` | guide | End-to-end walkthroughs — you are here. |
|
|
81
|
+
| `concepts/` | concept | Mental models (tenancy, permissions, schema). |
|
|
82
|
+
| `tasks/` | task | Single-goal procedures with verification steps. |
|
|
83
|
+
| `reference/` | reference | Exhaustive lookups (env vars, CLI, endpoints). |
|
|
84
|
+
| `operations/` | ui | Admin-UI surfaces and operational runbooks. |
|
|
85
|
+
| `internal/` | mixed | Repo-only notes; exempt from shipped-doc rules. |
|
|
86
|
+
| book root | entity | One file per Spine entity — [types](../types.md), [apps](../apps.md), [roles](../roles.md), [pipelines](../pipelines.md), [triggers](../triggers.md), [timers](../timers.md), [integrations](../integrations.md), [ai-agents](../ai-agents.md), [prompts](../prompts.md), [api-keys](../api-keys.md), [deliveries](../deliveries.md). |
|
|
87
|
+
|
|
88
|
+
Entity files all use the same seven sections — *What this is for → Fields and
|
|
89
|
+
settings → Minimal configuration → Full configuration → Example → Core files →
|
|
90
|
+
Agent notes* — so once you have read one, you know the shape of all of them.
|
|
91
|
+
|
|
92
|
+
## How to read it
|
|
93
|
+
|
|
94
|
+
- **Developers:** read this guide section in order
|
|
95
|
+
([install](./01-install-and-first-run.md) →
|
|
96
|
+
[project map](./02-project-map.md) →
|
|
97
|
+
[domain model](./03-domain-model.md) →
|
|
98
|
+
[first app](./04-first-app.md)), then the entity file for whatever you are
|
|
99
|
+
building, then `reference/` for exact spellings.
|
|
100
|
+
- **Agents:** [03-domain-model.md](./03-domain-model.md) gives you the
|
|
101
|
+
primitives and how they compose; each entity file's *Agent notes* section
|
|
102
|
+
lists the mistakes that actually break things; [05-glossary.md](./05-glossary.md)
|
|
103
|
+
pins down terminology.
|
|
104
|
+
- Every page is verified against the code at the `verified_against` commit in
|
|
105
|
+
its frontmatter. Where the docs disagree with code, code wins — treat that as
|
|
106
|
+
a bug and check `Core files` on the relevant entity page.
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Install and first run
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: guide
|
|
5
|
+
verified_against: d0c49d4
|
|
6
|
+
verified_on: 2026-10-30
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/cli/commands/init.ts
|
|
9
|
+
- .framework/cli/lib/project-files.ts
|
|
10
|
+
- .framework/templates/project.json
|
|
11
|
+
- .framework/templates/spine.config.neutral.json
|
|
12
|
+
- .framework/cli/commands/migrate.ts
|
|
13
|
+
- .framework/cli/commands/bootstrap.ts
|
|
14
|
+
- .env.example
|
|
15
|
+
- netlify.toml
|
|
16
|
+
- scripts/dev-netlify.sh
|
|
17
|
+
- scripts/netlify-dev-wrapper.sh
|
|
18
|
+
- config/vite.config.ts
|
|
19
|
+
- .framework/public/_redirects
|
|
20
|
+
- .framework/src/App.tsx
|
|
21
|
+
- .framework/src/pages/SetupPage.tsx
|
|
22
|
+
- .framework/src/pages/auth/RegisterPage.tsx
|
|
23
|
+
- .framework/functions/invites.ts
|
|
24
|
+
- .framework/migrations/052_registration_security.sql
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Install and first run
|
|
28
|
+
|
|
29
|
+
Prerequisites: Node ≥ 22.13 and npm ≥ 10 (recorded in `.spine-manifest.json`
|
|
30
|
+
by init), a Supabase project, and (for local dev) the Netlify CLI — pinned as a
|
|
31
|
+
devDependency, so `npm install` puts it in `node_modules`.
|
|
32
|
+
|
|
33
|
+
## Step 1 — scaffold
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install spine-framework
|
|
37
|
+
npx spine-framework init # or: init <dir>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Tarball/pre-release installs work the same way: `npm i
|
|
41
|
+
./spine-framework-<ver>.tgz` — `init` keeps the `file:` spec in
|
|
42
|
+
`package.json` rather than overwriting it with a registry version.
|
|
43
|
+
|
|
44
|
+
`init` (`.framework/cli/commands/init.ts`) copies the framework-owned file set
|
|
45
|
+
declared by `.framework/templates/project.json` into the target directory:
|
|
46
|
+
|
|
47
|
+
- **`.framework/`** — `cli`, `functions`, `migrations`, `public`, `schemas`,
|
|
48
|
+
`scripts`, `seeds`, `src`, `tests`, `docs`, `templates`, plus `index.html`
|
|
49
|
+
and `README.md`.
|
|
50
|
+
- **`config/`** — `vite.config.ts`, the tsconfig family, `tailwind.config.cjs`,
|
|
51
|
+
`postcss.config.cjs`, `components.json`.
|
|
52
|
+
- **Root files** — the shipped `scripts/*.sh` / `*.mts` / `verify-install.ts`
|
|
53
|
+
set, `bin/`, `vitest.config.ts`, `.env.example`, `LICENSE.md`.
|
|
54
|
+
- **`custom/`** — the empty workspace `init` creates for your code:
|
|
55
|
+
`custom/apps`, `custom/functions`, `custom/components`,
|
|
56
|
+
`custom/migrations`, `custom/tests`.
|
|
57
|
+
- **Generated files** — `package.json` (your name, framework scripts, the
|
|
58
|
+
framework's dependency set inlined, plus an exact `spine-framework` pin),
|
|
59
|
+
`package-lock.json` (when the package ships the verified lock template),
|
|
60
|
+
`.gitignore`, `netlify.toml`, a neutral `spine.config.json`, and the frozen
|
|
61
|
+
`.spine-manifest.json` integrity manifest.
|
|
62
|
+
- **Agent assets** — `AGENTS.md` (the framework-owned rules block between the
|
|
63
|
+
`spine-framework:begin/end` markers — refreshed on upgrade; keep your own
|
|
64
|
+
notes outside the markers) and `.devin/skills/spine-*/` task skills, synced
|
|
65
|
+
from `.framework/templates/agent/`. These are hashed into the manifest's
|
|
66
|
+
`agent_files` map rather than `files`.
|
|
67
|
+
|
|
68
|
+
`init` is deliberately file-only: it does **not** run `npm install`, write
|
|
69
|
+
`.env`, or touch any database or network resource. It refuses to run into a
|
|
70
|
+
directory that already has `.framework/` — that is what
|
|
71
|
+
`npx spine-framework upgrade` is for.
|
|
72
|
+
|
|
73
|
+
## Step 2 — `.env`
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cp .env.example .env
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Required for a working install (`.env.example` has the full list):
|
|
80
|
+
|
|
81
|
+
| Variable | Used by |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY` | the browser app (`.framework/src/lib/supabase.ts`) |
|
|
84
|
+
| `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_ANON_KEY` | Netlify functions (service-role + user-scoped clients) |
|
|
85
|
+
| `SUPABASE_DB_PASSWORD` | `npx spine-framework migrate` — connects directly to `db.<project-ref>.supabase.co:5432` as `postgres` (`.framework/cli/commands/migrate.ts`) |
|
|
86
|
+
| `APP_BASE_URL` | invite links and auth redirects (`http://localhost:8888` in dev) |
|
|
87
|
+
|
|
88
|
+
Where to find them: the URL and both keys are on one page — **Supabase
|
|
89
|
+
Dashboard → Project Settings → API Keys** (older dashboards: Settings →
|
|
90
|
+
API / Data API); `SUPABASE_DB_PASSWORD` is under **Project Settings →
|
|
91
|
+
Database**. Current dashboards issue new-style keys: the **Publishable
|
|
92
|
+
key** (`sb_publishable_…`) is the anon key and a **Secret key**
|
|
93
|
+
(`sb_secret_…`) is the service-role key — set `*_ANON_KEY` /
|
|
94
|
+
`SUPABASE_SERVICE_ROLE_KEY` to them directly. Legacy `anon`/`service_role`
|
|
95
|
+
JWTs work identically (verified end-to-end on a hosted project:
|
|
96
|
+
`signInWithPassword`, `auth.admin.createUser`, and PostgREST all accept the
|
|
97
|
+
new formats).
|
|
98
|
+
|
|
99
|
+
Optional but worth knowing early: `RESEND_API_KEY` (invite/notification
|
|
100
|
+
email), `OPENAI_API_KEY` (AI stage types), `VITE_TURNSTILE_SITE_KEY` (bot
|
|
101
|
+
protection on auth pages), `SCHEDULER_API_KEY` (system-cron HTTP guard), and
|
|
102
|
+
`INTERNAL_INVOKE_SECRET` — **required for trigger-dispatched pipelines**: if it
|
|
103
|
+
is unset, triggers write a `queued` execution row but the pipeline runner is
|
|
104
|
+
never invoked (`.framework/functions/_shared/trigger-engine.ts`).
|
|
105
|
+
|
|
106
|
+
## Step 3 — install deps and verify
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install
|
|
110
|
+
npm run verify # scripts/verify-integrity.sh — checks the tree against .spine-manifest.json
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Expect `npm audit` findings — the pinned dependency set (mostly the
|
|
114
|
+
`netlify-cli` devDependency tree) carries known advisories, and the count
|
|
115
|
+
jumps between the tarball-only install and the full post-init install. The
|
|
116
|
+
shipped `package-lock.json` template is the verified set: do **not** run
|
|
117
|
+
`npm audit fix`, which moves pinned versions the manifest was generated
|
|
118
|
+
against. Findings are tracked upstream, not per-project.
|
|
119
|
+
|
|
120
|
+
## Step 4 — migrate the database
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx spine-framework migrate
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This applies every `.framework/migrations/*.sql` file (and anything in
|
|
127
|
+
`custom/migrations/`, unless `--framework-only`) in order, recording each in a
|
|
128
|
+
`_spine_migrations` table so reruns are idempotent (`--dry-run` shows pending
|
|
129
|
+
files without applying them). File numbering is non-contiguous — retired
|
|
130
|
+
migrations are removed from the package rather than renumbered, so gaps are
|
|
131
|
+
expected and only lexical order matters. The core migration seeds the `system_admin`
|
|
132
|
+
role, the `spine-core` and `admin` apps, the `spine-system` account, and the
|
|
133
|
+
core runtime types (`.framework/migrations/003_core_system_data.sql`,
|
|
134
|
+
`.framework/migrations/011_spine_system_account.sql`).
|
|
135
|
+
|
|
136
|
+
## Step 5 — run it
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npm run dev:netlify
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`dev:netlify` runs `npm run assemble` first (via `predev:netlify`) and then
|
|
143
|
+
`scripts/dev-netlify.sh`, which cleans stale processes and launches the pinned
|
|
144
|
+
`netlify dev`. Netlify serves the site on **http://localhost:8888** and starts
|
|
145
|
+
the Vite dev server on 3001 via `scripts/netlify-dev-wrapper.sh`.
|
|
146
|
+
**Wait for the "Local dev server ready" banner** — the first `dev:netlify`
|
|
147
|
+
run bundles ~80 functions and can take a couple of minutes before the banner
|
|
148
|
+
appears; this is normal, not a hang. Early requests during function bundling
|
|
149
|
+
can crash the dev server (noted in `scripts/dev-netlify.sh`).
|
|
150
|
+
|
|
151
|
+
Ports are **fixed**: `netlify dev` must bind 8888 and Vite 3001 — both are
|
|
152
|
+
set in manifest-protected files (`netlify.toml` `[dev]` port/targetPort,
|
|
153
|
+
`config/vite.config.ts`), and there is no supported alternate-port
|
|
154
|
+
configuration. Moving only one side breaks the `/api` proxy and can
|
|
155
|
+
silently cross-connect two Spine projects on the same machine. Check the
|
|
156
|
+
ports are free first (`lsof -i :8888 -i :3001`): `dev-netlify.sh` cleans up
|
|
157
|
+
stale processes it owns but will not kill an unrelated server holding the
|
|
158
|
+
port — a second Spine project's dev stack is the usual culprit; stop that
|
|
159
|
+
one yourself.
|
|
160
|
+
|
|
161
|
+
Ignore `Failed to fetch AI Gateway token … Unauthorized` in `netlify dev`
|
|
162
|
+
output — that is the Netlify CLI's own AI feature probing your Netlify
|
|
163
|
+
account, unrelated to Spine.
|
|
164
|
+
|
|
165
|
+
Two URL spaces matter:
|
|
166
|
+
|
|
167
|
+
- `/api/*` → `/.netlify/functions/:splat`. In dev this is the Vite proxy to
|
|
168
|
+
`localhost:8888` (`config/vite.config.ts`); in production it is the
|
|
169
|
+
`_redirects` rule in `.framework/public/_redirects`.
|
|
170
|
+
- Everything else → the React SPA.
|
|
171
|
+
|
|
172
|
+
`npm run dev` alone starts *only* Vite on 3001 — fine for frontend work, but
|
|
173
|
+
`/api/*` calls still proxy to 8888, so functions need `netlify dev` running.
|
|
174
|
+
|
|
175
|
+
## First admin — browser-free bootstrap (recommended for automation)
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npx spine-framework bootstrap --email you@example.com --password '<pick-one>'
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
This is the scriptable path (`S-002`): it creates the first `system_admin`
|
|
182
|
+
person bound to the `spine-system` account — the same row shape the
|
|
183
|
+
`handle_new_auth_user` trigger writes on registration — creates a confirmed
|
|
184
|
+
auth user through `auth.admin.createUser(email_confirm: true)`, and mints a
|
|
185
|
+
`sk_` API key, all without a browser. The raw key is printed **once**; only
|
|
186
|
+
its PBKDF2 hash is stored. `--scope <scope>` (repeatable) narrows the key —
|
|
187
|
+
the default `*:*` resolves to the `system_admin` role on the machine
|
|
188
|
+
principal. Omit `--email`/`--password` and the person record is created
|
|
189
|
+
DB-only (no UI login; the minted key still works for `x-api-key` callers).
|
|
190
|
+
The command is idempotent: when a `system_admin` already exists in
|
|
191
|
+
`spine-system` it skips person creation and just mints another key
|
|
192
|
+
(`.framework/cli/commands/bootstrap.ts`).
|
|
193
|
+
|
|
194
|
+
## First login — what actually happens
|
|
195
|
+
|
|
196
|
+
Alternatively, register in the browser. The real flow, as the code
|
|
197
|
+
implements it:
|
|
198
|
+
|
|
199
|
+
1. An unauthenticated visitor is redirected to `/login`
|
|
200
|
+
(`.framework/src/App.tsx`). If `VITE_SETUP_MODE=true` is set, the `/` route
|
|
201
|
+
instead shows a static `SetupPage` listing the same steps as this page
|
|
202
|
+
(`.framework/src/pages/SetupPage.tsx`).
|
|
203
|
+
2. Go to `/register` and create an account. **The first user to register gets
|
|
204
|
+
`system_admin`**: the `handle_new_auth_user` database trigger detects an
|
|
205
|
+
empty `people` table and binds the new person to the `spine-system` account
|
|
206
|
+
with the `system_admin` role
|
|
207
|
+
(`.framework/migrations/052_registration_security.sql`). If the seeds are
|
|
208
|
+
missing, registration raises instead of creating a rootless user.
|
|
209
|
+
3. Non-first, non-invited signups get **no account and no role** — placement
|
|
210
|
+
happens when `complete-registration` runs the server-side RPC
|
|
211
|
+
(`.framework/functions/invites.ts`). An authenticated user without an
|
|
212
|
+
account is routed to `/register?resume=1` until placement finishes, never
|
|
213
|
+
to a 404 (`.framework/src/App.tsx`).
|
|
214
|
+
4. After login, a `system_admin` lands on `/spine-framework/admin` — the
|
|
215
|
+
schema-driven admin app from `.framework/src/apps/admin/index.tsx`. Other
|
|
216
|
+
users land on the first app their role can see, or `NoAppPage` when nothing
|
|
217
|
+
is routable.
|
|
218
|
+
|
|
219
|
+
## Giving your agent access
|
|
220
|
+
|
|
221
|
+
The verified path for letting an agent (or any machine caller) reach the
|
|
222
|
+
runtime API:
|
|
223
|
+
|
|
224
|
+
1. **Bootstrap an admin + key** — one step, no browser: `npx
|
|
225
|
+
spine-framework bootstrap` (see "First admin" above) both creates the
|
|
226
|
+
`system_admin` and prints a `sk_` key. The browser alternative: register
|
|
227
|
+
at `/register` (first user becomes `system_admin`), then create a scoped
|
|
228
|
+
key under **Admin → Configs → API Keys**. Either way the raw key is shown
|
|
229
|
+
**once** — copy it immediately (`.framework/functions/api-keys.ts`).
|
|
230
|
+
2. **Give the key to the agent** as the environment variable `SPINE_API_KEY`.
|
|
231
|
+
Agents send `x-api-key: sk_…` on `/api/*` requests; the header resolves to
|
|
232
|
+
a machine principal carrying the key's scopes and account binding
|
|
233
|
+
(`.framework/functions/_shared/principal.ts`). Turnstile is not in this
|
|
234
|
+
path — bot protection only guards the human auth pages.
|
|
235
|
+
|
|
236
|
+
**Caveat:** for the browser path, Supabase **email confirmation must be
|
|
237
|
+
off** in the project (Auth → Providers), or the first registrant cannot sign
|
|
238
|
+
in without access to a real inbox. `bootstrap` is unaffected — it creates
|
|
239
|
+
the auth user with `email_confirm: true` through the service role.
|
|
240
|
+
|
|
241
|
+
## Gaps
|
|
242
|
+
|
|
243
|
+
- **`npx spine-framework dev` runs the same flow as the package scripts** —
|
|
244
|
+
`scripts/assemble.sh`, then Vite via `config/vite.config.ts` (`--netlify`
|
|
245
|
+
for the full `netlify dev` stack on :8888). `npm run dev` /
|
|
246
|
+
`npm run dev:netlify` remain the canonical entry points.
|
|
247
|
+
- **`bootstrap` covers first-run provisioning only.** Subsequent admins are
|
|
248
|
+
added through the invite flow in the admin app (or another `bootstrap`
|
|
249
|
+
run, which skips person creation and only mints a new key).
|
|
250
|
+
- **Timers only tick under the Netlify scheduler.** `trigger-scheduler` is a
|
|
251
|
+
scheduled function (`* * * * *` in `netlify.toml`); pipelines triggered by
|
|
252
|
+
timers do not run without it, and trigger dispatch additionally needs
|
|
253
|
+
`INTERNAL_INVOKE_SECRET` (see Step 2).
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Anatomy of an installed project
|
|
3
|
+
audience: developers, agents
|
|
4
|
+
kind: guide
|
|
5
|
+
verified_against: f69c37d
|
|
6
|
+
verified_on: 2026-10-29
|
|
7
|
+
source_files:
|
|
8
|
+
- .framework/templates/project.json
|
|
9
|
+
- .framework/cli/commands/init.ts
|
|
10
|
+
- .framework/cli/commands/upgrade.ts
|
|
11
|
+
- .framework/cli/lib/project-files.ts
|
|
12
|
+
- scripts/checksum-manifest.mts
|
|
13
|
+
- scripts/verify-integrity.sh
|
|
14
|
+
- scripts/assemble.sh
|
|
15
|
+
- scripts/assemble-frontend.sh
|
|
16
|
+
- scripts/assemble-functions.sh
|
|
17
|
+
- config/vite.config.ts
|
|
18
|
+
- netlify.toml
|
|
19
|
+
- .framework/cli/commands/create-app.ts
|
|
20
|
+
- .framework/cli/commands/install-app.ts
|
|
21
|
+
- .framework/src/components/CustomAppLoader.tsx
|
|
22
|
+
- .framework/schemas/spine.config.schema.json
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Anatomy of an installed project
|
|
26
|
+
|
|
27
|
+
A Spine project is two concentric layers: a **sealed framework layer** the
|
|
28
|
+
package owns and overwrites on upgrade, and a **customer layer** the framework
|
|
29
|
+
never writes to.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
my-project/
|
|
33
|
+
├─ .framework/ # SEALED — framework source, vendored by init/upgrade
|
|
34
|
+
│ ├─ cli/ # the spine-framework CLI source
|
|
35
|
+
│ ├─ functions/ # Netlify functions (the whole API surface)
|
|
36
|
+
│ ├─ migrations/ # SQL migrations applied by `migrate`
|
|
37
|
+
│ ├─ public/ # static assets + _redirects
|
|
38
|
+
│ ├─ schemas/ # spine.config.schema.json
|
|
39
|
+
│ ├─ scripts/ seeds/ docs/ templates/
|
|
40
|
+
│ ├─ src/ # React frontend + admin app + this book
|
|
41
|
+
│ └─ tests/
|
|
42
|
+
├─ config/ # SEALED — build config (vite, tsconfig, tailwind…)
|
|
43
|
+
├─ scripts/ # SEALED — assemble/verify/dev shell scripts
|
|
44
|
+
├─ bin/ # SEALED — spine-framework bin shims
|
|
45
|
+
├─ custom/ # YOURS — apps, functions, components, migrations, tests
|
|
46
|
+
├─ .assembled/ # GENERATED — build output, never edit
|
|
47
|
+
├─ .spine-manifest.json # GENERATED — frozen integrity manifest
|
|
48
|
+
├─ spine.config.json # YOURS — branding + registration policy
|
|
49
|
+
├─ netlify.toml # mixed — framework blocks + your custom_* sections
|
|
50
|
+
├─ package.json # merged — framework scripts/deps + your own
|
|
51
|
+
└─ .env # YOURS — secrets; never written by the framework
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## The sealed layer
|
|
55
|
+
|
|
56
|
+
The file set is declared in `.framework/templates/project.json`
|
|
57
|
+
(`framework_dirs`, `framework_files`, `config_files`, `root_scripts`, `bin`)
|
|
58
|
+
and every protected file's sha256 is recorded in `.spine-manifest.json` — the
|
|
59
|
+
protected trees are `.framework`, `config`, `scripts`, and `bin`
|
|
60
|
+
(`scripts/checksum-manifest.mts`, `PROTECTED_DIRS`).
|
|
61
|
+
|
|
62
|
+
- `npm run verify` (`scripts/verify-integrity.sh` → `scripts/verify-manifest.mts`)
|
|
63
|
+
re-hashes the tree and fails on drift. `SPINE_INTEGRITY=warn` downgrades to
|
|
64
|
+
warnings.
|
|
65
|
+
- `npx spine-framework upgrade` re-syncs the sealed layer to the
|
|
66
|
+
`spine-framework` version installed in `node_modules`
|
|
67
|
+
(`.framework/cli/commands/upgrade.ts`). It first verifies the tree against
|
|
68
|
+
the manifest and **aborts on any locally modified or missing protected file**
|
|
69
|
+
unless `--force` is passed — so do not edit `.framework/`, `config/`,
|
|
70
|
+
`scripts/`, or `bin/`; changes there are destroyed on the next upgrade
|
|
71
|
+
anyway.
|
|
72
|
+
- Deletions on upgrade are confined to `.framework/`; sealed files dropped
|
|
73
|
+
upstream outside it are left in place with a warning.
|
|
74
|
+
|
|
75
|
+
## `custom/` — your code
|
|
76
|
+
|
|
77
|
+
`init` creates `custom/apps`, `custom/functions`, `custom/components`,
|
|
78
|
+
`custom/migrations`, and `custom/tests` (`.framework/cli/commands/init.ts`).
|
|
79
|
+
Everything in it is yours: not integrity-tracked, never touched by upgrade.
|
|
80
|
+
|
|
81
|
+
- **Custom apps** live at `custom/apps/<slug>/`.
|
|
82
|
+
`npx spine-framework create-app <slug>` scaffolds `manifest.json`,
|
|
83
|
+
`index.tsx`, and `components/`, then inserts the `apps` row with
|
|
84
|
+
`renderer: 'custom'` (`.framework/cli/commands/create-app.ts`).
|
|
85
|
+
`CustomAppLoader` resolves the UI via
|
|
86
|
+
`import.meta.glob('../../../custom/apps/*/index.tsx')`
|
|
87
|
+
(`.framework/src/components/CustomAppLoader.tsx`), and the Vite alias
|
|
88
|
+
`@custom` points at `custom/apps` (`config/vite.config.ts`).
|
|
89
|
+
- **Custom functions** live at `custom/functions/` or inside an app at
|
|
90
|
+
`custom/apps/<slug>/functions/`; assembly merges them into the flat
|
|
91
|
+
functions directory and hard-fails on basename collisions with framework
|
|
92
|
+
functions (`scripts/assemble-functions.sh`). Name yours `custom_*`.
|
|
93
|
+
- **Custom migrations** in `custom/migrations/` run with
|
|
94
|
+
`npx spine-framework migrate` (skip them with `--framework-only`).
|
|
95
|
+
- **Packaged apps** installed via `npx spine-framework install-app <pkg>` also
|
|
96
|
+
land under `custom/apps/<slug>/`; their `manifest.json` can seed types,
|
|
97
|
+
roles, pipelines, and registration policy into the database
|
|
98
|
+
(`.framework/cli/commands/install-app.ts`).
|
|
99
|
+
|
|
100
|
+
## `.assembled/` — build output
|
|
101
|
+
|
|
102
|
+
`npm run assemble` (`scripts/assemble.sh`) produces `.assembled/` fresh on
|
|
103
|
+
every dev start and build:
|
|
104
|
+
|
|
105
|
+
- `.assembled/src` — the framework frontend plus each `custom/apps/<slug>/`
|
|
106
|
+
copied verbatim (never basename-flattened), plus the fixed-up `index.html`
|
|
107
|
+
(`scripts/assemble-frontend.sh`). Vite builds and serves from here.
|
|
108
|
+
- `.assembled/netlify/functions` — framework + custom functions flattened into
|
|
109
|
+
the single directory Netlify requires (`netlify.toml`
|
|
110
|
+
`functions.directory`); duplicate basenames are a hard error, not a
|
|
111
|
+
last-wins overwrite (`scripts/assemble-functions.sh`).
|
|
112
|
+
|
|
113
|
+
Never edit `.assembled/` — it is regenerated and deleted freely.
|
|
114
|
+
|
|
115
|
+
## `.spine-manifest.json` — the integrity contract
|
|
116
|
+
|
|
117
|
+
Written by `init` and regenerated by `upgrade`
|
|
118
|
+
(`.framework/cli/lib/project-files.ts` → `writeFrozenManifest`): the package
|
|
119
|
+
version (`framework_version`), the framework-owned dependency list, a tree
|
|
120
|
+
digest, and a sha256 per protected file. It is the input to `npm run verify`
|
|
121
|
+
and to upgrade's local-modification check.
|
|
122
|
+
|
|
123
|
+
## `spine.config.json` — project runtime config
|
|
124
|
+
|
|
125
|
+
Customer-owned; `init` seeds the neutral template
|
|
126
|
+
(`.framework/templates/spine.config.neutral.json`) and
|
|
127
|
+
`install-app`/`update-db-app` merge per-app registration policy into it
|
|
128
|
+
(`.framework/cli/commands/install-app.ts`). It carries `branding` and the
|
|
129
|
+
`registration` block that drives signup routing/role assignment — schema at
|
|
130
|
+
`.framework/schemas/spine.config.schema.json`. Upgrade never writes it.
|
|
131
|
+
|
|
132
|
+
## `netlify.toml` and `package.json` — mixed ownership
|
|
133
|
+
|
|
134
|
+
- `netlify.toml`: framework blocks are rewritten on upgrade, but
|
|
135
|
+
`[functions."custom_*"]` sections are treated as app-owned and preserved
|
|
136
|
+
verbatim (`.framework/cli/lib/project-files.ts` → `splitNetlifyToml` /
|
|
137
|
+
`renderNetlifyToml`). Scheduled custom functions belong there.
|
|
138
|
+
- `package.json`: framework-owned scripts and dependencies are merged in and
|
|
139
|
+
`spine-framework` pinned exactly; your own scripts and deps are preserved.
|
|
140
|
+
Upgrade removes a dependency only if the previous framework version owned it
|
|
141
|
+
and the new one does not.
|
|
142
|
+
|
|
143
|
+
## `.env` — yours, always
|
|
144
|
+
|
|
145
|
+
No framework command writes `.env`; it is gitignored and excluded from the
|
|
146
|
+
file set (`.framework/templates/project.json` `exclude_globs`). `.env.example`
|
|
147
|
+
ships as the documented baseline.
|