feat(data): split system/custom table capabilities and lock system tables#71
Merged
Merged
Conversation
…bles Split the single `data.tables.read`/`manage` pair into a system-vs-custom family so a persona (e.g. the seeded Client role) can see and manage custom tables without ever seeing the four internal system tables: data.custom.tables.read / data.custom.tables.manage data.system.tables.read / data.system.tables.manage Server enforcement (the UI mirrors it, never the sole gate): - GET /data/tables filters per family — system tables are returned only to holders of a system read cap; content-row callers (loop pickers) still see the full list. Single-table reads gate the same way. - PATCH /data/tables/:id is kind-aware (canManageTable) and runs assertSystemTableUpdateAllowed: a system table's identity (name, slug, route base, labels, kind) and built-in fields are frozen for EVERYONE, while custom fields and the primary field stay mutable. - Row writes reject built-in cell edits on the structural system tables (pages/components/layouts) via lockedBuiltInCellKey; posts built-ins and all custom fields stay editable. The editor writes those trees via its own endpoints, so this never blocks it. Client: - TableSettings renders a reduced panel for system tables (Display + Fields only; General/Routing/Kind/Danger hidden) with a "system-managed" note. - fieldGuards locks built-in fields on system tables (no edit/delete/reorder) while custom fields and "Add field" stay available. - Grid/inspector cells render built-in values read-only on structural system tables via isBuiltInValueLocked. Shared rules live in @core/data/systemTableGuard so server and client agree. Roles resynced in both dialect migrations + SYSTEM_ROLES (owner/admin get all four; client gets data.custom.tables.read only). Docs + tests updated; new unit + capability-harness integration coverage added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- DataSidebar splits tables into "System" and "Your tables" groups (labels show only when both groups are present, so a custom-only persona sees a plain list). - Remove the explanatory banner in TableSettings for system tables — the reduced panel speaks for itself. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the Site explorer's header pattern: - Export / Import become icon buttons in the "Data tables" panel header (`headerActions`) instead of full-width footer buttons. - "New table" becomes an icon button in the "Custom tables" section header. - Section headers (System / Custom tables) carry a count, styled like the Site explorer sections. The Custom section always renders (empty → "None yet") so the New-table action has a home; the System section renders only when the user can see system tables. - Rename "Your tables" → "Custom tables". Footer removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The Data view treated all
data_tablesidentically: anyone withdata.tables.readsaw the four internal system tables (posts/pages/components/layouts) alongside custom tables,updateDataTablehad no system guard (only delete was blocked), and built-in field values were hand-editable in the grid. This splits the capability and locks system tables down — so e.g. a Client persona sees custom tables but never the system ones.Capability split
Replaces
data.tables.read/data.tables.managewith a system-vs-custom family:data.custom.tables.readdata.custom.tables.managedata.system.tables.readdata.system.tables.manageRoles: owner/admin get all four; client gets
data.custom.tables.readonly. Resynced in both dialect migrations +SYSTEM_ROLES.Server enforcement (UI mirrors it, never the sole gate)
GET /data/tables): system tables returned only to system-read holders; content-row callers (loop/template pickers) still see the full list. Single-table reads gate the same way.assertSystemTableUpdateAllowed): on a system table, identity (name/slug/route/labels/kind) and built-in fields are immutable for everyone; custom fields + primary field are mutable (gated bydata.system.tables.manage).lockedBuiltInCellKey): built-in cell writes rejected on the structural system tables (pages/components/layouts);postsbuilt-ins and all custom fields stay writable. The site editor writes those trees via its own endpoints, so this never blocks it.Client
TableSettings: reduced panel for system tables — only Display (primary field) + Fields (add/manage custom fields); General/Routing/Kind/Danger hidden, with a "system-managed" note.fieldGuards: built-in fields on system tables fully locked (no edit/delete/reorder); custom fields + "Add field" stay available.Shared rules live in
@core/data/systemTableGuardso server and client agree.Tests
systemTableGuard.test.ts(frozen identity, built-in freeze, custom-field/primary-field allowed, value-lock predicate).dataSystemTableAccess.test.ts— custom-only persona sees no system tables; owner sees them; system-table rename + built-in removal rejected; custom-field add allowed; system-read-only persona denied management.Verification
bun run build(tsc + vite) — passbun test— 5458 pass, 0 failbun run lint— cleanNotes: branched from
main(not stacked on the layouts PR). The tree also carries an unrelated parallel session's AI/loops work-in-progress; only data-view files are staged here. Follow-up to the layouts single-source-of-truth PR.🤖 Generated with Claude Code