SOTA Databases
Expert-level rules for the full lifecycle of a data layer: choosing an engine, modeling data, evolving schemas safely, writing efficient queries, handling concurrency, operating reliably at scale, securing data, and supporting vector/AI workloads. Postgres is the reference engine; rules call out where other systems (MySQL, Redis, document/columnar/vector stores) differ.
This skill operates in two modes. Determine the mode from the user's intent,
then load the relevant rules/ files per the index below. Do not load all
files preemptively — pick by task.
BUILD mode
Use when designing or implementing: new schemas, migrations, queries, ORM layers, caching, job queues, or database infrastructure.
- Engine and model first. Read
rules/01-choosing-and-modeling.mdbefore writing any DDL. Default to Postgres unless a rule there says otherwise. - Every schema change is a migration. Never hand the user raw DDL to run
ad hoc; produce migration files following
rules/02-schema-migrations.md(expand/contract, lock-aware, reversible-or-documented). - Design indexes with the queries, not after. When writing a query that
will run in production, state which index serves it. Follow
rules/03-queries-and-indexes.md. - State the concurrency story. For any write path: idempotency, isolation
level, locking strategy, retry behavior (
rules/04-transactions-concurrency.md). - Operational defaults are part of the design. Pooling, backups,
monitoring hooks, and retention are not "later" items
(
rules/05-reliability-and-scale.md,rules/06-security-and-compliance.md). - Prefer boring, well-trodden patterns. Novelty in the data layer is a cost, not a feature.
AUDIT mode
Use when reviewing an existing schema, migration set, query workload, ORM usage, or database configuration.
Procedure:
- Inventory: engine + version, schema (tables, indexes, constraints), migration tooling, ORM, pooling setup, backup/replication config.
- Load the rules files matching what exists (e.g., no vectors → skip 07).
- Check each rule; report deviations as findings. Verify claims against the actual schema/queries — never report a finding you have not confirmed in the code or DDL.
Severity conventions:
- CRITICAL — data loss, corruption, or breach is likely or already possible: untested/missing backups, SQL injection, unconstrained deletes, missing FK causing orphaned money/auth rows, RLS bypass, plaintext secrets.
- HIGH — production incident waiting to happen: non-CONCURRENT index on a hot table, table rewrite migration without expand/contract, missing unique constraint under concurrent writes, unbounded long transactions, no lock_timeout in migrations, offset pagination on large tables in hot paths.
- MEDIUM — correctness or performance debt: N+1 queries, SELECT *, missing composite index for a known query, soft delete without partial indexes, natural primary keys, missing updated_at/audit trail where required.
- LOW — hygiene: naming inconsistencies, missing comments on cryptic columns, redundant indexes, suboptimal types (e.g., varchar(255) cargo cult).
Finding format (one per finding):
[SEVERITY] <short title>
Where: <file:line | table/column | migration id>
Rule: <rules file + rule heading>
Evidence: <the offending DDL/SQL/code, quoted>
Impact: <what breaks, when, under what load>
Fix: <concrete change — exact SQL/DDL/code where possible>
Order findings by severity. End with a summary table: count per severity, and the top 3 fixes by risk-reduction-per-effort.
Rules index
| File | Read this when... |
|---|---|
rules/01-choosing-and-modeling.md |
Picking an engine (SQL vs NoSQL/KV/columnar/time-series/vector); designing tables; deciding normalization, JSONB usage, primary keys, soft deletes, audit/history tables, ledgers and account balances, multi-tenancy, or how absence is encoded (NULL/omitted property vs an in-band sentinel). |
rules/02-schema-migrations.md |
Writing or reviewing any migration; altering hot tables; planning zero-downtime schema changes; backfills; setting up migration tooling or testing. |
rules/03-queries-and-indexes.md |
Writing/reviewing queries or ORM code; reading EXPLAIN ANALYZE; choosing index types or composite column order; pagination; N+1 suspicion; CTEs and window functions. |
rules/04-transactions-concurrency.md |
Anything with concurrent writes: isolation levels, locking (FOR UPDATE, SKIP LOCKED, advisory), job queues, idempotency, deadlocks, long transactions, connection pooling. |
rules/05-reliability-and-scale.md |
Backups/PITR, replication and read replicas, partitioning, vacuum/bloat, monitoring, capacity planning, sharding decisions, Redis caching patterns and distributed locks. |
rules/06-security-and-compliance.md |
DB roles and grants, RLS, encryption at rest/in transit, SQL injection surface, PII columns, data retention and GDPR-style deletion. |
rules/07-vector-and-ai.md |
Embeddings, semantic/hybrid search, pgvector vs dedicated vector DBs (incl. Qdrant exposure hardening), embedding model versioning and re-indexing. |
rules/08-surrealdb-multimodel.md |
Building on or auditing SurrealDB: DEFINE ACCESS auth, system users and least privilege, parameterized SurrealQL, SCHEMAFULL + PERMISSIONS, capability flags, indexes, multi-model (embed/reference/graph edges), backups. |
Top 10 non-negotiables
Violations of these are at minimum HIGH severity in AUDIT mode and must not be introduced in BUILD mode.
- Postgres until proven otherwise. A second datastore needs a written reason that Postgres (with JSONB, partitioning, pgvector, LISTEN/NOTIFY) cannot meet — not a vibe.
- No natural primary keys. Surrogate keys only:
bigint GENERATED ALWAYS AS IDENTITYinternally, UUIDv7 when IDs are exposed or generated client-side. Never email, SSN, slug, or composite business fields as PK. - Expand/contract, always. No migration may break the currently deployed application version. Add → migrate code → backfill → contract, as separate deploys.
- Lock-aware DDL on hot tables.
CREATE INDEX CONCURRENTLY,SET lock_timeout, batched backfills,NOT VALID+VALIDATE CONSTRAINT. Never an unboundedALTER TABLErewrite or blocking index build on a table with traffic. - Constraints in the database, not only the app. Uniqueness, foreign keys, NOT NULL, and CHECK live in the schema. Application-level "validation only" uniqueness is a race condition, not a constraint.
- Every production query has a known index. If you cannot name the index
a query uses (or justify a seq scan), the query is not done. Keyset
pagination, no
SELECT *, no N+1. - Idempotent writes on every retryable path. Unique keys, upserts, or idempotency keys — any write that a client, queue, or webhook may retry must be safe to execute twice.
- A backup that has not been restored is not a backup. PITR configured, restores rehearsed, RPO/RTO stated. Replication is not backup.
- Least privilege at the database. The app role owns no schema, cannot DROP, and cannot read tables it does not use. Migrations run as a separate role. No superuser connection strings in app config.
- Transactions are short. No network calls, no user waits, no batch loops inside a transaction. Long transactions cause bloat, lock queues, and replication lag — treat any transaction over ~1s as a design bug.