diff --git a/.agents/skills/constructive-access-control.zip b/.agents/skills/constructive-access-control.zip deleted file mode 100644 index a2c7fc5..0000000 Binary files a/.agents/skills/constructive-access-control.zip and /dev/null differ diff --git a/.agents/skills/constructive-agents.zip b/.agents/skills/constructive-agents.zip deleted file mode 100644 index 030d4f0..0000000 Binary files a/.agents/skills/constructive-agents.zip and /dev/null differ diff --git a/.agents/skills/constructive-auth.zip b/.agents/skills/constructive-auth.zip deleted file mode 100644 index b6a90cf..0000000 Binary files a/.agents/skills/constructive-auth.zip and /dev/null differ diff --git a/.agents/skills/constructive-billing.zip b/.agents/skills/constructive-billing.zip deleted file mode 100644 index 442bc58..0000000 Binary files a/.agents/skills/constructive-billing.zip and /dev/null differ diff --git a/.agents/skills/constructive-blueprints.zip b/.agents/skills/constructive-blueprints.zip deleted file mode 100644 index 202cd7c..0000000 Binary files a/.agents/skills/constructive-blueprints.zip and /dev/null differ diff --git a/.agents/skills/constructive-codegen.zip b/.agents/skills/constructive-codegen.zip deleted file mode 100644 index 669c582..0000000 Binary files a/.agents/skills/constructive-codegen.zip and /dev/null differ diff --git a/.agents/skills/constructive-data-modeling.zip b/.agents/skills/constructive-data-modeling.zip deleted file mode 100644 index 2c7a1e9..0000000 Binary files a/.agents/skills/constructive-data-modeling.zip and /dev/null differ diff --git a/.agents/skills/constructive-data-modeling/SKILL.md b/.agents/skills/constructive-data-modeling/SKILL.md index 23652e1..c0213e8 100644 --- a/.agents/skills/constructive-data-modeling/SKILL.md +++ b/.agents/skills/constructive-data-modeling/SKILL.md @@ -340,9 +340,12 @@ escape hatch, and combining predicates with expressions. ## Views Create views via `db.view.create`; `viewType` selects the view body (`View*` node -type). Three optional options control PostgreSQL storage attributes and update -semantics: `securityInvoker` (default `true`), `securityBarrier` (default -`false`), and `checkOption` (`null | 'local' | 'cascaded'`). +type). The body in `data` references its source by **catalog ID** +(`source_table_id` / `field_ids`, etc.), never a raw schema/table name — the server +resolves names and enforces same-database ownership + AST validation. Three optional +options control PostgreSQL storage attributes and update semantics: `securityInvoker` +(default `true`), `securityBarrier` (default `false`), and `checkOption` +(`null | 'local' | 'cascaded'`). ```typescript await db.view.create({ @@ -352,7 +355,7 @@ await db.view.create({ name: 'owners_view', viewType: 'ViewTableProjection', tableId: ownersTableId, - data: { source_schema: 'app_public', source_table: 'owners' }, + data: { source_table_id: ownersTableId }, securityBarrier: true, checkOption: 'cascaded', isReadOnly: false, @@ -364,7 +367,8 @@ await db.view.create({ // SELECT ... WITH CASCADED CHECK OPTION ``` -See [views.md](./references/views.md) for all view options and generated SQL. +See [views.md](./references/views.md) for all view options, the ID-based body, and +ownership/validation guarantees. ## `api_required` (Required API Fields) diff --git a/.agents/skills/constructive-data-modeling/references/views.md b/.agents/skills/constructive-data-modeling/references/views.md index d7bbf02..e2f090c 100644 --- a/.agents/skills/constructive-data-modeling/references/views.md +++ b/.agents/skills/constructive-data-modeling/references/views.md @@ -7,6 +7,13 @@ each row compiles to a PostgreSQL `CREATE VIEW`. The view body is chosen by for the catalog: `ViewTableProjection`, `ViewJoinedTables`, `ViewAggregated`, `ViewFilteredTable`, `ViewComposite`). +The view body lives in the `data` object and is **referenced by ID, never by raw +schema/table name**. Depending on `viewType`, `data` carries `source_table_id` / +`primary_table_id` / per-join `table_id` (all catalog table UUIDs) and optional +`field_ids`. The server resolves each ID to the physical schema/table name for you +and validates it (see [Referential integrity & ownership](#referential-integrity--ownership)), +so you never hand-write a schema name into a view. + ```typescript await db.view.create({ data: { @@ -15,7 +22,9 @@ await db.view.create({ name: 'active_projects', viewType: 'ViewTableProjection', tableId: projectsTableId, - data: { source_schema: 'app_public', source_table: 'projects' }, + // ID-based body: names are resolved from the catalog server-side. + // field_ids is optional — omit it to SELECT * from the source table. + data: { source_table_id: projectsTableId }, isReadOnly: true, }, select: { id: true }, @@ -49,7 +58,7 @@ await db.view.create({ name: 'owners_view', viewType: 'ViewTableProjection', tableId: ownersTableId, - data: { source_schema: 'app_public', source_table: 'owners' }, + data: { source_table_id: ownersTableId }, securityInvoker: true, securityBarrier: true, checkOption: 'cascaded', @@ -82,3 +91,28 @@ Set `checkOption: null` to drop the check option again. > Only `null | 'local' | 'cascaded'` are valid for `checkOption`. A check option > is meaningful only on updatable views (`isReadOnly: false`). + +## Referential integrity & ownership + +View bodies reference their source objects by **catalog ID** (`source_table_id`, +`primary_table_id`, per-join `table_id`, `field_ids`) — never by a raw +schema/table name you supply. This is what keeps views safe and tenant-scoped: + +- **Ownership is enforced.** Every referenced table ID is checked to belong to the + same `databaseId` as the view; a table from another database is rejected + (generates a `CROSS_DATABASE_REF` error). `field_ids` are likewise scoped to the + view's database. You cannot point a view at another tenant's table by ID or by + guessing its physical schema name. +- **Names are derived, not trusted.** The physical `source_schema` / `source_table` + that end up in the generated `CREATE VIEW` are looked up from the ID server-side, + so a caller can't inject an arbitrary schema name. +- **The query AST is validated.** Before the view is created/altered, the compiled + query is run through the same AST validator used by check constraints, indexes, + and functions — it restricts every referenced schema to the view's own database + schemas (plus framework schemas). This also covers the `ViewComposite` escape + hatch (`data.query_ast`): an out-of-scope schema reference there fails validation + rather than reaching PostgreSQL. + +So `db.view.create` gives the same ownership and AST-validation guarantees as the +other declarative DDL surfaces — referencing by ID is the mechanism that provides +them, which is why the name-based shortcut isn't accepted. diff --git a/.agents/skills/constructive-entities.zip b/.agents/skills/constructive-entities.zip deleted file mode 100644 index ef32bf2..0000000 Binary files a/.agents/skills/constructive-entities.zip and /dev/null differ diff --git a/.agents/skills/constructive-events.zip b/.agents/skills/constructive-events.zip deleted file mode 100644 index ff337d3..0000000 Binary files a/.agents/skills/constructive-events.zip and /dev/null differ diff --git a/.agents/skills/constructive-features.zip b/.agents/skills/constructive-features.zip deleted file mode 100644 index d7f9832..0000000 Binary files a/.agents/skills/constructive-features.zip and /dev/null differ diff --git a/.agents/skills/constructive-flow-graphs.zip b/.agents/skills/constructive-flow-graphs.zip deleted file mode 100644 index 417f35a..0000000 Binary files a/.agents/skills/constructive-flow-graphs.zip and /dev/null differ diff --git a/.agents/skills/constructive-frontend.zip b/.agents/skills/constructive-frontend.zip deleted file mode 100644 index b3d0341..0000000 Binary files a/.agents/skills/constructive-frontend.zip and /dev/null differ diff --git a/.agents/skills/constructive-hooks.zip b/.agents/skills/constructive-hooks.zip deleted file mode 100644 index afc2ded..0000000 Binary files a/.agents/skills/constructive-hooks.zip and /dev/null differ diff --git a/.agents/skills/constructive-i18n.zip b/.agents/skills/constructive-i18n.zip deleted file mode 100644 index c0f0ceb..0000000 Binary files a/.agents/skills/constructive-i18n.zip and /dev/null differ diff --git a/.agents/skills/constructive-jobs.zip b/.agents/skills/constructive-jobs.zip deleted file mode 100644 index 38a8151..0000000 Binary files a/.agents/skills/constructive-jobs.zip and /dev/null differ diff --git a/.agents/skills/constructive-notifications.zip b/.agents/skills/constructive-notifications.zip deleted file mode 100644 index a2f1435..0000000 Binary files a/.agents/skills/constructive-notifications.zip and /dev/null differ diff --git a/.agents/skills/constructive-orm.zip b/.agents/skills/constructive-orm.zip deleted file mode 100644 index 8aba8d7..0000000 Binary files a/.agents/skills/constructive-orm.zip and /dev/null differ diff --git a/.agents/skills/constructive-platform.zip b/.agents/skills/constructive-platform.zip deleted file mode 100644 index 6b84979..0000000 Binary files a/.agents/skills/constructive-platform.zip and /dev/null differ diff --git a/.agents/skills/constructive-principals.zip b/.agents/skills/constructive-principals.zip deleted file mode 100644 index 61fe5e3..0000000 Binary files a/.agents/skills/constructive-principals.zip and /dev/null differ diff --git a/.agents/skills/constructive-realtime.zip b/.agents/skills/constructive-realtime.zip deleted file mode 100644 index 3a0eb67..0000000 Binary files a/.agents/skills/constructive-realtime.zip and /dev/null differ diff --git a/.agents/skills/constructive-search.zip b/.agents/skills/constructive-search.zip deleted file mode 100644 index 1e66286..0000000 Binary files a/.agents/skills/constructive-search.zip and /dev/null differ diff --git a/.agents/skills/constructive-security.zip b/.agents/skills/constructive-security.zip deleted file mode 100644 index 4abf823..0000000 Binary files a/.agents/skills/constructive-security.zip and /dev/null differ diff --git a/.agents/skills/constructive-storage.zip b/.agents/skills/constructive-storage.zip deleted file mode 100644 index c2548ac..0000000 Binary files a/.agents/skills/constructive-storage.zip and /dev/null differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ab1bf2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +# Skill packages are not tracked; regenerate on demand if needed. +*.zip diff --git a/AGENTS.md b/AGENTS.md index fd785bd..72952f9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,15 +51,16 @@ Skills in this repository are API documentation for app builders. All examples M SKILL.md # Required: skill definition scripts/ # Required: executable scripts {script-name}.sh # Bash scripts (preferred) - {skill-name}.zip # Required: packaged for distribution ``` +> `.zip` packages are **not** committed to this repo (they caused constant merge +> conflicts). `*.zip` is gitignored; distribution packaging happens out-of-band. + ### Naming Conventions - **Skill directory**: `kebab-case` (e.g., `constructive-codegen`, `log-monitor`) - **SKILL.md**: Always uppercase, always this exact filename - **Scripts**: `kebab-case.sh` (e.g., `deploy.sh`, `fetch-logs.sh`) -- **Zip file**: Must match directory name exactly: `{skill-name}.zip` ### SKILL.md Format @@ -152,11 +153,7 @@ This allows agents helping with ORM queries to read only `orm-patterns.md` inste - Include a cleanup trap for temp files - Reference the script path as `/mnt/skills/user/{skill-name}/scripts/{script}.sh` -### Creating the Zip Package - -After creating or updating a skill: +### Packaging -```bash -cd .agents/skills -zip -r {skill-name}.zip {skill-name}/ -``` +Skill `.zip` archives are not tracked in this repo — `*.zip` is gitignored. Do not +commit them; if a distributable package is needed it is produced out-of-band. diff --git a/CLAUDE.md b/CLAUDE.md index 0b22d88..2468546 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,14 +35,6 @@ A collection of skills for AI coding agents working with Constructive tooling. S | **constructive-hooks** | Generated React Query hooks — query/mutation hooks, cache, optimistic updates | | **constructive-platform** | Server config, services, domains, deployment, env, cloud functions, cnc CLI | -## Commands - -### Package a skill for distribution -```bash -cd .agents/skills -zip -r {skill-name}.zip {skill-name}/ -``` - ## Skill Structure ``` @@ -51,9 +43,11 @@ zip -r {skill-name}.zip {skill-name}/ SKILL.md # Required: skill definition (keep under 500 lines) references/ # Optional: detailed documentation {topic}.md - {skill-name}.zip # Required: packaged for distribution ``` +> `.zip` packages are **not** committed to this repo (they caused constant merge +> conflicts). `*.zip` is gitignored; do not commit skill archives. + ### SKILL.md Format Each skill requires a SKILL.md with YAML frontmatter: @@ -81,7 +75,6 @@ Optional frontmatter fields: - Skill directory: `kebab-case` - SKILL.md: Always uppercase, exact filename -- Zip file: Must match directory name: `{skill-name}.zip` ## Key Design Principles