Skip to main content

designing-db-schemas

Design, change, or review a database schema in the WSO2 API Platform. Use when adding or altering a table, column, index, or constraint in any *.sql schema file, reviewing schema changes before a PR, evaluating a migration plan, or asking whether a table is well designed and what indexes it needs.

Datos de origen

Repositorio
wso2/api-platform
Última actividad en el origen
12 de agosto de 2026 a las 07:22
Idioma detectado de SKILL.md
inglés
Estrellas
76
Forks
122

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
3 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
designing-db-schemas
description
Design, change, or review a database schema in the WSO2 API Platform. Use when adding or altering a table, column, index, or constraint in any *.sql schema file, reviewing schema changes before a PR, evaluating a migration plan, or asking whether a table is well designed and what indexes it needs.
allowed-tools
Bash, Read, Edit, Write, Glob, Grep
# WSO2 API Platform — Database Schema Design This skill governs **all schema work** for the WSO2 API Platform: designing new tables, adding to existing ones, and reviewing DDL changes. It is not a post-hoc review tool — it is the process to follow when writing DDL. The rules live in **`references/api-platform-db-schema-rules.md`** (next to this skill). That file is the source of truth for every rule; this file is the workflow. ## Usage ```text /designing-db-schemas [table-name | path-to-schema-file] ``` - **No argument** — review all in-scope schema files. - **Table name** — apply the relevant workflow for that table. - **Schema file path** — review that file only. --- ## Schema file scope Discover schema files with: ```bash find . -name "*.sql" -not -path "*/node_modules/*" -not -path "*/target/*" | sort ``` Do **not** use `find . -name "schema*.sql"` — it matches 10 of the 19 schema files and misses every gateway-controller and event-gateway file. | GA product | Path | Rules | |---|---|---| | Platform API | `platform-api/internal/database/` | R0–R10 | | Platform API — eventgateway plugin | `platform-api/plugins/eventgateway/schema/` | R0–R10 | | API Portal | `portals/api-portal/database/` | R0–R10 | | AI Workspace | packages Platform API's schemas — no source of its own | — | | Gateway Controller | `gateway/gateway-controller/pkg/storage/` **and** `gateway/gateway-controller/resources/` | R0–R2, R4–R10 (**R3 skipped**) | | Event Gateway Controller | `event-gateway/gateway-controller/pkg/dbschema/` | R0–R2, R4–R10 (**R3 skipped**) | | Fixtures | `platform-api/internal/database/init-platform-api-db.sql`, `tests/integration-e2e/init-db.sql` | keep in sync | **Type exemption** — gateway-controller and event-gateway schemas are owned by separate teams who manage their own type choices. Apply all structural, constraint, audit, index, alignment, and idempotency rules (R0–R2, R4–R10) as normal, but do **not** raise R3 findings (column types, JSONB, BOOLEAN, TIMESTAMPTZ, VARCHAR widths) against those files. **Two copies** — `gateway/gateway-controller` keeps the same schema under both `pkg/storage/` and `resources/`. Grep repo-wide before editing: `grep -rln "<table_name>" --include="*.sql" .` --- ## Workflows ### Workflow A — Making a schema change #### Step A0 — Admissibility gate (R0) These are GA products. Decide whether the change is allowed **before** touching a file. | Request | Verdict | |---|---| | New table | Allowed — full R1–R10 apply | | New nullable/defaulted column on a shipped table | Allowed | | New index on a shipped table | Allowed | | Change a shipped column's type or width | **Blocked** — migration | | Rename a shipped column or table | **Blocked** — migration | | Add/drop a PK, or change an FK target or `ON DELETE` | **Blocked** — migration | | Add `NOT NULL` or `UNIQUE` to an existing column | **Blocked** — revalidates customer data | | Drop a column | **Blocked** as one step — two-release sequence, needs approval | | "Fix" a shipped table that violates R1–R10 | **Blocked** — record as `LEGACY-ACCEPTED` (R0-LEGACY-ACCEPTED) | Confirm the table has actually shipped before applying the freeze — one added earlier in the same unreleased branch is still malleable: ```bash git log --oneline -1 -S"CREATE TABLE IF NOT EXISTS <table>" -- '*.sql' ``` When blocked, don't silently narrow the task. Say which part is blocked and why, deliver the allowed remainder, and offer the migration-plan route as separate, approved work. #### Step A1 — Read the schemas first Locate every schema file with the glob above and read each in full before drafting anything. Apply R3 type rules to all files except gateway-controller and event-gateway. #### Step A2 — Open the rules reference Read `references/api-platform-db-schema-rules.md`. The rules you need depend on the change: | Change type | Rules to apply | |---|---| | New table | R0 (admissibility), R1 (identity), R2 (org-scoping), R3 (types), R4 (constraints), R5 (audit), R6 (indexes), R8 (all dialects), R9 (idempotent DDL), R10 (naming) | | New column | R0, R3 (type), R4 (constraints), R5 (audit), R6 (index if filterable), R7 (Go layer sync), R8, R9, R10 | | New index | R0, R6 (correct pattern — FK, status, compound, partial), R8, R9, R10 | | Type change on a shipped column | **R0 — blocked.** Stop; this is a migration, not a schema edit | #### Step A3 — Self-review checklist ```text [ ] R0 Change is additive — no retype/rename/PK-FK change/NOT NULL/UNIQUE on a shipped table [ ] R0 Column added to an existing table: per-dialect ALTER TABLE written for already-provisioned databases (new tables/indexes need none — their guarded CREATE covers both cases) [ ] R1 Entity tables: uuid VARCHAR(40) PRIMARY KEY [ ] R1 Junction/mapping tables: composite PRIMARY KEY — not UNIQUE-only, not surrogate UUID [ ] R1 Non-leading FK columns of a composite PK have their own indexes [ ] R1 Named resource tables carry handle + name + version (all NOT NULL) [ ] R1 handle VARCHAR(40) slug ≠ name VARCHAR(255) display string; no UNIQUE on name [ ] R2 organization_uuid FK present; UNIQUE constraints include it (if org-scoped) [ ] R3 No bare TEXT in Postgres — SQLite TEXT / SQL Server NVARCHAR(MAX) are intentional (R8) [ ] R3 Large/variable payloads use BYTEA/BLOB/VARBINARY(MAX) — not wide VARCHAR [ ] R3 JSONB only when a repository query reads inside it with JSON operators; scan target checked against the driver in use (pgx v5 also takes *string/*[]byte — see R3-JSONB-SCAN-COMPAT) [ ] R3 Boolean flags: SMALLINT (Postgres/SQL Server) or INTEGER (SQLite), 0/1 — no BOOLEAN [ ] R3 VARCHAR widths match R3-VARCHAR-SIZES; nothing above VARCHAR(1023) for plain storage [ ] R3 Indexed/UNIQUE columns ≤ VARCHAR(255); hashes are VARCHAR(255) [ ] R3 Timestamps: TIMESTAMPTZ (Postgres) / DATETIME (SQLite) / DATETIME2(7) (SQL Server), UTC [ ] R4 No CHECK constraints for enum/status values — validated in the service layer instead [ ] R4 Required columns NOT NULL, with a DEFAULT where one is sensible [ ] R4 No plaintext credential/token column; hashed or vault-referenced, named accordingly [ ] R4 Every FK has an explicit ON DELETE clause [ ] R5 User-initiated table → all four audit columns; system-managed → created_by/updated_by ABSENT [ ] R5 Every domain entity table has data_version VARCHAR(20) NOT NULL DEFAULT '1.0' [ ] R6 FK columns, organization_uuid, and filtered status columns have indexes — except where the column is already the leftmost part of the PK or a covering UNIQUE constraint [ ] R7 Go model/repository/DTO updated in the same commit; named columns, no SELECT * [ ] R8 Change applied to every dialect file (or divergence is intentional and documented) [ ] R9 All DDL is idempotent (IF NOT EXISTS / OBJECT_ID / sys.indexes guards) [ ] R10 All identifiers lowercase snake_case; pure mapping tables have a _mappings suffix ``` #### Step A4 — Write the DDL Use the engine-specific guards (R9) — `CREATE TABLE IF NOT EXISTS` is not valid T-SQL: ```sql -- PostgreSQL / SQLite CREATE TABLE IF NOT EXISTS <table> (...); CREATE INDEX IF NOT EXISTS idx_... ON <table>(...); -- SQL Server IF OBJECT_ID(N'dbo.<table>', N'U') IS NULL CREATE TABLE dbo.<table> (...); IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_...' AND object_id = OBJECT_ID(N'dbo.<table>')) CREATE INDEX idx_... ON dbo.<table>(...); ``` Keep `CREATE INDEX` statements in a dedicated block after all `CREATE TABLE` statements. Start from the quick-reference templates at the end of the rules file. #### Step A5 — Apply to all schema files, then ship the upgrade path Apply to every in-scope dialect file, same column order, same position. Only the R8 divergences may differ. Then, **if the change adds a column to an existing table**, write the per-dialect `ALTER TABLE` (R0-UPGRADE-PATH) — `CREATE TABLE IF NOT EXISTS` does nothing to a database that already exists, so a column added to a `CREATE TABLE` body reaches fresh installs only. A new table or a new index needs no `ALTER`: its guarded `CREATE ... IF NOT EXISTS` / `OBJECT_ID` / `sys.indexes` form (R9, Step A4) already applies to fresh and already-provisioned databases alike. #### Step A6 — Verify on more than one dialect ```bash cd <component> && go build ./... && go test ./internal/repository/... ./internal/database/... ``` Then: start from an empty **SQLite** database; start from an empty **server dialect** (Postgres or SQL Server); and apply the `ALTER` to a **pre-existing** database from the previous release. Report which dialects were actually exercised and which were only edited. --- ### Workflow B — Reviewing existing DDL (PR / audit) #### Step B1 — Locate and read all schema files Use the glob above. Note which files are gateway-controller or event-gateway — those skip R3. #### Step B2 — Open the rules reference Read `references/api-platform-db-schema-rules.md`. Evaluate every rule group (R0–R10) in order. #### Step B3 — Record findings | Field | Value | |---|---| | **Rule** | e.g. `R3-NO-TEXT` | | **Table · column** | exact location | | **Severity** | `HIGH` (data safety / correctness) · `MEDIUM` (missing guarantee or index) · `LOW` (style) · `LEGACY-ACCEPTED` (shipped table, frozen by R0) | | **Finding** | what is wrong | | **Fix** | the exact DDL needed — **omit for `LEGACY-ACCEPTED`** | Two adjustments this repo requires: - **A shipped table's violation is `LEGACY-ACCEPTED`, not `HIGH`.** Record it in the deviations table of `.claude/rules/db-schema-changes.md` so later reviews stop re-reporting it. Do not propose remediation DDL. - **Blanket-missing findings collapse.** When a rule is violated uniformly across many tables, record one representative finding naming the pattern with a couple of examples — not one per table. Findings on new tables/columns in the diff are live and use the normal severities. #### Step B4 — Cross-check multi-engine alignment Verify all dialect files are structurally in sync (R8). Intentional type-level divergences are not findings. To compare one table across dialects: ```bash for f in platform-api/internal/database/schema*.sql; do echo "--- $f" awk '/CREATE TABLE.*<table>/,/\);/' "$f" | grep -oE '^\s+[a-z_]+' | tr -d ' ' done ``` #### Step B5 — Write findings to JSON Run from this skill's directory, with an absolute `--out` so the report lands in the project: ```bash node scripts/generate-schema-report.js \ --findings '<findings-json-array>' \ --schema '<path-to-schema-file>' \ --out "$(git rev-parse --show-toplevel)/schema-reports/schema-review.json" ``` Output shape: ```json { "meta": { "schema": "<path>", "reviewedAt": "<ISO-8601>", "rules": ["R0","R1","R2","R3","R4","R5","R6","R7","R8","R9","R10"] }, "summary": { "HIGH": 0, "MEDIUM": 0, "LOW": 0, "LEGACY-ACCEPTED": 0 }, "findings": [ { "id": "r3-001", "severity": "HIGH", "rule": "R3-NO-TEXT", "table": "<table>", "column": "<col>", "finding": "...", "fix": "..." } ] } ``` #### Step B6 — Report summary Produce a findings table sorted by severity. Include a "No issues" row for any rule group that passed cleanly — reviewers need to know what was checked. --- ## Quick-reference templates New entity table (Postgres and SQL Server), the standard column-type/width cheat sheet, and the junction/mapping table pattern (under **R1-COMPOSITE-PK**) all live in **`references/api-platform-db-schema-rules.md`**. Use them as the starting point in Step A4.
Ver en GitHub