spine-framework 0.3.124 → 0.3.126
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/.framework/cli/commands/agents.ts +35 -37
- package/.framework/cli/commands/auth.ts +35 -34
- package/.framework/cli/commands/create-app.ts +104 -40
- package/.framework/cli/commands/dev.ts +104 -69
- package/.framework/cli/commands/doctor.ts +179 -69
- package/.framework/cli/commands/generate.ts +83 -143
- package/.framework/cli/commands/init.ts +72 -34
- package/.framework/cli/commands/install-app.ts +260 -125
- package/.framework/cli/commands/items.ts +33 -44
- package/.framework/cli/commands/migrate.ts +122 -40
- package/.framework/cli/commands/migrations.ts +33 -40
- package/.framework/cli/commands/pipelines.ts +31 -39
- package/.framework/cli/commands/status.ts +47 -23
- package/.framework/cli/commands/system.ts +47 -37
- package/.framework/cli/commands/test.ts +112 -68
- package/.framework/cli/commands/validate-app.ts +215 -121
- package/.framework/cli/context.ts +112 -130
- package/.framework/cli/env-loader.ts +47 -18
- package/.framework/cli/index.ts +81 -42
- package/.framework/docs/runtime-types.md +1024 -0
- package/.framework/functions/_shared/agent-runner.ts +1296 -961
- package/.framework/functions/_shared/app-manifest.ts +82 -68
- package/.framework/functions/_shared/audit.ts +135 -83
- package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +224 -335
- package/.framework/functions/_shared/kb.ts +319 -0
- package/.framework/functions/_shared/llm.ts +92 -0
- package/.framework/functions/_shared/logging.ts +288 -0
- package/.framework/functions/_shared/middleware.ts +329 -365
- package/.framework/functions/_shared/outcomes.ts +36 -0
- package/.framework/functions/_shared/permissions.ts +359 -643
- package/.framework/functions/_shared/pipeline-runner.ts +243 -316
- package/.framework/functions/_shared/principal.ts +376 -468
- package/.framework/functions/_shared/resolve-credentials.ts +102 -0
- package/.framework/functions/_shared/resolve-ids.ts +188 -16
- package/.framework/functions/_shared/retry-deliveries.ts +104 -0
- package/.framework/functions/_shared/schema-utils.ts +611 -373
- package/.framework/functions/_shared/testing.ts +207 -137
- package/.framework/functions/_shared/tracing.ts +276 -0
- package/.framework/functions/_shared/trigger-engine.ts +159 -211
- package/.framework/functions/_shared/webhook-registration.ts +95 -81
- package/.framework/functions/_shared/webhook-registry.ts +153 -75
- package/.framework/functions/account-nodes.ts +31 -53
- package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
- package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
- package/.framework/functions/adapters/openai-outbound.ts +40 -0
- package/.framework/functions/admin-data.ts +685 -537
- package/.framework/functions/admin-funnel.ts +31 -20
- package/.framework/functions/admin-install-funnel.ts +47 -28
- package/.framework/functions/admin-signals.ts +47 -29
- package/.framework/functions/ai-agents.ts +122 -147
- package/.framework/functions/ai-interactions.ts +180 -90
- package/.framework/functions/api-keys.ts +250 -192
- package/.framework/functions/apps.ts +203 -197
- package/.framework/functions/auth.ts +98 -91
- package/.framework/functions/cil-agent-ingest.ts +773 -0
- package/.framework/functions/cil-agent.ts +592 -0
- package/.framework/functions/cil-callmap.ts +1227 -0
- package/.framework/functions/cil-config.ts +583 -0
- package/.framework/functions/cil-context.ts +445 -0
- package/.framework/functions/cil-doc.ts +1752 -0
- package/.framework/functions/cil-embeddings.ts +1202 -0
- package/.framework/functions/cil-graph.ts +585 -0
- package/.framework/functions/cil-ingest.ts +2416 -0
- package/.framework/functions/cil-pipeline.ts +318 -0
- package/.framework/functions/cil-project.ts +499 -0
- package/.framework/functions/cil-validate.ts +469 -0
- package/.framework/functions/debug-auth.ts +73 -53
- package/.framework/functions/deliveries.ts +117 -0
- package/.framework/functions/embeddings.ts +528 -516
- package/.framework/functions/eval-harness.ts +158 -106
- package/.framework/functions/integration-outbound.ts +311 -0
- package/.framework/functions/integration-routes.ts +240 -466
- package/.framework/functions/integrations.ts +132 -140
- package/.framework/functions/invites.ts +401 -201
- package/.framework/functions/item-progress.ts +113 -53
- package/.framework/functions/kb.ts +28 -0
- package/.framework/functions/logs.ts +239 -222
- package/.framework/functions/observability.ts +308 -259
- package/.framework/functions/pipeline-executions.ts +179 -235
- package/.framework/functions/pipelines.ts +163 -205
- package/.framework/functions/prompt-configs.ts +109 -156
- package/.framework/functions/roles.ts +97 -147
- package/.framework/functions/system-cron.ts +132 -218
- package/.framework/functions/system.ts +112 -52
- package/.framework/functions/tests.ts +32 -28
- package/.framework/functions/timers.ts +162 -210
- package/.framework/functions/triggers.ts +282 -346
- package/.framework/functions/types.ts +283 -400
- package/.framework/migrations/001_core_schema.sql +630 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
- package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
- package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
- package/.framework/migrations/005_core_observability.sql +598 -0
- package/.framework/migrations/006_security_hardening_rls.sql +97 -0
- package/.framework/migrations/007_kb_article_list.sql +237 -0
- package/.framework/migrations/008_items_target.sql +8 -0
- package/.framework/migrations/009_roles_slug_unique.sql +11 -0
- package/.framework/public/spine.config.json +91 -0
- package/.framework/scripts/app-install-cli.ts +112 -98
- package/.framework/src/App.tsx +67 -20
- package/.framework/src/apps/admin/index.tsx +97 -27
- package/.framework/src/components/AppWrapper.tsx +50 -11
- package/.framework/src/components/CustomAppLoader.tsx +131 -22
- package/.framework/src/components/admin/AdminListPage.tsx +75 -8
- package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
- package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
- package/.framework/src/components/admin/PageInstructions.tsx +49 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
- package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
- package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
- package/.framework/src/components/app-sidebar.tsx +50 -3
- package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
- package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
- package/.framework/src/components/kb/KBArticleList.tsx +557 -0
- package/.framework/src/components/layout/AppShell.tsx +54 -16
- package/.framework/src/components/layout/Header.tsx +50 -38
- package/.framework/src/components/layout/Layout.tsx +48 -32
- package/.framework/src/components/layout/Sidebar.tsx +167 -16
- package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
- package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
- package/.framework/src/components/runtime/DataFilters.tsx +78 -1
- package/.framework/src/components/runtime/DataHeader.tsx +32 -29
- package/.framework/src/components/runtime/DataListPage.tsx +161 -2
- package/.framework/src/components/runtime/DataStats.tsx +48 -1
- package/.framework/src/components/runtime/DataTable.tsx +153 -1
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
- package/.framework/src/components/runtime/index.ts +16 -9
- package/.framework/src/components/search-form.tsx +33 -1
- package/.framework/src/components/shared/AgentView.tsx +48 -51
- package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
- package/.framework/src/components/shared/InviteManager.tsx +113 -52
- package/.framework/src/components/shared/MemberList.tsx +182 -0
- package/.framework/src/components/shared/SchemaFields.tsx +96 -78
- package/.framework/src/components/ui/DataTable.tsx +86 -56
- package/.framework/src/components/ui/Form.tsx +188 -109
- package/.framework/src/components/ui/ItemCard.tsx +86 -58
- package/.framework/src/components/ui/ItemListView.tsx +88 -61
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
- package/.framework/src/components/ui/Modal.tsx +81 -4
- package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
- package/.framework/src/components/ui/accordion.tsx +97 -5
- package/.framework/src/components/ui/alert-dialog.tsx +225 -13
- package/.framework/src/components/ui/alert.tsx +113 -6
- package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
- package/.framework/src/components/ui/avatar.tsx +129 -7
- package/.framework/src/components/ui/badge.tsx +65 -3
- package/.framework/src/components/ui/breadcrumb.tsx +145 -8
- package/.framework/src/components/ui/button-group.tsx +81 -4
- package/.framework/src/components/ui/button.tsx +49 -2
- package/.framework/src/components/ui/calendar.tsx +65 -3
- package/.framework/src/components/ui/card.tsx +145 -8
- package/.framework/src/components/ui/carousel.tsx +129 -7
- package/.framework/src/components/ui/chart.tsx +161 -10
- package/.framework/src/components/ui/checkbox.tsx +49 -2
- package/.framework/src/components/ui/collapsible.tsx +81 -5
- package/.framework/src/components/ui/combobox.tsx +305 -20
- package/.framework/src/components/ui/command.tsx +177 -11
- package/.framework/src/components/ui/context-menu.tsx +273 -17
- package/.framework/src/components/ui/dialog.tsx +209 -27
- package/.framework/src/components/ui/direction.tsx +64 -4
- package/.framework/src/components/ui/drawer.tsx +193 -12
- package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
- package/.framework/src/components/ui/empty.tsx +145 -9
- package/.framework/src/components/ui/field.tsx +209 -14
- package/.framework/src/components/ui/hover-card.tsx +81 -4
- package/.framework/src/components/ui/input-group.tsx +162 -10
- package/.framework/src/components/ui/input-otp.tsx +98 -5
- package/.framework/src/components/ui/input.tsx +49 -2
- package/.framework/src/components/ui/item.tsx +225 -13
- package/.framework/src/components/ui/kbd.tsx +65 -3
- package/.framework/src/components/ui/label.tsx +49 -2
- package/.framework/src/components/ui/menubar.tsx +289 -17
- package/.framework/src/components/ui/native-select.tsx +97 -5
- package/.framework/src/components/ui/navigation-menu.tsx +177 -10
- package/.framework/src/components/ui/pagination.tsx +161 -9
- package/.framework/src/components/ui/popover.tsx +145 -8
- package/.framework/src/components/ui/progress.tsx +49 -2
- package/.framework/src/components/ui/radio-group.tsx +65 -3
- package/.framework/src/components/ui/resizable.tsx +82 -4
- package/.framework/src/components/ui/scroll-area.tsx +65 -3
- package/.framework/src/components/ui/select.tsx +193 -11
- package/.framework/src/components/ui/separator.tsx +49 -2
- package/.framework/src/components/ui/sheet.tsx +193 -11
- package/.framework/src/components/ui/sidebar.tsx +481 -38
- package/.framework/src/components/ui/skeleton.tsx +49 -2
- package/.framework/src/components/ui/slider.tsx +49 -2
- package/.framework/src/components/ui/sonner.tsx +49 -2
- package/.framework/src/components/ui/spinner.tsx +49 -2
- package/.framework/src/components/ui/switch.tsx +49 -2
- package/.framework/src/components/ui/table-primitives.tsx +160 -33
- package/.framework/src/components/ui/table.tsx +161 -9
- package/.framework/src/components/ui/tabs.tsx +113 -6
- package/.framework/src/components/ui/textarea.tsx +49 -2
- package/.framework/src/components/ui/toggle-group.tsx +81 -4
- package/.framework/src/components/ui/toggle.tsx +65 -3
- package/.framework/src/components/ui/tooltip.tsx +97 -5
- package/.framework/src/contexts/AppContext.tsx +129 -45
- package/.framework/src/contexts/AuthContext.tsx +187 -144
- package/.framework/src/hooks/use-mobile.ts +48 -2
- package/.framework/src/hooks/useApi.ts +208 -159
- package/.framework/src/hooks/useAppPath.ts +32 -23
- package/.framework/src/hooks/useApps.ts +51 -20
- package/.framework/src/hooks/useEntityList.ts +32 -78
- package/.framework/src/hooks/useEntityRecord.ts +35 -96
- package/.framework/src/hooks/useForm.ts +32 -92
- package/.framework/src/hooks/useListSchema.ts +49 -78
- package/.framework/src/hooks/useSchemaRecord.ts +114 -105
- package/.framework/src/lib/api.ts +195 -116
- package/.framework/src/lib/supabase.ts +98 -64
- package/.framework/src/lib/utils.ts +287 -151
- package/.framework/src/main.tsx +49 -3
- package/.framework/src/pages/DashboardPage.tsx +52 -29
- package/.framework/src/pages/NotFoundPage.tsx +32 -10
- package/.framework/src/pages/SetupPage.tsx +32 -12
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
- package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
- package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
- package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
- package/.framework/src/pages/admin/AppsPage.tsx +49 -2
- package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
- package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
- package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
- package/.framework/src/pages/admin/LogsPage.tsx +422 -75
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
- package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
- package/.framework/src/pages/admin/RolesPage.tsx +171 -18
- package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
- package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
- package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
- package/.framework/src/pages/admin/TimersPage.tsx +48 -20
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
- package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
- package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
- package/.framework/src/pages/admin/TypesPage.tsx +48 -20
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
- package/.framework/src/pages/auth/LoginPage.tsx +50 -23
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
- package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
- package/.framework/src/types/auth.ts +128 -71
- package/.framework/src/types/types.ts +373 -157
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
- package/docs/README.md +9 -130
- package/netlify.toml +5 -2
- package/package.json +13 -25
- package/scripts/kb-ingest-docs.ts +203 -0
- package/spine.config.json +65 -4
- package/.framework/migrations/001_schema.sql +0 -425
- package/.framework/migrations/002_rls_and_functions.sql +0 -763
- package/.framework/migrations/004_enhancements.sql +0 -43
- package/.framework/migrations/005_auth_user_trigger.sql +0 -105
- package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
- package/.framework/migrations/016_invites.sql +0 -27
- package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
- package/.framework/migrations/018_apps_required_roles.sql +0 -17
- package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
- package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
- package/.framework/migrations/021_app_domains.sql +0 -112
- package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
- package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
- package/.framework/migrations/024_messages_account_id.sql +0 -9
- package/.framework/migrations/025_retype_threads_messages.sql +0 -240
- package/.framework/migrations/026_fix_rls_policies.sql +0 -47
- package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
- package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
- package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
- package/.framework/migrations/030_messages_updated_by.sql +0 -6
- package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
- package/docs/APPS.md +0 -232
- package/docs/ARCHITECTURE.md +0 -246
- package/docs/INSTALL.md +0 -155
- package/docs/design-schema-spec.md +0 -1837
- package/docs/dev-guides/01-create-an-app.md +0 -183
- package/docs/dev-guides/02-create-a-function.md +0 -178
- package/docs/dev-guides/03-create-a-component.md +0 -178
- package/docs/dev-guides/04-webhook-handlers.md +0 -129
- package/docs/dev-guides/05-testing.md +0 -168
- package/docs/dev-guides/README.md +0 -40
- package/docs/npm-packages-plan.md +0 -288
- package/docs/spine-core--api-reference.md +0 -822
|
@@ -1,1837 +0,0 @@
|
|
|
1
|
-
# Spine v2 — Design Schema & Validation Schema Specification
|
|
2
|
-
|
|
3
|
-
**Version:** 1.0 — Generated 2026-04-26
|
|
4
|
-
**Source of truth:** All definitions in this document are derived directly from the live codebase.
|
|
5
|
-
**Primary sources:** `v2-core/src/types/types.ts`, `v2-core/src/components/shared/FieldRenderer.tsx`, `v2-core/functions/_shared/schema-utils.ts`, `v2-core/src/components/runtime/SchemaDetailForm.tsx`, `v2-core/src/components/runtime/DataListPage.tsx`
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Table of Contents
|
|
10
|
-
|
|
11
|
-
1. [Overview & Key Concepts](#1-overview--key-concepts)
|
|
12
|
-
2. [Top-Level Shape](#2-top-level-shape)
|
|
13
|
-
3. [fields — Field Definitions](#3-fields--field-definitions)
|
|
14
|
-
4. [views — List & Detail Views](#4-views--list--detail-views)
|
|
15
|
-
5. [record_permissions](#5-record_permissions)
|
|
16
|
-
6. [functionality — Reserved](#6-functionality--reserved)
|
|
17
|
-
7. [Field-Level permissions](#7-field-level-permissions)
|
|
18
|
-
8. [validation_schema](#8-validation_schema)
|
|
19
|
-
9. [system Field Flag](#9-system-field-flag)
|
|
20
|
-
10. [Complete Examples](#10-complete-examples)
|
|
21
|
-
11. [Rules & Constraints](#11-rules--constraints)
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## 1. Overview & Key Concepts
|
|
26
|
-
|
|
27
|
-
### What is `design_schema`?
|
|
28
|
-
|
|
29
|
-
`design_schema` is a JSONB column on the `types` table. It is the complete configuration contract for a type — defining its fields, how those fields are rendered in list and detail views, who can access which fields, and what automation is bound to the type.
|
|
30
|
-
|
|
31
|
-
### What is `validation_schema`?
|
|
32
|
-
|
|
33
|
-
`validation_schema` is a separate JSONB column on the `types` table. It is **auto-generated** from `design_schema` by `generateValidationSchema()` in `schema-utils.ts`. It strips display/permission information and retains only structural validation rules. The backend uses it to sanitize and validate incoming record data.
|
|
34
|
-
|
|
35
|
-
> **Do not hand-author `validation_schema`.** It is always derived from `design_schema`.
|
|
36
|
-
|
|
37
|
-
### `data_type` vs `display_type`
|
|
38
|
-
|
|
39
|
-
These are two different concepts used in two different places:
|
|
40
|
-
|
|
41
|
-
| Concept | Where it lives | What it controls |
|
|
42
|
-
|---|---|---|
|
|
43
|
-
| `data_type` | `design_schema.fields[key].data_type` | Storage format, backend sanitization, default form input widget |
|
|
44
|
-
| `display_type` | `design_schema.views[viewKey].fields[key].display_type` | View-level render override — changes how the field is presented without changing the data contract |
|
|
45
|
-
|
|
46
|
-
A field with `data_type: "text"` can be rendered as `display_type: "textarea"` in a specific view. The data contract doesn't change.
|
|
47
|
-
|
|
48
|
-
### `system` vs custom fields
|
|
49
|
-
|
|
50
|
-
| `system: true` | `system: false` / absent |
|
|
51
|
-
|---|---|
|
|
52
|
-
| Value lives at `record[fieldName]` — a real DB column | Value lives at `record.data[fieldName]` — stored in JSONB |
|
|
53
|
-
| Set by Spine core — not writable by non-`system-admin` roles | Defined by type author — writable per field permissions |
|
|
54
|
-
| Examples: `id`, `title`, `is_active`, `created_at` | Examples: `priority`, `category`, `content` |
|
|
55
|
-
|
|
56
|
-
Source: `SchemaFields.tsx` line 45:
|
|
57
|
-
```ts
|
|
58
|
-
field.system ? data[name] : (data.data?.[name] ?? data[name])
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## 2. Top-Level Shape
|
|
64
|
-
|
|
65
|
-
```json
|
|
66
|
-
{
|
|
67
|
-
"fields": { },
|
|
68
|
-
"views": { },
|
|
69
|
-
"record_permissions": { },
|
|
70
|
-
"functionality": null
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
| Key | Type | Required | Description |
|
|
75
|
-
|---|---|---|---|
|
|
76
|
-
| `fields` | `Record<string, FieldDefinition>` | ✅ | All field definitions, keyed by field name |
|
|
77
|
-
| `views` | `Record<string, ListView \| DetailView>` | ✅ | Named view configurations |
|
|
78
|
-
| `record_permissions` | `Record<string, string[]>` | ✅ | Record-level CRUD permissions per role |
|
|
79
|
-
| `functionality` | `FunctionalityBindings \| null` | — | Pipeline, agent, embedding, integration bindings |
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## 3. `fields` — Field Definitions
|
|
84
|
-
|
|
85
|
-
The key is the **field name** in `snake_case`. This key is the canonical identifier used everywhere — in views, validation schemas, API payloads, and permissions.
|
|
86
|
-
|
|
87
|
-
### 3.1 Field Definition Properties
|
|
88
|
-
|
|
89
|
-
| Property | Type | Required | Notes |
|
|
90
|
-
|---|---|---|---|
|
|
91
|
-
| `data_type` | enum | ✅ | See full list below |
|
|
92
|
-
| `label` | string | ✅ | Human-readable display name |
|
|
93
|
-
| `required` | boolean | ✅ | Drives form validation and backend enforcement |
|
|
94
|
-
| `system` | boolean | — | `true` = DB column; `false`/absent = in `record.data` |
|
|
95
|
-
| `placeholder` | string | — | Input placeholder text — UI hint only |
|
|
96
|
-
| `description` | string | — | Help text rendered below the field |
|
|
97
|
-
| `rows` | number | — | Textarea/JSON editor row height hint |
|
|
98
|
-
| `min` | number | — | Minimum value for number/range fields |
|
|
99
|
-
| `max` | number | — | Maximum value for number/range fields |
|
|
100
|
-
| `step` | number | — | Step increment for number/range fields |
|
|
101
|
-
| `readonly` | boolean | — | Render as read-only regardless of edit mode |
|
|
102
|
-
| `disabled` | boolean | — | Render as disabled |
|
|
103
|
-
| `options` | `string[] \| {value: string, label: string}[]` | — | Required for `select`, `multiselect`, `radio` |
|
|
104
|
-
| `permissions` | `Record<string, string[]>` | ✅ | Field-level read/write per role |
|
|
105
|
-
| `validation` | object | — | Structural validation constraints (see §3.3) |
|
|
106
|
-
|
|
107
|
-
### 3.2 `data_type` — Full Enum (22 values)
|
|
108
|
-
|
|
109
|
-
These are the exact values accepted by `FieldDefinition.data_type` in `types.ts` and handled by `FieldRenderer.tsx` and `schema-utils.ts`:
|
|
110
|
-
|
|
111
|
-
| `data_type` | Input rendered | Backend sanitization | Notes |
|
|
112
|
-
|---|---|---|---|
|
|
113
|
-
| `text` | `<input type="text">` | HTML-escaped, length-constrained | Default fallback type |
|
|
114
|
-
| `textarea` | `<textarea>` | HTML-escaped, length-constrained | Multi-line text |
|
|
115
|
-
| `rich_text` | `<textarea>` (future: rich editor) | HTML sanitized (safe tags only) | Allows basic HTML formatting |
|
|
116
|
-
| `email` | `<input type="email">` | Lowercased, validated format | Rendered as `mailto:` link in readonly |
|
|
117
|
-
| `phone` | `<input type="tel">` | Stripped to digits + `+` | Pattern validation if provided |
|
|
118
|
-
| `url` | `<input type="url">` | Validated, http/https only | Rendered as external link in readonly |
|
|
119
|
-
| `number` | `<input type="number">` | Parsed to `Number`, min/max enforced | Also used for `currency`, `range` base |
|
|
120
|
-
| `currency` | `<input type="number">` | Rounded to 2 decimal places | Use `validation.currency_code` for display |
|
|
121
|
-
| `range` | `<input type="range">` + value display | Same as `number` | Requires `min` and `max` |
|
|
122
|
-
| `date` | `<input type="date">` | ISO date string `YYYY-MM-DD` | |
|
|
123
|
-
| `datetime` | `<input type="datetime-local">` | ISO datetime string | |
|
|
124
|
-
| `boolean` | Checkbox | Coerced from string/int if needed | Readonly: "Yes" / "No" |
|
|
125
|
-
| `checkbox` | Checkbox | Same as `boolean` | Alias for `boolean` |
|
|
126
|
-
| `select` | `<select>` | Validated against `options` | Requires `options` |
|
|
127
|
-
| `multiselect` | Checkbox group | Array of strings, validated against `options` | Requires `options` |
|
|
128
|
-
| `radio` | Radio group | Validated against `options` | Requires `options` |
|
|
129
|
-
| `color` | Color picker + hex text input | Validated as `#RRGGBB` or `#RGB`, normalized to uppercase 6-digit | |
|
|
130
|
-
| `file` | `<input type="file">` | Filename sanitized, size/type checked | |
|
|
131
|
-
| `image` | `<input type="file">` | Same as `file` + image dimension hints | |
|
|
132
|
-
| `json` | Monospace textarea | Validated as parseable JSON, script injection blocked | Readonly: formatted `<pre>` |
|
|
133
|
-
| `reference` | Text input (future: picker) | UUID format validated | Use `validation.reference_kind` + `reference_type` |
|
|
134
|
-
| `address` | Text inputs per component | Each component sanitized as text | Stored as object: `{street, city, state, postal_code, country}` |
|
|
135
|
-
|
|
136
|
-
### 3.3 `validation` Sub-Properties
|
|
137
|
-
|
|
138
|
-
| Property | Applies to | Type | Description |
|
|
139
|
-
|---|---|---|---|
|
|
140
|
-
| `minLength` | `text`, `textarea`, `rich_text` | number | Minimum character count |
|
|
141
|
-
| `maxLength` | `text`, `textarea`, `rich_text`, `url` | number | Maximum character count |
|
|
142
|
-
| `pattern` | `text`, `phone` | string | Regex pattern (JavaScript syntax) |
|
|
143
|
-
| `min` | `number`, `currency`, `range`, `date`, `datetime` | number / ISO string | Minimum value or date |
|
|
144
|
-
| `max` | `number`, `currency`, `range`, `date`, `datetime` | number / ISO string | Maximum value or date |
|
|
145
|
-
| `step` | `number`, `range` | number | Step increment |
|
|
146
|
-
| `integer` | `number` | boolean | Enforce integer-only values |
|
|
147
|
-
| `precision` | `currency` | number | Decimal precision |
|
|
148
|
-
| `maxSize` | `file`, `image` | number | Max file size in bytes |
|
|
149
|
-
| `allowedTypes` | `file`, `image` | string[] | Allowed MIME types (e.g. `["image/png", "image/jpeg"]`) |
|
|
150
|
-
| `maxWidth` | `image` | number | Max image width in pixels |
|
|
151
|
-
| `maxHeight` | `image` | number | Max image height in pixels |
|
|
152
|
-
| `currency_code` | `currency` | string | ISO 4217 code (e.g. `"USD"`) — used for display formatting |
|
|
153
|
-
| `reference_kind` | `reference` | string | Entity kind to reference (e.g. `"item"`, `"person"`) |
|
|
154
|
-
| `reference_type` | `reference` | string | Type slug to reference (e.g. `"task"`) |
|
|
155
|
-
| `max` (count) | `multiselect` | number | Maximum number of selections allowed |
|
|
156
|
-
|
|
157
|
-
### 3.4 Field Examples
|
|
158
|
-
|
|
159
|
-
**Minimal field** — `data_type`, `label`, `required` are always required:
|
|
160
|
-
```json
|
|
161
|
-
{
|
|
162
|
-
"title": {
|
|
163
|
-
"data_type": "text",
|
|
164
|
-
"label": "Title",
|
|
165
|
-
"required": true,
|
|
166
|
-
"permissions": {
|
|
167
|
-
"system-admin": ["read", "write"]
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**Minimal custom field** — non-system fields always include tenant roles:
|
|
174
|
-
```json
|
|
175
|
-
{
|
|
176
|
-
"notes": {
|
|
177
|
-
"data_type": "textarea",
|
|
178
|
-
"label": "Notes",
|
|
179
|
-
"required": false,
|
|
180
|
-
"permissions": {
|
|
181
|
-
"system-admin": ["read", "write"],
|
|
182
|
-
"admin": ["read", "write"],
|
|
183
|
-
"member": ["read", "write"],
|
|
184
|
-
"guest": ["read"]
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
**Maximal field — text:**
|
|
191
|
-
```json
|
|
192
|
-
{
|
|
193
|
-
"summary": {
|
|
194
|
-
"data_type": "text",
|
|
195
|
-
"label": "Summary",
|
|
196
|
-
"required": false,
|
|
197
|
-
"system": false,
|
|
198
|
-
"placeholder": "Enter a brief summary",
|
|
199
|
-
"description": "A short description shown in list views",
|
|
200
|
-
"readonly": false,
|
|
201
|
-
"disabled": false,
|
|
202
|
-
"validation": {
|
|
203
|
-
"minLength": 10,
|
|
204
|
-
"maxLength": 500,
|
|
205
|
-
"pattern": "^[A-Za-z0-9 .,!?-]+$"
|
|
206
|
-
},
|
|
207
|
-
"permissions": {
|
|
208
|
-
"system-admin": ["read", "write"],
|
|
209
|
-
"admin": ["read", "write"],
|
|
210
|
-
"member": ["read"],
|
|
211
|
-
"guest": []
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
**Select field with options:**
|
|
218
|
-
```json
|
|
219
|
-
{
|
|
220
|
-
"status": {
|
|
221
|
-
"data_type": "select",
|
|
222
|
-
"label": "Status",
|
|
223
|
-
"required": true,
|
|
224
|
-
"system": false,
|
|
225
|
-
"options": ["todo", "in_progress", "done", "blocked"],
|
|
226
|
-
"permissions": {
|
|
227
|
-
"admin": ["read", "write"],
|
|
228
|
-
"member": ["read", "write"],
|
|
229
|
-
"guest": ["read"]
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
**Select with labeled options:**
|
|
236
|
-
```json
|
|
237
|
-
{
|
|
238
|
-
"priority": {
|
|
239
|
-
"data_type": "select",
|
|
240
|
-
"label": "Priority",
|
|
241
|
-
"required": true,
|
|
242
|
-
"options": [
|
|
243
|
-
{ "value": "low", "label": "Low" },
|
|
244
|
-
{ "value": "medium", "label": "Medium" },
|
|
245
|
-
{ "value": "high", "label": "High" },
|
|
246
|
-
{ "value": "urgent", "label": "Urgent 🔥" }
|
|
247
|
-
],
|
|
248
|
-
"permissions": {
|
|
249
|
-
"admin": ["read", "write"],
|
|
250
|
-
"member": ["read", "write"]
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
**Reference field:**
|
|
257
|
-
```json
|
|
258
|
-
{
|
|
259
|
-
"assignee_id": {
|
|
260
|
-
"data_type": "reference",
|
|
261
|
-
"label": "Assignee",
|
|
262
|
-
"required": false,
|
|
263
|
-
"system": false,
|
|
264
|
-
"validation": {
|
|
265
|
-
"reference_kind": "person",
|
|
266
|
-
"reference_type": "employee"
|
|
267
|
-
},
|
|
268
|
-
"permissions": {
|
|
269
|
-
"admin": ["read", "write"],
|
|
270
|
-
"member": ["read"]
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
**Number field with constraints:**
|
|
277
|
-
```json
|
|
278
|
-
{
|
|
279
|
-
"score": {
|
|
280
|
-
"data_type": "range",
|
|
281
|
-
"label": "Score",
|
|
282
|
-
"required": false,
|
|
283
|
-
"min": 0,
|
|
284
|
-
"max": 100,
|
|
285
|
-
"step": 5,
|
|
286
|
-
"validation": {
|
|
287
|
-
"min": 0,
|
|
288
|
-
"max": 100,
|
|
289
|
-
"step": 5,
|
|
290
|
-
"integer": true
|
|
291
|
-
},
|
|
292
|
-
"permissions": {
|
|
293
|
-
"admin": ["read", "write"],
|
|
294
|
-
"member": ["read", "write"]
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
---
|
|
301
|
-
|
|
302
|
-
## 4. `views` — List & Detail Views
|
|
303
|
-
|
|
304
|
-
Views are named configurations that control how fields are presented. The key is the view slug (e.g. `"default_list"`, `"default_detail"`). Multiple views of the same type can exist.
|
|
305
|
-
|
|
306
|
-
### 4.1 List View
|
|
307
|
-
|
|
308
|
-
Used by `DataListPage` → `DataTable`. Drives table columns, sorting, filtering, and stats.
|
|
309
|
-
|
|
310
|
-
```ts
|
|
311
|
-
type ListView = {
|
|
312
|
-
type: "list"
|
|
313
|
-
display: "table" | "card" | "board"
|
|
314
|
-
label: string
|
|
315
|
-
fields: Record<string, ViewFieldConfig>
|
|
316
|
-
default_sort?: { field: string; direction: "asc" | "desc" }
|
|
317
|
-
filters?: string[]
|
|
318
|
-
stats?: Array<{ title: string; type: "count" | "filter_count"; icon?: string; color?: string; filter?: Record<string, any> }>
|
|
319
|
-
group_by?: string
|
|
320
|
-
}
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
| Property | Required | Notes |
|
|
324
|
-
|---|---|---|
|
|
325
|
-
| `type` | ✅ | Must be `"list"` |
|
|
326
|
-
| `display` | ✅ | `"table"` is fully implemented; `"card"` and `"board"` are reserved |
|
|
327
|
-
| `label` | ✅ | Human-readable view name |
|
|
328
|
-
| `fields` | ✅ | Field keys + `ViewFieldConfig` per field |
|
|
329
|
-
| `default_sort` | — | Defaults to `created_at desc` if absent |
|
|
330
|
-
| `filters` | — | Array of field names to expose as filter controls |
|
|
331
|
-
| `stats` | — | Summary stat cards above the table |
|
|
332
|
-
| `group_by` | — | Field name for board grouping (board display only) |
|
|
333
|
-
|
|
334
|
-
**Minimal list view:**
|
|
335
|
-
```json
|
|
336
|
-
{
|
|
337
|
-
"default_list": {
|
|
338
|
-
"type": "list",
|
|
339
|
-
"display": "table",
|
|
340
|
-
"label": "Default List",
|
|
341
|
-
"fields": {
|
|
342
|
-
"title": { "sortable": true, "display_type": "text" },
|
|
343
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
**Maximal list view:**
|
|
350
|
-
```json
|
|
351
|
-
{
|
|
352
|
-
"default_list": {
|
|
353
|
-
"type": "list",
|
|
354
|
-
"display": "table",
|
|
355
|
-
"label": "Tasks",
|
|
356
|
-
"fields": {
|
|
357
|
-
"title": { "sortable": true, "searchable": true, "display_type": "text" },
|
|
358
|
-
"status": { "sortable": true, "display_type": "badge" },
|
|
359
|
-
"priority": { "sortable": true, "display_type": "badge" },
|
|
360
|
-
"due_date": { "sortable": true, "display_type": "timestamp" },
|
|
361
|
-
"is_active": { "sortable": true, "display_type": "boolean" },
|
|
362
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
363
|
-
},
|
|
364
|
-
"default_sort": { "field": "due_date", "direction": "asc" },
|
|
365
|
-
"filters": ["status", "priority", "is_active"],
|
|
366
|
-
"stats": [
|
|
367
|
-
{ "title": "Total", "type": "count", "icon": "ClipboardIcon", "color": "blue" },
|
|
368
|
-
{ "title": "Open", "type": "filter_count", "icon": "ClockIcon", "color": "yellow", "filter": { "status": "todo" } },
|
|
369
|
-
{ "title": "Done", "type": "filter_count", "icon": "CheckCircleIcon", "color": "green", "filter": { "status": "done" } }
|
|
370
|
-
]
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
### 4.2 Detail View
|
|
376
|
-
|
|
377
|
-
Used by `SchemaDetailForm` → `SchemaFields` → `FieldRenderer`. Drives the record detail page form/display.
|
|
378
|
-
|
|
379
|
-
```ts
|
|
380
|
-
type DetailView = {
|
|
381
|
-
type: "detail"
|
|
382
|
-
label: string
|
|
383
|
-
sections: Array<{
|
|
384
|
-
title: string
|
|
385
|
-
fields: Record<string, ViewFieldConfig>
|
|
386
|
-
}>
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
| Property | Required | Notes |
|
|
391
|
-
|---|---|---|
|
|
392
|
-
| `type` | ✅ | Must be `"detail"` |
|
|
393
|
-
| `label` | ✅ | Human-readable view name |
|
|
394
|
-
| `sections` | ✅ | Array of sections; each has a `title` and `fields` map |
|
|
395
|
-
|
|
396
|
-
Sections render as separate cards on the detail page. Fields within a section render in two-column grid by default.
|
|
397
|
-
|
|
398
|
-
**Minimal detail view:**
|
|
399
|
-
```json
|
|
400
|
-
{
|
|
401
|
-
"default_detail": {
|
|
402
|
-
"type": "detail",
|
|
403
|
-
"label": "Default Detail",
|
|
404
|
-
"sections": [
|
|
405
|
-
{
|
|
406
|
-
"title": "Details",
|
|
407
|
-
"fields": {
|
|
408
|
-
"title": { "display_type": "text" }
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
]
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
**Maximal detail view:**
|
|
417
|
-
```json
|
|
418
|
-
{
|
|
419
|
-
"default_detail": {
|
|
420
|
-
"type": "detail",
|
|
421
|
-
"label": "Task Detail",
|
|
422
|
-
"sections": [
|
|
423
|
-
{
|
|
424
|
-
"title": "Core Info",
|
|
425
|
-
"fields": {
|
|
426
|
-
"title": { "display_type": "input" },
|
|
427
|
-
"status": { "display_type": "select" },
|
|
428
|
-
"priority": { "display_type": "radio" },
|
|
429
|
-
"due_date": { "display_type": "date_picker" }
|
|
430
|
-
}
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
"title": "Content",
|
|
434
|
-
"fields": {
|
|
435
|
-
"description": { "display_type": "textarea" },
|
|
436
|
-
"notes": { "display_type": "rich_text" }
|
|
437
|
-
}
|
|
438
|
-
},
|
|
439
|
-
{
|
|
440
|
-
"title": "System",
|
|
441
|
-
"fields": {
|
|
442
|
-
"is_active": { "display_type": "checkbox" },
|
|
443
|
-
"created_at": { "display_type": "timestamp" }
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
]
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
### 4.3 `ViewFieldConfig` — `display_type` Enum
|
|
452
|
-
|
|
453
|
-
The `display_type` in a view overrides the default input widget without changing the field's data contract.
|
|
454
|
-
|
|
455
|
-
| `display_type` | Renders as | Notes |
|
|
456
|
-
|---|---|---|
|
|
457
|
-
| `text` | Plain text display | Read-only display in list views |
|
|
458
|
-
| `input` | `<input type="text">` | Editable text in detail |
|
|
459
|
-
| `textarea` | `<textarea>` | Multi-line editable |
|
|
460
|
-
| `rich_text` | Sanitized HTML textarea | Basic formatting |
|
|
461
|
-
| `select` | `<select>` dropdown | Requires field `options` |
|
|
462
|
-
| `multiselect` | Checkbox group | Requires field `options` |
|
|
463
|
-
| `radio` | Radio button group | Requires field `options` |
|
|
464
|
-
| `checkbox` | Single checkbox | Boolean toggle |
|
|
465
|
-
| `switch` | Toggle switch | Alias for `checkbox` |
|
|
466
|
-
| `date_picker` | `<input type="date">` | |
|
|
467
|
-
| `datetime_picker` | `<input type="datetime-local">` | |
|
|
468
|
-
| `color_picker` | Color input + hex field | |
|
|
469
|
-
| `file_upload` | File input | |
|
|
470
|
-
| `image_upload` | File input (image) | |
|
|
471
|
-
| `range_slider` | Range slider + value | Requires `min`/`max` on field |
|
|
472
|
-
| `badge` | Colored badge pill | Good for status/priority in list views |
|
|
473
|
-
| `timestamp` | Formatted date/time string | `formatDateTime()` from `lib/utils` |
|
|
474
|
-
| `currency` | Formatted currency string | Uses `validation.currency_code` |
|
|
475
|
-
| `number` | Numeric display | |
|
|
476
|
-
| `rating` | Reserved | Not yet implemented |
|
|
477
|
-
| `autocomplete` | Reserved | Not yet implemented |
|
|
478
|
-
| `address_form` | Reserved | Not yet implemented |
|
|
479
|
-
| `reference_picker` | Reserved | Not yet implemented |
|
|
480
|
-
|
|
481
|
-
---
|
|
482
|
-
|
|
483
|
-
## 5. `record_permissions`
|
|
484
|
-
|
|
485
|
-
Controls who can perform CRUD operations on records of this type.
|
|
486
|
-
|
|
487
|
-
```json
|
|
488
|
-
{
|
|
489
|
-
"record_permissions": {
|
|
490
|
-
"system-admin": ["create", "read", "update", "delete"],
|
|
491
|
-
"admin": ["create", "read", "update"],
|
|
492
|
-
"member": ["read", "update"],
|
|
493
|
-
"guest": ["read"]
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
| Property | Notes |
|
|
499
|
-
|---|---|
|
|
500
|
-
| Keys | Role slugs — must match slugs in the `roles` table |
|
|
501
|
-
| Values | Array of actions. Valid values: `"create"`, `"read"`, `"update"`, `"delete"` |
|
|
502
|
-
| Absent role | No access — not inherited from other roles |
|
|
503
|
-
| Empty array `[]` | Explicitly no access |
|
|
504
|
-
|
|
505
|
-
**Minimum (system-only type):**
|
|
506
|
-
```json
|
|
507
|
-
{
|
|
508
|
-
"record_permissions": {
|
|
509
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
**Full tenant type:**
|
|
515
|
-
```json
|
|
516
|
-
{
|
|
517
|
-
"record_permissions": {
|
|
518
|
-
"system-admin": ["create", "read", "update", "delete"],
|
|
519
|
-
"admin": ["create", "read", "update", "delete"],
|
|
520
|
-
"member": ["create", "read", "update"],
|
|
521
|
-
"guest": ["read"]
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
---
|
|
527
|
-
|
|
528
|
-
## 6. `functionality` — Reserved
|
|
529
|
-
|
|
530
|
-
`functionality` is currently `null` in all system seeds. The shape is fully defined in `types.ts` (`FunctionalityBindings`) and reserved for future automation bindings. Document the structure here for forward compatibility.
|
|
531
|
-
|
|
532
|
-
```json
|
|
533
|
-
{
|
|
534
|
-
"functionality": {
|
|
535
|
-
"pipelines": [
|
|
536
|
-
{
|
|
537
|
-
"pipeline_id": "uuid",
|
|
538
|
-
"trigger": "on_create",
|
|
539
|
-
"roles": ["admin", "member"]
|
|
540
|
-
}
|
|
541
|
-
],
|
|
542
|
-
"ai_agents": [
|
|
543
|
-
{
|
|
544
|
-
"agent_id": "uuid",
|
|
545
|
-
"capabilities": ["read", "summarize", "suggest"],
|
|
546
|
-
"trigger": "manual",
|
|
547
|
-
"roles": ["admin"]
|
|
548
|
-
}
|
|
549
|
-
],
|
|
550
|
-
"embeddings": [
|
|
551
|
-
{
|
|
552
|
-
"slug": "task-embeddings",
|
|
553
|
-
"fields": ["title", "description"],
|
|
554
|
-
"model": "text-embedding-3-small",
|
|
555
|
-
"vector_column": "embedding",
|
|
556
|
-
"trigger": "on_create_or_update"
|
|
557
|
-
}
|
|
558
|
-
],
|
|
559
|
-
"integrations": [
|
|
560
|
-
{
|
|
561
|
-
"integration_id": "uuid",
|
|
562
|
-
"sync": "bidirectional",
|
|
563
|
-
"field_map": {
|
|
564
|
-
"title": { "external_field": "name", "direction": "both" }
|
|
565
|
-
},
|
|
566
|
-
"trigger": "on_create_or_update"
|
|
567
|
-
}
|
|
568
|
-
],
|
|
569
|
-
"constraints": [
|
|
570
|
-
{
|
|
571
|
-
"type": "unique",
|
|
572
|
-
"fields": ["title", "account_id"],
|
|
573
|
-
"message": "A task with this title already exists"
|
|
574
|
-
},
|
|
575
|
-
{
|
|
576
|
-
"type": "conditional_required",
|
|
577
|
-
"field": "due_date",
|
|
578
|
-
"condition": "priority === 'urgent'",
|
|
579
|
-
"message": "Due date is required for urgent tasks"
|
|
580
|
-
},
|
|
581
|
-
{
|
|
582
|
-
"type": "immutable",
|
|
583
|
-
"field": "created_by",
|
|
584
|
-
"after": "create",
|
|
585
|
-
"message": "Creator cannot be changed after creation"
|
|
586
|
-
}
|
|
587
|
-
]
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
**`pipeline` trigger values:** `"manual"` | `"on_create"` | `"on_update"` | `"on_field_change"` | `"on_delete"` | `"scheduled"`
|
|
593
|
-
**`ai_agent` capability values:** `"read"` | `"summarize"` | `"suggest"` | `"update"`
|
|
594
|
-
**`embedding` trigger values:** `"on_create"` | `"on_update"` | `"on_create_or_update"`
|
|
595
|
-
**`constraint` type values:** `"unique"` | `"conditional_required"` | `"immutable"`
|
|
596
|
-
|
|
597
|
-
> **Current status:** `functionality` is not yet enforced by the backend. Set to `null` until needed.
|
|
598
|
-
|
|
599
|
-
---
|
|
600
|
-
|
|
601
|
-
## 7. Field-Level `permissions`
|
|
602
|
-
|
|
603
|
-
Nested inside each field definition. Controls who can read or write individual field values.
|
|
604
|
-
|
|
605
|
-
```json
|
|
606
|
-
{
|
|
607
|
-
"permissions": {
|
|
608
|
-
"system-admin": ["read", "write"],
|
|
609
|
-
"admin": ["read", "write"],
|
|
610
|
-
"member": ["read"],
|
|
611
|
-
"guest": []
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
| Valid action values | Meaning |
|
|
617
|
-
|---|---|
|
|
618
|
-
| `"read"` | Role can see this field's value |
|
|
619
|
-
| `"write"` | Role can modify this field's value |
|
|
620
|
-
|
|
621
|
-
**Rules:**
|
|
622
|
-
- Actions for field permissions are `read` and `write` only — not `create`/`delete` (those are record-level)
|
|
623
|
-
- Empty array `[]` = explicitly no access to this field
|
|
624
|
-
- Absent role key = no access
|
|
625
|
-
- `record_permissions` gates first — if a role can't read a record, field permissions are irrelevant
|
|
626
|
-
- `system: true` fields should always restrict `write` to `system-admin` by convention
|
|
627
|
-
|
|
628
|
-
---
|
|
629
|
-
|
|
630
|
-
## 8. `validation_schema`
|
|
631
|
-
|
|
632
|
-
### What it is
|
|
633
|
-
|
|
634
|
-
`validation_schema` is stored alongside `design_schema` on the `types` table. It is the server-side enforcement contract. **It is always generated by `generateValidationSchema()` in `schema-utils.ts` — never hand-authored.**
|
|
635
|
-
|
|
636
|
-
### Shape
|
|
637
|
-
|
|
638
|
-
```json
|
|
639
|
-
{
|
|
640
|
-
"fields": {
|
|
641
|
-
"field_name": {
|
|
642
|
-
"data_type": "text",
|
|
643
|
-
"required": true,
|
|
644
|
-
"minLength": 1,
|
|
645
|
-
"maxLength": 255
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
Per-field properties are: `data_type`, `required`, plus any `validation` sub-properties flattened from the field definition, plus `options` if present.
|
|
652
|
-
|
|
653
|
-
### What the backend enforces per `data_type`
|
|
654
|
-
|
|
655
|
-
| `data_type` | Sanitization applied |
|
|
656
|
-
|---|---|
|
|
657
|
-
| `text` | HTML entity escape, control chars stripped, `minLength`/`maxLength`/`pattern` enforced |
|
|
658
|
-
| `textarea` | Same as `text`, preserves line breaks |
|
|
659
|
-
| `rich_text` | Safe HTML tag allowlist, script/onX stripped, `minLength`/`maxLength` enforced |
|
|
660
|
-
| `email` | Lowercased, regex format validated |
|
|
661
|
-
| `phone` | Stripped to digits + `+`, `pattern` validated if set |
|
|
662
|
-
| `url` | URL parsed, http/https only enforced |
|
|
663
|
-
| `number` | Coerced to `Number`, `min`/`max`/`step` enforced |
|
|
664
|
-
| `currency` | Coerced to `Number`, rounded to 2 decimal places, `min`/`max` enforced |
|
|
665
|
-
| `range` | Same as `number` |
|
|
666
|
-
| `date` | Parsed to ISO `YYYY-MM-DD`, `min`/`max` date enforced |
|
|
667
|
-
| `datetime` | Parsed to ISO datetime, `min`/`max` enforced |
|
|
668
|
-
| `boolean` / `checkbox` | Coerced from string/int (`"true"`, `"1"`, `"yes"` → `true`) |
|
|
669
|
-
| `select` / `radio` | Validated against `options` array |
|
|
670
|
-
| `multiselect` | Array of strings, each validated against `options`, deduped, `max` count enforced |
|
|
671
|
-
| `color` | Validated as `#RRGGBB` or `#RGB`, normalized to uppercase 6-digit hex |
|
|
672
|
-
| `file` / `image` | Filename sanitized, `maxSize` and `allowedTypes` enforced |
|
|
673
|
-
| `json` | Parsed as JSON, script injection blocked |
|
|
674
|
-
| `reference` | UUID format validated |
|
|
675
|
-
| `address` | Each component sanitized as `text` |
|
|
676
|
-
|
|
677
|
-
### Example generated `validation_schema`
|
|
678
|
-
|
|
679
|
-
Given this `design_schema.fields`:
|
|
680
|
-
```json
|
|
681
|
-
{
|
|
682
|
-
"title": { "data_type": "text", "label": "Title", "required": true, "system": true, "validation": { "minLength": 1, "maxLength": 255 } },
|
|
683
|
-
"status": { "data_type": "select", "label": "Status", "required": true, "options": ["todo", "in_progress", "done"] },
|
|
684
|
-
"due_date": { "data_type": "date", "label": "Due Date", "required": false }
|
|
685
|
-
}
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
`generateValidationSchema()` produces:
|
|
689
|
-
```json
|
|
690
|
-
{
|
|
691
|
-
"fields": {
|
|
692
|
-
"title": { "data_type": "text", "required": true, "minLength": 1, "maxLength": 255 },
|
|
693
|
-
"status": { "data_type": "select", "required": true, "options": ["todo", "in_progress", "done"] },
|
|
694
|
-
"due_date": { "data_type": "date", "required": false }
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
```
|
|
698
|
-
|
|
699
|
-
---
|
|
700
|
-
|
|
701
|
-
## 9. `system` Field Flag
|
|
702
|
-
|
|
703
|
-
### Behavior
|
|
704
|
-
|
|
705
|
-
| Flag | Where value is stored | Who can write |
|
|
706
|
-
|---|---|---|
|
|
707
|
-
| `system: true` | `record[fieldName]` — real DB column | `system-admin` only (by convention) |
|
|
708
|
-
| `system: false` or absent | `record.data[fieldName]` — JSONB column | Per field `permissions` |
|
|
709
|
-
|
|
710
|
-
### System fields that always exist on every record
|
|
711
|
-
|
|
712
|
-
These are DB columns present on all entity tables and do not need to be defined in `design_schema.fields` to appear in views:
|
|
713
|
-
|
|
714
|
-
| Field | Type | Notes |
|
|
715
|
-
|---|---|---|
|
|
716
|
-
| `id` | `uuid` | Auto-generated |
|
|
717
|
-
| `title` | `text` | Primary display field |
|
|
718
|
-
| `is_active` | `boolean` | Soft delete flag |
|
|
719
|
-
| `account_id` | `uuid` | Owning account |
|
|
720
|
-
| `created_at` | `timestamp` | Auto-set |
|
|
721
|
-
| `updated_at` | `timestamp` | Auto-updated |
|
|
722
|
-
| `created_by` | `uuid` | FK to `people.id` |
|
|
723
|
-
|
|
724
|
-
These can be referenced in `views.fields` without being in `design_schema.fields`.
|
|
725
|
-
|
|
726
|
-
### Including system fields in `design_schema.fields`
|
|
727
|
-
|
|
728
|
-
You should include system fields you want to be editable in forms. Example:
|
|
729
|
-
|
|
730
|
-
```json
|
|
731
|
-
{
|
|
732
|
-
"title": {
|
|
733
|
-
"data_type": "text",
|
|
734
|
-
"label": "Title",
|
|
735
|
-
"required": true,
|
|
736
|
-
"system": true,
|
|
737
|
-
"validation": { "minLength": 1, "maxLength": 255 },
|
|
738
|
-
"permissions": {
|
|
739
|
-
"system-admin": ["read", "write"],
|
|
740
|
-
"admin": ["read", "write"],
|
|
741
|
-
"member": ["read", "write"]
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
---
|
|
748
|
-
|
|
749
|
-
## 10. Complete Examples
|
|
750
|
-
|
|
751
|
-
### 10.1 Minimal `design_schema`
|
|
752
|
-
|
|
753
|
-
One system field, one custom field, minimal list and detail views, system-admin only:
|
|
754
|
-
|
|
755
|
-
```json
|
|
756
|
-
{
|
|
757
|
-
"fields": {
|
|
758
|
-
"title": {
|
|
759
|
-
"data_type": "text",
|
|
760
|
-
"label": "Title",
|
|
761
|
-
"required": true,
|
|
762
|
-
"system": true,
|
|
763
|
-
"permissions": {
|
|
764
|
-
"system-admin": ["read", "write"]
|
|
765
|
-
}
|
|
766
|
-
},
|
|
767
|
-
"notes": {
|
|
768
|
-
"data_type": "textarea",
|
|
769
|
-
"label": "Notes",
|
|
770
|
-
"required": false,
|
|
771
|
-
"permissions": {
|
|
772
|
-
"system-admin": ["read", "write"]
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
},
|
|
776
|
-
"views": {
|
|
777
|
-
"default_list": {
|
|
778
|
-
"type": "list",
|
|
779
|
-
"display": "table",
|
|
780
|
-
"label": "Default List",
|
|
781
|
-
"fields": {
|
|
782
|
-
"title": { "sortable": true, "display_type": "text" },
|
|
783
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
784
|
-
},
|
|
785
|
-
"default_sort": { "field": "created_at", "direction": "desc" }
|
|
786
|
-
},
|
|
787
|
-
"default_detail": {
|
|
788
|
-
"type": "detail",
|
|
789
|
-
"label": "Default Detail",
|
|
790
|
-
"sections": [
|
|
791
|
-
{
|
|
792
|
-
"title": "Details",
|
|
793
|
-
"fields": {
|
|
794
|
-
"title": { "display_type": "input" },
|
|
795
|
-
"notes": { "display_type": "textarea" }
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
]
|
|
799
|
-
}
|
|
800
|
-
},
|
|
801
|
-
"record_permissions": {
|
|
802
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
803
|
-
},
|
|
804
|
-
"functionality": null
|
|
805
|
-
}
|
|
806
|
-
```
|
|
807
|
-
|
|
808
|
-
### 10.2 Maximal `design_schema` — Task Type
|
|
809
|
-
|
|
810
|
-
Full field set, multi-section detail view, stats, filters, role permissions, functionality reserved:
|
|
811
|
-
|
|
812
|
-
```json
|
|
813
|
-
{
|
|
814
|
-
"fields": {
|
|
815
|
-
"title": {
|
|
816
|
-
"data_type": "text",
|
|
817
|
-
"label": "Title",
|
|
818
|
-
"required": true,
|
|
819
|
-
"system": true,
|
|
820
|
-
"validation": { "minLength": 1, "maxLength": 255 },
|
|
821
|
-
"permissions": {
|
|
822
|
-
"system-admin": ["read", "write"],
|
|
823
|
-
"admin": ["read", "write"],
|
|
824
|
-
"member": ["read", "write"],
|
|
825
|
-
"guest": ["read"]
|
|
826
|
-
}
|
|
827
|
-
},
|
|
828
|
-
"status": {
|
|
829
|
-
"data_type": "select",
|
|
830
|
-
"label": "Status",
|
|
831
|
-
"required": true,
|
|
832
|
-
"system": false,
|
|
833
|
-
"options": ["todo", "in_progress", "done", "blocked"],
|
|
834
|
-
"permissions": {
|
|
835
|
-
"admin": ["read", "write"],
|
|
836
|
-
"member": ["read", "write"],
|
|
837
|
-
"guest": ["read"]
|
|
838
|
-
}
|
|
839
|
-
},
|
|
840
|
-
"priority": {
|
|
841
|
-
"data_type": "select",
|
|
842
|
-
"label": "Priority",
|
|
843
|
-
"required": true,
|
|
844
|
-
"system": false,
|
|
845
|
-
"options": [
|
|
846
|
-
{ "value": "low", "label": "Low" },
|
|
847
|
-
{ "value": "medium", "label": "Medium" },
|
|
848
|
-
{ "value": "high", "label": "High" },
|
|
849
|
-
{ "value": "urgent", "label": "Urgent" }
|
|
850
|
-
],
|
|
851
|
-
"permissions": {
|
|
852
|
-
"admin": ["read", "write"],
|
|
853
|
-
"member": ["read", "write"],
|
|
854
|
-
"guest": ["read"]
|
|
855
|
-
}
|
|
856
|
-
},
|
|
857
|
-
"due_date": {
|
|
858
|
-
"data_type": "date",
|
|
859
|
-
"label": "Due Date",
|
|
860
|
-
"required": false,
|
|
861
|
-
"system": false,
|
|
862
|
-
"permissions": {
|
|
863
|
-
"admin": ["read", "write"],
|
|
864
|
-
"member": ["read", "write"],
|
|
865
|
-
"guest": ["read"]
|
|
866
|
-
}
|
|
867
|
-
},
|
|
868
|
-
"description": {
|
|
869
|
-
"data_type": "textarea",
|
|
870
|
-
"label": "Description",
|
|
871
|
-
"required": false,
|
|
872
|
-
"system": false,
|
|
873
|
-
"validation": { "maxLength": 5000 },
|
|
874
|
-
"permissions": {
|
|
875
|
-
"admin": ["read", "write"],
|
|
876
|
-
"member": ["read", "write"],
|
|
877
|
-
"guest": ["read"]
|
|
878
|
-
}
|
|
879
|
-
},
|
|
880
|
-
"internal_notes": {
|
|
881
|
-
"data_type": "textarea",
|
|
882
|
-
"label": "Internal Notes",
|
|
883
|
-
"required": false,
|
|
884
|
-
"system": false,
|
|
885
|
-
"validation": { "maxLength": 5000 },
|
|
886
|
-
"permissions": {
|
|
887
|
-
"admin": ["read", "write"],
|
|
888
|
-
"member": [],
|
|
889
|
-
"guest": []
|
|
890
|
-
}
|
|
891
|
-
},
|
|
892
|
-
"score": {
|
|
893
|
-
"data_type": "range",
|
|
894
|
-
"label": "Completion Score",
|
|
895
|
-
"required": false,
|
|
896
|
-
"system": false,
|
|
897
|
-
"min": 0,
|
|
898
|
-
"max": 100,
|
|
899
|
-
"step": 5,
|
|
900
|
-
"validation": { "min": 0, "max": 100, "step": 5, "integer": true },
|
|
901
|
-
"permissions": {
|
|
902
|
-
"admin": ["read", "write"],
|
|
903
|
-
"member": ["read", "write"]
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
},
|
|
907
|
-
"views": {
|
|
908
|
-
"default_list": {
|
|
909
|
-
"type": "list",
|
|
910
|
-
"display": "table",
|
|
911
|
-
"label": "Tasks",
|
|
912
|
-
"fields": {
|
|
913
|
-
"title": { "sortable": true, "searchable": true, "display_type": "text" },
|
|
914
|
-
"status": { "sortable": true, "display_type": "badge" },
|
|
915
|
-
"priority": { "sortable": true, "display_type": "badge" },
|
|
916
|
-
"due_date": { "sortable": true, "display_type": "timestamp" },
|
|
917
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
918
|
-
},
|
|
919
|
-
"default_sort": { "field": "due_date", "direction": "asc" },
|
|
920
|
-
"filters": ["status", "priority", "is_active"],
|
|
921
|
-
"stats": [
|
|
922
|
-
{ "title": "Total", "type": "count", "icon": "ClipboardIcon", "color": "blue" },
|
|
923
|
-
{ "title": "Open", "type": "filter_count", "icon": "ClockIcon", "color": "yellow", "filter": { "status": "todo" } },
|
|
924
|
-
{ "title": "Done", "type": "filter_count", "icon": "CheckCircleIcon", "color": "green", "filter": { "status": "done" } }
|
|
925
|
-
]
|
|
926
|
-
},
|
|
927
|
-
"default_detail": {
|
|
928
|
-
"type": "detail",
|
|
929
|
-
"label": "Task Detail",
|
|
930
|
-
"sections": [
|
|
931
|
-
{
|
|
932
|
-
"title": "Core",
|
|
933
|
-
"fields": {
|
|
934
|
-
"title": { "display_type": "input" },
|
|
935
|
-
"status": { "display_type": "select" },
|
|
936
|
-
"priority": { "display_type": "radio" },
|
|
937
|
-
"due_date": { "display_type": "date_picker" }
|
|
938
|
-
}
|
|
939
|
-
},
|
|
940
|
-
{
|
|
941
|
-
"title": "Details",
|
|
942
|
-
"fields": {
|
|
943
|
-
"description": { "display_type": "textarea" },
|
|
944
|
-
"score": { "display_type": "range_slider" }
|
|
945
|
-
}
|
|
946
|
-
},
|
|
947
|
-
{
|
|
948
|
-
"title": "Internal",
|
|
949
|
-
"fields": {
|
|
950
|
-
"internal_notes": { "display_type": "textarea" }
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
]
|
|
954
|
-
}
|
|
955
|
-
},
|
|
956
|
-
"record_permissions": {
|
|
957
|
-
"system-admin": ["create", "read", "update", "delete"],
|
|
958
|
-
"admin": ["create", "read", "update", "delete"],
|
|
959
|
-
"member": ["create", "read", "update"],
|
|
960
|
-
"guest": ["read"]
|
|
961
|
-
},
|
|
962
|
-
"functionality": null
|
|
963
|
-
}
|
|
964
|
-
```
|
|
965
|
-
|
|
966
|
-
### 10.3 Corresponding `validation_schema` (auto-generated)
|
|
967
|
-
|
|
968
|
-
```json
|
|
969
|
-
{
|
|
970
|
-
"fields": {
|
|
971
|
-
"title": { "data_type": "text", "required": true, "minLength": 1, "maxLength": 255 },
|
|
972
|
-
"status": { "data_type": "select", "required": true, "options": ["todo", "in_progress", "done", "blocked"] },
|
|
973
|
-
"priority": { "data_type": "select", "required": true, "options": [{"value":"low","label":"Low"},{"value":"medium","label":"Medium"},{"value":"high","label":"High"},{"value":"urgent","label":"Urgent"}] },
|
|
974
|
-
"due_date": { "data_type": "date", "required": false },
|
|
975
|
-
"description": { "data_type": "textarea", "required": false, "maxLength": 5000 },
|
|
976
|
-
"internal_notes": { "data_type": "textarea", "required": false, "maxLength": 5000 },
|
|
977
|
-
"score": { "data_type": "range", "required": false, "min": 0, "max": 100, "step": 5, "integer": true }
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
```
|
|
981
|
-
|
|
982
|
-
---
|
|
983
|
-
|
|
984
|
-
## 11. Rules & Constraints
|
|
985
|
-
|
|
986
|
-
### Field-level `permissions` — when to set them
|
|
987
|
-
- Field `permissions` are **only needed to restrict access below the record-level grant**
|
|
988
|
-
- If `record_permissions` already grants a role full access, repeating that grant at the field level is redundant — omit it
|
|
989
|
-
- System-only types (all fields `system: true`, `record_permissions` grants `system-admin` only) need **no field-level permissions at all**
|
|
990
|
-
- Custom fields (`system: false`) that should be visible to tenant roles (`admin`, `member`, `guest`) **must** declare those roles in field `permissions`, since the record-level grant alone does not grant field visibility to those roles
|
|
991
|
-
- A field with no matching role entry (and no record-level field override) is invisible and unwritable to that role
|
|
992
|
-
- `validation: null` is acceptable (used in all system seeds) — omitting `validation` entirely is also fine
|
|
993
|
-
|
|
994
|
-
### Field names
|
|
995
|
-
- Must be `snake_case`
|
|
996
|
-
- Must be unique within a type
|
|
997
|
-
- The key in `design_schema.fields` IS the field name — it is used as the data key in API payloads and `record.data`
|
|
998
|
-
|
|
999
|
-
### Views
|
|
1000
|
-
- `views.fields` keys should reference fields defined in `design_schema.fields` OR known system columns (`id`, `title`, `is_active`, `created_at`, `updated_at`, `created_by`)
|
|
1001
|
-
- Referencing an undefined field key in a view is non-fatal (field is silently skipped) but should be avoided
|
|
1002
|
-
- A type must have at least one view named `"default_list"` and one named `"default_detail"` for the runtime UI to work
|
|
1003
|
-
|
|
1004
|
-
### `options` requirement
|
|
1005
|
-
- Required for `data_type: "select"`, `"multiselect"`, `"radio"` — field will not render correctly without it
|
|
1006
|
-
- Options can be plain strings `["a", "b"]` or labeled objects `[{value, label}]` — not mixed
|
|
1007
|
-
|
|
1008
|
-
### `reference` fields
|
|
1009
|
-
- `validation.reference_kind` and `validation.reference_type` should be set to enable future reference picker UI
|
|
1010
|
-
- Value stored is a UUID string
|
|
1011
|
-
|
|
1012
|
-
### `validation_schema`
|
|
1013
|
-
- Always auto-generated by `generateValidationSchema()` — do not hand-edit
|
|
1014
|
-
- When `design_schema` is updated, `validation_schema` must be regenerated and saved together
|
|
1015
|
-
|
|
1016
|
-
### `system: true` fields
|
|
1017
|
-
- By convention, `write` permission should be restricted to `system-admin` only
|
|
1018
|
-
- Do not include system fields in `design_schema.fields` unless you want them editable in forms
|
|
1019
|
-
|
|
1020
|
-
### `record_permissions`
|
|
1021
|
-
- At minimum, include `"system-admin": ["create", "read", "update", "delete"]`
|
|
1022
|
-
- Valid actions: `"create"`, `"read"`, `"update"`, `"delete"` — no others
|
|
1023
|
-
|
|
1024
|
-
### `functionality`
|
|
1025
|
-
- Set to `null` until automation bindings are needed
|
|
1026
|
-
- Do not set non-null values unless the runtime enforcement is confirmed active
|
|
1027
|
-
|
|
1028
|
-
---
|
|
1029
|
-
|
|
1030
|
-
## 12. Runtime Entity — Minimal `design_schema` Examples
|
|
1031
|
-
|
|
1032
|
-
Each example below includes **only the user-facing system columns** for that entity's DB table — all marked `system: true`. Since `record_permissions` grants `system-admin` full access, **no field-level `permissions` are set** — they are only needed when restricting access below the record-level grant.
|
|
1033
|
-
|
|
1034
|
-
These serve as the starting point for any custom type built on that entity. Add custom fields (with `system: false`) and their field-level `permissions` on top of these.
|
|
1035
|
-
|
|
1036
|
-
> Excluded from all examples: `id`, `type_id`, `account_id`, `app_id`, `data`, `design_schema`, `validation_schema`, `created_by`, `updated_by`, `auth_uid`, `role_id`, `owner_account_id` — these are internal FK/system columns not exposed in UI forms.
|
|
1037
|
-
|
|
1038
|
-
---
|
|
1039
|
-
|
|
1040
|
-
### 12.1 `items`
|
|
1041
|
-
|
|
1042
|
-
DB columns: `title`, `description`, `status`, `is_active`, `item_type`, `created_at`, `updated_at`
|
|
1043
|
-
|
|
1044
|
-
```json
|
|
1045
|
-
{
|
|
1046
|
-
"fields": {
|
|
1047
|
-
"title": {
|
|
1048
|
-
"data_type": "text",
|
|
1049
|
-
"label": "Title",
|
|
1050
|
-
"required": true,
|
|
1051
|
-
"system": true,
|
|
1052
|
-
"validation": null
|
|
1053
|
-
},
|
|
1054
|
-
"description": {
|
|
1055
|
-
"data_type": "textarea",
|
|
1056
|
-
"label": "Description",
|
|
1057
|
-
"required": false,
|
|
1058
|
-
"system": true,
|
|
1059
|
-
"validation": null
|
|
1060
|
-
},
|
|
1061
|
-
"status": {
|
|
1062
|
-
"data_type": "text",
|
|
1063
|
-
"label": "Status",
|
|
1064
|
-
"required": true,
|
|
1065
|
-
"system": true,
|
|
1066
|
-
"validation": null
|
|
1067
|
-
},
|
|
1068
|
-
"is_active": {
|
|
1069
|
-
"data_type": "boolean",
|
|
1070
|
-
"label": "Active",
|
|
1071
|
-
"required": true,
|
|
1072
|
-
"system": true,
|
|
1073
|
-
"validation": null
|
|
1074
|
-
},
|
|
1075
|
-
"item_type": {
|
|
1076
|
-
"data_type": "text",
|
|
1077
|
-
"label": "Item Type",
|
|
1078
|
-
"required": true,
|
|
1079
|
-
"system": true,
|
|
1080
|
-
"validation": null
|
|
1081
|
-
},
|
|
1082
|
-
"created_at": {
|
|
1083
|
-
"data_type": "datetime",
|
|
1084
|
-
"label": "Created",
|
|
1085
|
-
"required": false,
|
|
1086
|
-
"system": true,
|
|
1087
|
-
"readonly": true,
|
|
1088
|
-
"validation": null
|
|
1089
|
-
},
|
|
1090
|
-
"updated_at": {
|
|
1091
|
-
"data_type": "datetime",
|
|
1092
|
-
"label": "Updated",
|
|
1093
|
-
"required": false,
|
|
1094
|
-
"system": true,
|
|
1095
|
-
"readonly": true,
|
|
1096
|
-
"validation": null
|
|
1097
|
-
}
|
|
1098
|
-
},
|
|
1099
|
-
"views": {
|
|
1100
|
-
"default_list": {
|
|
1101
|
-
"type": "list",
|
|
1102
|
-
"display": "table",
|
|
1103
|
-
"label": "Items",
|
|
1104
|
-
"fields": {
|
|
1105
|
-
"title": { "sortable": true, "display_type": "text" },
|
|
1106
|
-
"status": { "sortable": true, "display_type": "badge" },
|
|
1107
|
-
"item_type": { "sortable": true, "display_type": "text" },
|
|
1108
|
-
"is_active": { "sortable": true, "display_type": "badge" },
|
|
1109
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
1110
|
-
},
|
|
1111
|
-
"default_sort": { "field": "created_at", "direction": "desc" }
|
|
1112
|
-
},
|
|
1113
|
-
"default_detail": {
|
|
1114
|
-
"type": "detail",
|
|
1115
|
-
"label": "Item Detail",
|
|
1116
|
-
"sections": [
|
|
1117
|
-
{
|
|
1118
|
-
"title": "Core",
|
|
1119
|
-
"fields": {
|
|
1120
|
-
"title": { "display_type": "input" },
|
|
1121
|
-
"description": { "display_type": "textarea" },
|
|
1122
|
-
"status": { "display_type": "input" },
|
|
1123
|
-
"item_type": { "display_type": "text" },
|
|
1124
|
-
"is_active": { "display_type": "checkbox" }
|
|
1125
|
-
}
|
|
1126
|
-
},
|
|
1127
|
-
{
|
|
1128
|
-
"title": "System",
|
|
1129
|
-
"fields": {
|
|
1130
|
-
"created_at": { "display_type": "timestamp" },
|
|
1131
|
-
"updated_at": { "display_type": "timestamp" }
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
]
|
|
1135
|
-
}
|
|
1136
|
-
},
|
|
1137
|
-
"record_permissions": {
|
|
1138
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
1139
|
-
},
|
|
1140
|
-
"functionality": null
|
|
1141
|
-
}
|
|
1142
|
-
```
|
|
1143
|
-
|
|
1144
|
-
---
|
|
1145
|
-
|
|
1146
|
-
### 12.2 `people`
|
|
1147
|
-
|
|
1148
|
-
DB columns: `full_name`, `email`, `phone`, `avatar_url`, `status`, `is_active`, `created_at`, `updated_at`
|
|
1149
|
-
|
|
1150
|
-
```json
|
|
1151
|
-
{
|
|
1152
|
-
"fields": {
|
|
1153
|
-
"full_name": {
|
|
1154
|
-
"data_type": "text",
|
|
1155
|
-
"label": "Full Name",
|
|
1156
|
-
"required": true,
|
|
1157
|
-
"system": true,
|
|
1158
|
-
"validation": null
|
|
1159
|
-
},
|
|
1160
|
-
"email": {
|
|
1161
|
-
"data_type": "email",
|
|
1162
|
-
"label": "Email",
|
|
1163
|
-
"required": true,
|
|
1164
|
-
"system": true,
|
|
1165
|
-
"validation": null
|
|
1166
|
-
},
|
|
1167
|
-
"phone": {
|
|
1168
|
-
"data_type": "phone",
|
|
1169
|
-
"label": "Phone",
|
|
1170
|
-
"required": false,
|
|
1171
|
-
"system": true,
|
|
1172
|
-
"validation": null
|
|
1173
|
-
},
|
|
1174
|
-
"avatar_url": {
|
|
1175
|
-
"data_type": "url",
|
|
1176
|
-
"label": "Avatar URL",
|
|
1177
|
-
"required": false,
|
|
1178
|
-
"system": true,
|
|
1179
|
-
"validation": null
|
|
1180
|
-
},
|
|
1181
|
-
"status": {
|
|
1182
|
-
"data_type": "text",
|
|
1183
|
-
"label": "Status",
|
|
1184
|
-
"required": true,
|
|
1185
|
-
"system": true,
|
|
1186
|
-
"validation": null
|
|
1187
|
-
},
|
|
1188
|
-
"is_active": {
|
|
1189
|
-
"data_type": "boolean",
|
|
1190
|
-
"label": "Active",
|
|
1191
|
-
"required": true,
|
|
1192
|
-
"system": true,
|
|
1193
|
-
"validation": null
|
|
1194
|
-
},
|
|
1195
|
-
"created_at": {
|
|
1196
|
-
"data_type": "datetime",
|
|
1197
|
-
"label": "Created",
|
|
1198
|
-
"required": false,
|
|
1199
|
-
"system": true,
|
|
1200
|
-
"readonly": true,
|
|
1201
|
-
"validation": null
|
|
1202
|
-
},
|
|
1203
|
-
"updated_at": {
|
|
1204
|
-
"data_type": "datetime",
|
|
1205
|
-
"label": "Updated",
|
|
1206
|
-
"required": false,
|
|
1207
|
-
"system": true,
|
|
1208
|
-
"readonly": true,
|
|
1209
|
-
"validation": null
|
|
1210
|
-
}
|
|
1211
|
-
},
|
|
1212
|
-
"views": {
|
|
1213
|
-
"default_list": {
|
|
1214
|
-
"type": "list",
|
|
1215
|
-
"display": "table",
|
|
1216
|
-
"label": "People",
|
|
1217
|
-
"fields": {
|
|
1218
|
-
"full_name": { "sortable": true, "display_type": "text" },
|
|
1219
|
-
"email": { "sortable": true, "display_type": "text" },
|
|
1220
|
-
"status": { "sortable": true, "display_type": "badge" },
|
|
1221
|
-
"is_active": { "sortable": true, "display_type": "badge" },
|
|
1222
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
1223
|
-
},
|
|
1224
|
-
"default_sort": { "field": "created_at", "direction": "desc" }
|
|
1225
|
-
},
|
|
1226
|
-
"default_detail": {
|
|
1227
|
-
"type": "detail",
|
|
1228
|
-
"label": "Person Detail",
|
|
1229
|
-
"sections": [
|
|
1230
|
-
{
|
|
1231
|
-
"title": "Identity",
|
|
1232
|
-
"fields": {
|
|
1233
|
-
"full_name": { "display_type": "input" },
|
|
1234
|
-
"email": { "display_type": "input" },
|
|
1235
|
-
"phone": { "display_type": "input" },
|
|
1236
|
-
"avatar_url": { "display_type": "input" }
|
|
1237
|
-
}
|
|
1238
|
-
},
|
|
1239
|
-
{
|
|
1240
|
-
"title": "Status",
|
|
1241
|
-
"fields": {
|
|
1242
|
-
"status": { "display_type": "input" },
|
|
1243
|
-
"is_active": { "display_type": "checkbox" }
|
|
1244
|
-
}
|
|
1245
|
-
},
|
|
1246
|
-
{
|
|
1247
|
-
"title": "System",
|
|
1248
|
-
"fields": {
|
|
1249
|
-
"created_at": { "display_type": "timestamp" },
|
|
1250
|
-
"updated_at": { "display_type": "timestamp" }
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
]
|
|
1254
|
-
}
|
|
1255
|
-
},
|
|
1256
|
-
"record_permissions": {
|
|
1257
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
1258
|
-
},
|
|
1259
|
-
"functionality": null
|
|
1260
|
-
}
|
|
1261
|
-
```
|
|
1262
|
-
|
|
1263
|
-
---
|
|
1264
|
-
|
|
1265
|
-
### 12.3 `accounts`
|
|
1266
|
-
|
|
1267
|
-
DB columns: `slug`, `display_name`, `description`, `is_active`, `created_at`, `updated_at`
|
|
1268
|
-
|
|
1269
|
-
```json
|
|
1270
|
-
{
|
|
1271
|
-
"fields": {
|
|
1272
|
-
"slug": {
|
|
1273
|
-
"data_type": "text",
|
|
1274
|
-
"label": "Slug",
|
|
1275
|
-
"required": true,
|
|
1276
|
-
"system": true,
|
|
1277
|
-
"validation": null
|
|
1278
|
-
},
|
|
1279
|
-
"display_name": {
|
|
1280
|
-
"data_type": "text",
|
|
1281
|
-
"label": "Display Name",
|
|
1282
|
-
"required": true,
|
|
1283
|
-
"system": true,
|
|
1284
|
-
"validation": null
|
|
1285
|
-
},
|
|
1286
|
-
"description": {
|
|
1287
|
-
"data_type": "textarea",
|
|
1288
|
-
"label": "Description",
|
|
1289
|
-
"required": false,
|
|
1290
|
-
"system": true,
|
|
1291
|
-
"validation": null
|
|
1292
|
-
},
|
|
1293
|
-
"is_active": {
|
|
1294
|
-
"data_type": "boolean",
|
|
1295
|
-
"label": "Active",
|
|
1296
|
-
"required": true,
|
|
1297
|
-
"system": true,
|
|
1298
|
-
"validation": null
|
|
1299
|
-
},
|
|
1300
|
-
"created_at": {
|
|
1301
|
-
"data_type": "datetime",
|
|
1302
|
-
"label": "Created",
|
|
1303
|
-
"required": false,
|
|
1304
|
-
"system": true,
|
|
1305
|
-
"readonly": true,
|
|
1306
|
-
"validation": null
|
|
1307
|
-
},
|
|
1308
|
-
"updated_at": {
|
|
1309
|
-
"data_type": "datetime",
|
|
1310
|
-
"label": "Updated",
|
|
1311
|
-
"required": false,
|
|
1312
|
-
"system": true,
|
|
1313
|
-
"readonly": true,
|
|
1314
|
-
"validation": null
|
|
1315
|
-
}
|
|
1316
|
-
},
|
|
1317
|
-
"views": {
|
|
1318
|
-
"default_list": {
|
|
1319
|
-
"type": "list",
|
|
1320
|
-
"display": "table",
|
|
1321
|
-
"label": "Accounts",
|
|
1322
|
-
"fields": {
|
|
1323
|
-
"display_name": { "sortable": true, "display_type": "text" },
|
|
1324
|
-
"slug": { "sortable": true, "display_type": "text" },
|
|
1325
|
-
"is_active": { "sortable": true, "display_type": "badge" },
|
|
1326
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
1327
|
-
},
|
|
1328
|
-
"default_sort": { "field": "created_at", "direction": "desc" }
|
|
1329
|
-
},
|
|
1330
|
-
"default_detail": {
|
|
1331
|
-
"type": "detail",
|
|
1332
|
-
"label": "Account Detail",
|
|
1333
|
-
"sections": [
|
|
1334
|
-
{
|
|
1335
|
-
"title": "Identity",
|
|
1336
|
-
"fields": {
|
|
1337
|
-
"display_name": { "display_type": "input" },
|
|
1338
|
-
"slug": { "display_type": "input" },
|
|
1339
|
-
"description": { "display_type": "textarea" },
|
|
1340
|
-
"is_active": { "display_type": "checkbox" }
|
|
1341
|
-
}
|
|
1342
|
-
},
|
|
1343
|
-
{
|
|
1344
|
-
"title": "System",
|
|
1345
|
-
"fields": {
|
|
1346
|
-
"created_at": { "display_type": "timestamp" },
|
|
1347
|
-
"updated_at": { "display_type": "timestamp" }
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
]
|
|
1351
|
-
}
|
|
1352
|
-
},
|
|
1353
|
-
"record_permissions": {
|
|
1354
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
1355
|
-
},
|
|
1356
|
-
"functionality": null
|
|
1357
|
-
}
|
|
1358
|
-
```
|
|
1359
|
-
|
|
1360
|
-
---
|
|
1361
|
-
|
|
1362
|
-
### 12.4 `threads`
|
|
1363
|
-
|
|
1364
|
-
DB columns: `title`, `target_type`, `visibility`, `status`, `created_at`, `updated_at`
|
|
1365
|
-
|
|
1366
|
-
```json
|
|
1367
|
-
{
|
|
1368
|
-
"fields": {
|
|
1369
|
-
"title": {
|
|
1370
|
-
"data_type": "text",
|
|
1371
|
-
"label": "Title",
|
|
1372
|
-
"required": false,
|
|
1373
|
-
"system": true,
|
|
1374
|
-
"validation": null
|
|
1375
|
-
},
|
|
1376
|
-
"target_type": {
|
|
1377
|
-
"data_type": "text",
|
|
1378
|
-
"label": "Target Type",
|
|
1379
|
-
"required": true,
|
|
1380
|
-
"system": true,
|
|
1381
|
-
"readonly": true,
|
|
1382
|
-
"validation": null
|
|
1383
|
-
},
|
|
1384
|
-
"visibility": {
|
|
1385
|
-
"data_type": "text",
|
|
1386
|
-
"label": "Visibility",
|
|
1387
|
-
"required": true,
|
|
1388
|
-
"system": true,
|
|
1389
|
-
"validation": null
|
|
1390
|
-
},
|
|
1391
|
-
"status": {
|
|
1392
|
-
"data_type": "text",
|
|
1393
|
-
"label": "Status",
|
|
1394
|
-
"required": true,
|
|
1395
|
-
"system": true,
|
|
1396
|
-
"validation": null
|
|
1397
|
-
},
|
|
1398
|
-
"created_at": {
|
|
1399
|
-
"data_type": "datetime",
|
|
1400
|
-
"label": "Created",
|
|
1401
|
-
"required": false,
|
|
1402
|
-
"system": true,
|
|
1403
|
-
"readonly": true,
|
|
1404
|
-
"validation": null
|
|
1405
|
-
},
|
|
1406
|
-
"updated_at": {
|
|
1407
|
-
"data_type": "datetime",
|
|
1408
|
-
"label": "Updated",
|
|
1409
|
-
"required": false,
|
|
1410
|
-
"system": true,
|
|
1411
|
-
"readonly": true,
|
|
1412
|
-
"validation": null
|
|
1413
|
-
}
|
|
1414
|
-
},
|
|
1415
|
-
"views": {
|
|
1416
|
-
"default_list": {
|
|
1417
|
-
"type": "list",
|
|
1418
|
-
"display": "table",
|
|
1419
|
-
"label": "Threads",
|
|
1420
|
-
"fields": {
|
|
1421
|
-
"title": { "sortable": true, "display_type": "text" },
|
|
1422
|
-
"target_type": { "sortable": true, "display_type": "text" },
|
|
1423
|
-
"visibility": { "sortable": true, "display_type": "badge" },
|
|
1424
|
-
"status": { "sortable": true, "display_type": "badge" },
|
|
1425
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
1426
|
-
},
|
|
1427
|
-
"default_sort": { "field": "created_at", "direction": "desc" }
|
|
1428
|
-
},
|
|
1429
|
-
"default_detail": {
|
|
1430
|
-
"type": "detail",
|
|
1431
|
-
"label": "Thread Detail",
|
|
1432
|
-
"sections": [
|
|
1433
|
-
{
|
|
1434
|
-
"title": "Core",
|
|
1435
|
-
"fields": {
|
|
1436
|
-
"title": { "display_type": "input" },
|
|
1437
|
-
"target_type": { "display_type": "text" },
|
|
1438
|
-
"visibility": { "display_type": "input" },
|
|
1439
|
-
"status": { "display_type": "input" }
|
|
1440
|
-
}
|
|
1441
|
-
},
|
|
1442
|
-
{
|
|
1443
|
-
"title": "System",
|
|
1444
|
-
"fields": {
|
|
1445
|
-
"created_at": { "display_type": "timestamp" },
|
|
1446
|
-
"updated_at": { "display_type": "timestamp" }
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
]
|
|
1450
|
-
}
|
|
1451
|
-
},
|
|
1452
|
-
"record_permissions": {
|
|
1453
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
1454
|
-
},
|
|
1455
|
-
"functionality": null
|
|
1456
|
-
}
|
|
1457
|
-
```
|
|
1458
|
-
|
|
1459
|
-
---
|
|
1460
|
-
|
|
1461
|
-
### 12.5 `messages`
|
|
1462
|
-
|
|
1463
|
-
DB columns: `content`, `direction`, `sequence`, `visibility`, `created_at`
|
|
1464
|
-
|
|
1465
|
-
```json
|
|
1466
|
-
{
|
|
1467
|
-
"fields": {
|
|
1468
|
-
"content": {
|
|
1469
|
-
"data_type": "textarea",
|
|
1470
|
-
"label": "Content",
|
|
1471
|
-
"required": true,
|
|
1472
|
-
"system": true,
|
|
1473
|
-
"validation": null
|
|
1474
|
-
},
|
|
1475
|
-
"direction": {
|
|
1476
|
-
"data_type": "text",
|
|
1477
|
-
"label": "Direction",
|
|
1478
|
-
"required": true,
|
|
1479
|
-
"system": true,
|
|
1480
|
-
"readonly": true,
|
|
1481
|
-
"validation": null
|
|
1482
|
-
},
|
|
1483
|
-
"sequence": {
|
|
1484
|
-
"data_type": "number",
|
|
1485
|
-
"label": "Sequence",
|
|
1486
|
-
"required": true,
|
|
1487
|
-
"system": true,
|
|
1488
|
-
"readonly": true,
|
|
1489
|
-
"validation": null
|
|
1490
|
-
},
|
|
1491
|
-
"visibility": {
|
|
1492
|
-
"data_type": "text",
|
|
1493
|
-
"label": "Visibility",
|
|
1494
|
-
"required": true,
|
|
1495
|
-
"system": true,
|
|
1496
|
-
"validation": null
|
|
1497
|
-
},
|
|
1498
|
-
"created_at": {
|
|
1499
|
-
"data_type": "datetime",
|
|
1500
|
-
"label": "Created",
|
|
1501
|
-
"required": false,
|
|
1502
|
-
"system": true,
|
|
1503
|
-
"readonly": true,
|
|
1504
|
-
"validation": null
|
|
1505
|
-
}
|
|
1506
|
-
},
|
|
1507
|
-
"views": {
|
|
1508
|
-
"default_list": {
|
|
1509
|
-
"type": "list",
|
|
1510
|
-
"display": "table",
|
|
1511
|
-
"label": "Messages",
|
|
1512
|
-
"fields": {
|
|
1513
|
-
"content": { "sortable": false, "display_type": "text" },
|
|
1514
|
-
"direction": { "sortable": true, "display_type": "badge" },
|
|
1515
|
-
"sequence": { "sortable": true, "display_type": "number" },
|
|
1516
|
-
"visibility": { "sortable": true, "display_type": "badge" },
|
|
1517
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
1518
|
-
},
|
|
1519
|
-
"default_sort": { "field": "sequence", "direction": "asc" }
|
|
1520
|
-
},
|
|
1521
|
-
"default_detail": {
|
|
1522
|
-
"type": "detail",
|
|
1523
|
-
"label": "Message Detail",
|
|
1524
|
-
"sections": [
|
|
1525
|
-
{
|
|
1526
|
-
"title": "Content",
|
|
1527
|
-
"fields": {
|
|
1528
|
-
"content": { "display_type": "textarea" },
|
|
1529
|
-
"direction": { "display_type": "text" },
|
|
1530
|
-
"sequence": { "display_type": "number" },
|
|
1531
|
-
"visibility": { "display_type": "input" }
|
|
1532
|
-
}
|
|
1533
|
-
},
|
|
1534
|
-
{
|
|
1535
|
-
"title": "System",
|
|
1536
|
-
"fields": {
|
|
1537
|
-
"created_at": { "display_type": "timestamp" }
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
]
|
|
1541
|
-
}
|
|
1542
|
-
},
|
|
1543
|
-
"record_permissions": {
|
|
1544
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
1545
|
-
},
|
|
1546
|
-
"functionality": null
|
|
1547
|
-
}
|
|
1548
|
-
```
|
|
1549
|
-
|
|
1550
|
-
---
|
|
1551
|
-
|
|
1552
|
-
### 12.6 `roles`
|
|
1553
|
-
|
|
1554
|
-
DB columns: `slug`, `name`, `description`, `is_system`, `is_active`, `is_protected`, `created_at`, `updated_at`
|
|
1555
|
-
|
|
1556
|
-
```json
|
|
1557
|
-
{
|
|
1558
|
-
"fields": {
|
|
1559
|
-
"slug": {
|
|
1560
|
-
"data_type": "text",
|
|
1561
|
-
"label": "Slug",
|
|
1562
|
-
"required": true,
|
|
1563
|
-
"system": true,
|
|
1564
|
-
"validation": null
|
|
1565
|
-
},
|
|
1566
|
-
"name": {
|
|
1567
|
-
"data_type": "text",
|
|
1568
|
-
"label": "Name",
|
|
1569
|
-
"required": true,
|
|
1570
|
-
"system": true,
|
|
1571
|
-
"validation": null
|
|
1572
|
-
},
|
|
1573
|
-
"description": {
|
|
1574
|
-
"data_type": "textarea",
|
|
1575
|
-
"label": "Description",
|
|
1576
|
-
"required": false,
|
|
1577
|
-
"system": true,
|
|
1578
|
-
"validation": null
|
|
1579
|
-
},
|
|
1580
|
-
"is_system": {
|
|
1581
|
-
"data_type": "boolean",
|
|
1582
|
-
"label": "System Role",
|
|
1583
|
-
"required": true,
|
|
1584
|
-
"system": true,
|
|
1585
|
-
"readonly": true,
|
|
1586
|
-
"validation": null
|
|
1587
|
-
},
|
|
1588
|
-
"is_active": {
|
|
1589
|
-
"data_type": "boolean",
|
|
1590
|
-
"label": "Active",
|
|
1591
|
-
"required": true,
|
|
1592
|
-
"system": true,
|
|
1593
|
-
"validation": null
|
|
1594
|
-
},
|
|
1595
|
-
"is_protected": {
|
|
1596
|
-
"data_type": "boolean",
|
|
1597
|
-
"label": "Protected",
|
|
1598
|
-
"required": false,
|
|
1599
|
-
"system": true,
|
|
1600
|
-
"readonly": true,
|
|
1601
|
-
"validation": null
|
|
1602
|
-
},
|
|
1603
|
-
"created_at": {
|
|
1604
|
-
"data_type": "datetime",
|
|
1605
|
-
"label": "Created",
|
|
1606
|
-
"required": false,
|
|
1607
|
-
"system": true,
|
|
1608
|
-
"readonly": true,
|
|
1609
|
-
"validation": null
|
|
1610
|
-
},
|
|
1611
|
-
"updated_at": {
|
|
1612
|
-
"data_type": "datetime",
|
|
1613
|
-
"label": "Updated",
|
|
1614
|
-
"required": false,
|
|
1615
|
-
"system": true,
|
|
1616
|
-
"readonly": true,
|
|
1617
|
-
"validation": null
|
|
1618
|
-
}
|
|
1619
|
-
},
|
|
1620
|
-
"views": {
|
|
1621
|
-
"default_list": {
|
|
1622
|
-
"type": "list",
|
|
1623
|
-
"display": "table",
|
|
1624
|
-
"label": "Roles",
|
|
1625
|
-
"fields": {
|
|
1626
|
-
"name": { "sortable": true, "display_type": "text" },
|
|
1627
|
-
"slug": { "sortable": true, "display_type": "text" },
|
|
1628
|
-
"is_system": { "sortable": true, "display_type": "badge" },
|
|
1629
|
-
"is_active": { "sortable": true, "display_type": "badge" },
|
|
1630
|
-
"created_at": { "sortable": true, "display_type": "timestamp" }
|
|
1631
|
-
},
|
|
1632
|
-
"default_sort": { "field": "name", "direction": "asc" }
|
|
1633
|
-
},
|
|
1634
|
-
"default_detail": {
|
|
1635
|
-
"type": "detail",
|
|
1636
|
-
"label": "Role Detail",
|
|
1637
|
-
"sections": [
|
|
1638
|
-
{
|
|
1639
|
-
"title": "Identity",
|
|
1640
|
-
"fields": {
|
|
1641
|
-
"name": { "display_type": "input" },
|
|
1642
|
-
"slug": { "display_type": "input" },
|
|
1643
|
-
"description": { "display_type": "textarea" }
|
|
1644
|
-
}
|
|
1645
|
-
},
|
|
1646
|
-
{
|
|
1647
|
-
"title": "Flags",
|
|
1648
|
-
"fields": {
|
|
1649
|
-
"is_system": { "display_type": "checkbox" },
|
|
1650
|
-
"is_active": { "display_type": "checkbox" },
|
|
1651
|
-
"is_protected": { "display_type": "checkbox" }
|
|
1652
|
-
}
|
|
1653
|
-
},
|
|
1654
|
-
{
|
|
1655
|
-
"title": "System",
|
|
1656
|
-
"fields": {
|
|
1657
|
-
"created_at": { "display_type": "timestamp" },
|
|
1658
|
-
"updated_at": { "display_type": "timestamp" }
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
]
|
|
1662
|
-
}
|
|
1663
|
-
},
|
|
1664
|
-
"record_permissions": {
|
|
1665
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
1666
|
-
},
|
|
1667
|
-
"functionality": null
|
|
1668
|
-
}
|
|
1669
|
-
```
|
|
1670
|
-
|
|
1671
|
-
---
|
|
1672
|
-
|
|
1673
|
-
### 12.7 `apps`
|
|
1674
|
-
|
|
1675
|
-
DB columns: `slug`, `name`, `description`, `icon`, `color`, `version`, `app_type`, `source`, `is_active`, `is_system`, `min_role`, `created_at`, `updated_at`
|
|
1676
|
-
|
|
1677
|
-
```json
|
|
1678
|
-
{
|
|
1679
|
-
"fields": {
|
|
1680
|
-
"slug": {
|
|
1681
|
-
"data_type": "text",
|
|
1682
|
-
"label": "Slug",
|
|
1683
|
-
"required": true,
|
|
1684
|
-
"system": true,
|
|
1685
|
-
"validation": null
|
|
1686
|
-
},
|
|
1687
|
-
"name": {
|
|
1688
|
-
"data_type": "text",
|
|
1689
|
-
"label": "Name",
|
|
1690
|
-
"required": true,
|
|
1691
|
-
"system": true,
|
|
1692
|
-
"validation": null
|
|
1693
|
-
},
|
|
1694
|
-
"description": {
|
|
1695
|
-
"data_type": "textarea",
|
|
1696
|
-
"label": "Description",
|
|
1697
|
-
"required": false,
|
|
1698
|
-
"system": true,
|
|
1699
|
-
"validation": null
|
|
1700
|
-
},
|
|
1701
|
-
"icon": {
|
|
1702
|
-
"data_type": "text",
|
|
1703
|
-
"label": "Icon",
|
|
1704
|
-
"required": false,
|
|
1705
|
-
"system": true,
|
|
1706
|
-
"validation": null
|
|
1707
|
-
},
|
|
1708
|
-
"color": {
|
|
1709
|
-
"data_type": "text",
|
|
1710
|
-
"label": "Color",
|
|
1711
|
-
"required": false,
|
|
1712
|
-
"system": true,
|
|
1713
|
-
"validation": null
|
|
1714
|
-
},
|
|
1715
|
-
"version": {
|
|
1716
|
-
"data_type": "text",
|
|
1717
|
-
"label": "Version",
|
|
1718
|
-
"required": true,
|
|
1719
|
-
"system": true,
|
|
1720
|
-
"validation": null
|
|
1721
|
-
},
|
|
1722
|
-
"app_type": {
|
|
1723
|
-
"data_type": "text",
|
|
1724
|
-
"label": "App Type",
|
|
1725
|
-
"required": true,
|
|
1726
|
-
"system": true,
|
|
1727
|
-
"readonly": true,
|
|
1728
|
-
"validation": null
|
|
1729
|
-
},
|
|
1730
|
-
"source": {
|
|
1731
|
-
"data_type": "text",
|
|
1732
|
-
"label": "Source",
|
|
1733
|
-
"required": true,
|
|
1734
|
-
"system": true,
|
|
1735
|
-
"readonly": true,
|
|
1736
|
-
"validation": null
|
|
1737
|
-
},
|
|
1738
|
-
"is_active": {
|
|
1739
|
-
"data_type": "boolean",
|
|
1740
|
-
"label": "Active",
|
|
1741
|
-
"required": true,
|
|
1742
|
-
"system": true,
|
|
1743
|
-
"validation": null
|
|
1744
|
-
},
|
|
1745
|
-
"is_system": {
|
|
1746
|
-
"data_type": "boolean",
|
|
1747
|
-
"label": "System App",
|
|
1748
|
-
"required": true,
|
|
1749
|
-
"system": true,
|
|
1750
|
-
"readonly": true,
|
|
1751
|
-
"validation": null
|
|
1752
|
-
},
|
|
1753
|
-
"min_role": {
|
|
1754
|
-
"data_type": "text",
|
|
1755
|
-
"label": "Minimum Role",
|
|
1756
|
-
"required": false,
|
|
1757
|
-
"system": true,
|
|
1758
|
-
"validation": null
|
|
1759
|
-
},
|
|
1760
|
-
"created_at": {
|
|
1761
|
-
"data_type": "datetime",
|
|
1762
|
-
"label": "Created",
|
|
1763
|
-
"required": false,
|
|
1764
|
-
"system": true,
|
|
1765
|
-
"readonly": true,
|
|
1766
|
-
"validation": null
|
|
1767
|
-
},
|
|
1768
|
-
"updated_at": {
|
|
1769
|
-
"data_type": "datetime",
|
|
1770
|
-
"label": "Updated",
|
|
1771
|
-
"required": false,
|
|
1772
|
-
"system": true,
|
|
1773
|
-
"readonly": true,
|
|
1774
|
-
"validation": null
|
|
1775
|
-
}
|
|
1776
|
-
},
|
|
1777
|
-
"views": {
|
|
1778
|
-
"default_list": {
|
|
1779
|
-
"type": "list",
|
|
1780
|
-
"display": "table",
|
|
1781
|
-
"label": "Apps",
|
|
1782
|
-
"fields": {
|
|
1783
|
-
"name": { "sortable": true, "display_type": "text" },
|
|
1784
|
-
"slug": { "sortable": true, "display_type": "text" },
|
|
1785
|
-
"version": { "sortable": true, "display_type": "text" },
|
|
1786
|
-
"app_type": { "sortable": true, "display_type": "badge" },
|
|
1787
|
-
"is_active": { "sortable": true, "display_type": "badge" },
|
|
1788
|
-
"created_at":{ "sortable": true, "display_type": "timestamp" }
|
|
1789
|
-
},
|
|
1790
|
-
"default_sort": { "field": "name", "direction": "asc" }
|
|
1791
|
-
},
|
|
1792
|
-
"default_detail": {
|
|
1793
|
-
"type": "detail",
|
|
1794
|
-
"label": "App Detail",
|
|
1795
|
-
"sections": [
|
|
1796
|
-
{
|
|
1797
|
-
"title": "Identity",
|
|
1798
|
-
"fields": {
|
|
1799
|
-
"name": { "display_type": "input" },
|
|
1800
|
-
"slug": { "display_type": "input" },
|
|
1801
|
-
"description": { "display_type": "textarea" },
|
|
1802
|
-
"icon": { "display_type": "input" },
|
|
1803
|
-
"color": { "display_type": "input" }
|
|
1804
|
-
}
|
|
1805
|
-
},
|
|
1806
|
-
{
|
|
1807
|
-
"title": "Configuration",
|
|
1808
|
-
"fields": {
|
|
1809
|
-
"version": { "display_type": "input" },
|
|
1810
|
-
"app_type": { "display_type": "text" },
|
|
1811
|
-
"source": { "display_type": "text" },
|
|
1812
|
-
"min_role": { "display_type": "input" }
|
|
1813
|
-
}
|
|
1814
|
-
},
|
|
1815
|
-
{
|
|
1816
|
-
"title": "Flags",
|
|
1817
|
-
"fields": {
|
|
1818
|
-
"is_active": { "display_type": "checkbox" },
|
|
1819
|
-
"is_system": { "display_type": "checkbox" }
|
|
1820
|
-
}
|
|
1821
|
-
},
|
|
1822
|
-
{
|
|
1823
|
-
"title": "System",
|
|
1824
|
-
"fields": {
|
|
1825
|
-
"created_at": { "display_type": "timestamp" },
|
|
1826
|
-
"updated_at": { "display_type": "timestamp" }
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
]
|
|
1830
|
-
}
|
|
1831
|
-
},
|
|
1832
|
-
"record_permissions": {
|
|
1833
|
-
"system-admin": ["create", "read", "update", "delete"]
|
|
1834
|
-
},
|
|
1835
|
-
"functionality": null
|
|
1836
|
-
}
|
|
1837
|
-
```
|