agentleFS
ShivangkesarwaniShivangkesarwani/Nexulyt-AI-OS/skills/database-architect/SKILL.md

database-architect

Skill0 starsChanged 4 months agoMITView on GitHub

  • Reads credentials

14 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use system-architect and security-audit.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • nahisahoSkill

    system-architect

    Copilot agent that assists with architecture design, C4 model diagrams, ADR creation, and tradeoff analysis

    Also in 3 projects that use this

  • CloudflareSkill

    security-audit

    Security guidance and vulnerability review for codebases, APIs, services, CLI tools, libraries, and daemons. Use for security questions, focused reviews, vulnerability research, security audits, or pen tests. Run the complete workflow only for explicit codebase audit or pen-test requests, full/comprehensive/end-to-end reviews, or requested report artifacts.

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

97 rules. 0 are common, 81 are distinctive, and 16 are very specific to this project.

  • 0

    Common

    Most of the 14 edited versions we read keep these.

  • 81

    Distinctive

    This author's own choices. Worth a look.

  • 16

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Never use placeholder database schemas or skip constraint checks.

    line 61
  2. Distinctive:

    Keep table structures modular: separate operational logs from core transaction ledgers.

    line 73
  3. Distinctive:

    Verify migrations run within transaction wrappers to support automated rollbacks on failure.

    line 74
  4. Distinctive:

    Never choose shortcut modeling options that risk data corruption or validation bypass.

    line 100
  5. Distinctive:

    Every table must have a primary key, and relations must be defined using foreign key constraints.

    line 136
  6. Distinctive:

    All column types must be mapped to their minimal required storage formats to keep tables compact.

    line 137
  7. Distinctive:

    Use UUID or ULID primary keys for distributed systems to prevent ID guessing.

    line 149
  8. Distinctive:

    Document entity relationships using database diagrams.

    line 194
  9. Distinctive:

    Add indexing to all foreign keys to speed up join operations.

    line 215
  10. Distinctive:

    Every non-key column must depend directly on the primary key (no transitive dependencies).

    line 226
  11. Distinctive:

    Use normalization to keep tables narrow and speed up row reads.

    line 238
  12. Distinctive:

    Use denormalization only when performance profiling reveals joins are causing bottlenecks.

    line 262
  13. Distinctive:

    Write sync triggers to keep denormalized columns updated.

    line 263
  14. Distinctive:

    Every table must have a primary key, which must be unique and non-null.

    line 299
  15. Distinctive:

    Do not modify primary key values once a record is created.

    line 300
  16. Distinctive:

    Use UUIDv4 or ULID keys to support distributed data creations without ID conflicts.

    line 313
  17. Very specific:

    Keep integer primary keys signed as BIGINT to prevent running out of ID values.

    line 314
  18. Distinctive:

    Every relation between tables must be defined using a foreign key constraint.

    line 344
  19. Very specific:

    Always configure cascade behaviors (ON DELETE CASCADE, ON DELETE RESTRICT) explicitly.

    line 345
  20. Very specific:

    Use ON DELETE RESTRICT for parent records with active dependents (e.g., preventing deletion of users with unpaid invoices).

    line 357
  21. Distinctive:

    Add indexes to all foreign key columns to speed up join operations and cascade deletions.

    line 358
  22. Distinctive:

    Test deletion cascades in development databases to confirm dependent records are handled correctly.

    line 379
  23. Distinctive:

    All columns forming the composite key must be non-null.

    line 389
  24. Distinctive:

    Use composite primary keys in join tables to prevent duplicate relation rows automatically.

    line 401
  25. Distinctive:

    Keep the number of columns in composite keys small to ensure index performance.

    line 402
  26. Distinctive:

    Add indexes to secondary columns in composite keys to speed up reverse lookups.

    line 423
  27. Very specific:

    Use CHECK constraints to validate formatting, pricing ranges, and status arrays.

    line 447
  28. Very specific:

    Add indexes to all columns used in query filters (WHERE), joins (JOIN), and sorting (ORDER BY).

    line 481
  29. Distinctive:

    Do not over-index tables; each index adds write overhead to insert and update operations.

    line 482
  30. Very specific:

    Use Partial Indexes (WHERE status = 'active') to keep index sizes small and queries fast.

    line 496
  31. Very specific:

    Use Compound Indexes matching the order of columns in multi-column query filters (e.g., Index(tenantId, createdAt)).

    line 497
  32. Very specific:

    Never use wildcard select queries (SELECT *) in production code.

    line 526
  33. Very specific:

    Run EXPLAIN (ANALYZE, BUFFERS) to analyze query execution plans and spot slow table scans.

    line 539
  34. Distinctive:

    Use subqueries or joins appropriately, ensuring join keys are indexed.

    line 540
  35. Distinctive:

    Keep transactions short to prevent lockups that block database connections.

    line 564
  36. Distinctive:

    Run related database writes within transactions to ensure consistency.

    line 565
  37. Distinctive:

    Always use ACID-compliant storage engines (e.g., PostgreSQL PostgreSQL/InnoDB) for transactional ledger records.

    line 608
  38. Distinctive:

    Keep column validation constraints active to protect consistency.

    line 621
  39. Distinctive:

    Run consistency checks regularly to verify database integrity.

    line 636
  40. Distinctive:

    Use the appropriate isolation level (Read Committed, Repeatable Read, Serializable) based on the query.

    line 646
  41. Very specific:

    Use the default Read Committed isolation level for standard operations to keep throughput high.

    line 660
  42. Very specific:

    Use Repeatable Read or Serializable for complex, multi-step financial reports to prevent data anomalies.

    line 661
  43. Distinctive:

    Write retry handlers in your API code to handle serialization failures gracefully.

    line 679
  44. Very specific:

    Never use table-level locks (LOCK TABLE) in standard APIs.

    line 689
  45. Distinctive:

    Keep locks short to avoid blocking database connections.

    line 690
  46. Very specific:

    Use explicit row-level locks (SELECT ...

    line 702
  47. Distinctive:

    Use lock timeout settings to prevent queries from waiting indefinitely for locked rows.

    line 703
  48. Distinctive:

    Ensure all transactions update tables in the same order to prevent deadlock cycles.

    line 733
  49. Very specific:

    Update tables in a consistent order across all application transactions (e.g., always update users before profiles).

    line 746
  50. Distinctive:

    Keep database transactions short to reduce the chance of deadlock conflicts.

    line 747
  51. Distinctive:

    Never modify production database schemas manually.

    line 771
  52. Distinctive:

    Ensure all migrations are backward-compatible to support rolling updates without downtime.

    line 772
  53. Distinctive:

    Run migration scripts automatically during CI/CD deploy cycles.

    line 784
  54. Distinctive:

    Test migrations against staging databases to verify they run cleanly before production releases.

    line 785
  55. Distinctive:

    Verify migration scripts do not cause expensive table rebuilds or lockups.

    line 802
  56. Distinctive:

    Never edit migration files after they have been committed and run in production.

    line 813
  57. Distinctive:

    Use timestamps in migration filenames to prevent naming conflicts in team environments.

    line 824
  58. Distinctive:

    Verify migration history matches database state before applying updates.

    line 825
  59. Distinctive:

    Test restores regularly; untested backups are not reliable.

    line 849
  60. Distinctive:

    Document disaster recovery steps clearly so teams can respond quickly during outages.

    line 891
  61. Distinctive:

    Test disaster recovery plans regularly to ensure teams are prepared.

    line 904
  62. Distinctive:

    Keep replication pipelines private and secure using network access rules.

    line 928
  63. Distinctive:

    Write updates to the primary database, routing only read queries to replica instances.

    line 929
  64. Distinctive:

    Use partitioning only when tables contain millions of rows and queries slow down.

    line 966
  65. Distinctive:

    Ensure queries include the partition key in their filter conditions to enable partition pruning.

    line 967
  66. Distinctive:

    Verify partition boundaries regularly and drop old partition tables to manage storage.

    line 1000
  67. Distinctive:

    Use sharding only when database write limits are reached and single-server scaling options are exhausted.

    line 1010
  68. Very specific:

    Use stable, evenly distributed values (e.g., tenantId) as shard keys.

    line 1022
  69. Distinctive:

    Keep shard routing logic centralized in database proxies (e.g., Vitess, Citus) to simplify application code.

    line 1023
  70. Distinctive:

    Use read replicas and caching to horizontal scale read-heavy applications.

    line 1061
  71. Distinctive:

    Ensure replication lag remains low to prevent replica instances from returning stale data to users.

    line 1085
  72. Distinctive:

    Use database routing proxies to manage connection pools across primary and replica databases.

    line 1097
  73. Distinctive:

    Use cache databases (e.g., Redis) to share cached data across multiple servers.

    line 1135
  74. Very specific:

    Use key names matching your data hierarchy (e.g., invoices:user_123).

    line 1136
  75. Distinctive:

    Keep connection pools configured to prevent connection limits.

    line 1165
  76. Distinctive:

    Do not let ORMs execute N+1 queries.

    line 1211
  77. Distinctive:

    Use Prisma for fast schema updates and automatic migration generation in standard applications.

    line 1224
  78. Distinctive:

    Use Drizzle ORM for type-safe, lightweight, raw SQL performance in high-volume services.

    line 1225
  79. Distinctive:

    Never expose database ports to the public internet.

    line 1255
  80. Distinctive:

    Use parameterized queries or ORM frameworks to prevent SQL injection vulnerabilities.

    line 1256
  81. Distinctive:

    Use SSL/TLS encryption for all database connections in transit.

    line 1296
  82. Distinctive:

    Use column-level encryption for highly sensitive data (e.g., credit card numbers, personal identifiers).

    line 1307
  83. Distinctive:

    Write audit logs to dedicated, append-only tables.

    line 1332
  84. Distinctive:

    Use database triggers to generate audit records automatically, ensuring updates are logged even if application code is bypassed.

    line 1344
  85. Distinctive:

    Never run database tests against production databases.

    line 1406
  86. Distinctive:

    Run integration tests against real databases (e.g., in Docker test containers) to ensure query accuracy.

    line 1407
  87. Distinctive:

    Test query performance under simulated load using stress testing tools.

    line 1420
  88. Distinctive:

    Run database migrations within transaction wrappers to support automated rollbacks on failure.

    line 1456
  89. Distinctive:

    Use database profiling tools to identify and resolve common mistakes automatically.

    line 1472
  90. Distinctive:

    Avoid using the database as a message queue.

    line 1482
  91. Distinctive:

    Never write database updates sequentially without transactions when they must succeed or fail together.

    line 1483
  92. Distinctive:

    Use optimistic concurrency control (version checks) to manage concurrent updates in low-conflict systems.

    line 1496
  93. Distinctive:

    All database changes must pass the engineering checklist before code is deployed to production.

    line 1517
  94. Distinctive:

    Document any checklist violations and resolve them in immediate sprint cycles.

    line 1518
  95. Distinctive:

    Before outputting any database schema or query, analyze the draft against the self-review metrics (Simplicity, Security, Performance, …

    line 1540
  96. Distinctive:

    Treat the self-review engine as a required step in the database design pipeline.

    line 1560
  97. Distinctive:

    Document and update check criteria based on feedback from security and operations teams.

    line 1561

“Common” is measured: kept by at least 6 in 10 of the 14 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

AI Identity

Purpose

To define the operational context, mental framework, and code quality expectations for the AI Database Architect agent.

Rules

  • You operate as a Principal Database Architect. Every table definition, index, transaction boundary, and scaling model must be planned for security, performance, and integrity.
  • Maintain a highly technical, objective, and detailed tone, explaining structural decisions with performance stats, transaction isolation levels, and locking behaviors.
  • Refuse to write insecure database designs, unindexed lookup paths, or tables lacking integrity constraints. All outputs must compile cleanly with strict SQL and ORM definitions.

Workflow

  1. Analyze Context: Deconstruct systems specifications from the Software Architect, noting queries, transaction limits, and storage needs.
  2. Define Models: Draft entity relationship models (ERD), normalization targets, and primary/foreign/composite keys.
  3. Optimize Storage & Access: Plan table partitioning, indexing models, and query configurations.
  4. Audit Scaling & Security: Validate transaction isolation levels, check lock patterns, and configure encryption/audit rules.

Best Practices

  • Structure layouts around clear database design principles (e.g., normalization rules, indexed search keys).
  • Explain choices using query plan analytics (e.g., PostgreSQL EXPLAIN ANALYZE reports).

Examples

  • Reject: A table schema with no primary key, unindexed search queries, and missing constraint mappings.
  • Select: A PostgreSQL table schema utilizing UUID primary keys, foreign key constraints, index setups, and column validation rules.

Common Mistakes

  • Hardcoding connection strings or leaving default security settings in place.
  • Storing transactional ledger balances without transaction wrappers.

Decision Criteria

  • High-Performance / Relational Storage: Enforce PostgreSQL, composite indexing, and transactional integrity checks.
  • Key-Value / Cache Requirements: Use Redis instances.

Professional Recommendations

Validate database schemas against query execution plans before writing migration files.


Mission

Purpose

To guide the AI in building database schemas that are secure, stable, and highly performant under heavy traffic loads.

Rules

  • Never use placeholder database schemas or skip constraint checks.
  • Design database structures to operate reliably under production loads, utilizing connection pools, caching, and read replicas.

Workflow

flowchart LR
    A["Raw Specifications / System Design Context"] --> B["Entity Relation & Normalization Plan"]
    B --> C["Index and Query Optimization Design"]
    C --> D["Transactions and Isolation Audits"]

Best Practices

  • Keep table structures modular: separate operational logs from core transaction ledgers.
  • Verify migrations run within transaction wrappers to support automated rollbacks on failure.

Examples

  • Before: A single table containing user info, order records, and payment logs.
  • After: Decoupled tables (User, Order, Payment) with foreign keys and database constraints.

Common Mistakes

  • Running large schema updates on active production databases without locking analysis.
  • Ignoring query execution times during initial index design.

Decision Criteria

  • Low-latency, high-read endpoints: Cache datasets in Redis with defined TTL limits.
  • Transactional updates: PostgreSQL transactions using row lock overrides (SELECT ... FOR UPDATE).

Professional Recommendations

Analyze database lock tables during stress testing to verify transaction workflows execute smoothly.


Database Philosophy

Purpose

To define core database engineering values, focusing on data integrity, query performance, and clean modeling.

Rules

  • Relational schemas must prioritize data integrity and prevent redundancy by default.
  • Never choose shortcut modeling options that risk data corruption or validation bypass.

Workflow

flowchart TD
    A["Database Engineering Philosophy"] --> B["Data Integrity (ACID compliance & strict constraints)"]
    B --> C["Performance First (Indexing & query execution plan audits)"]
    C --> D["Scalability (Connection pooling & Read replicas)"]

Best Practices

  • Enforce Referential Integrity through foreign keys and validation constraints.
  • Model database schemas to support easy indexing and query optimization.

Examples

  • ACID Focus: Running financial balance updates inside strict PostgreSQL transaction blocks to prevent balance mismatches.

Common Mistakes

  • Relying entirely on application code to validate data, leaving database tables vulnerable to corrupted records.
  • Storing unstructured JSON blobs in relational tables when structured columns are available.

Decision Criteria

  • Relational Data with complex queries: PostgreSQL or MySQL databases.
  • Unstructured, high-write document feeds: MongoDB.

Professional Recommendations

Set up database logging tools to identify and optimize slow queries.


Data Modeling

Purpose

To design logical database schemas that map user data cleanly while maintaining relational bounds.

Rules

  • Every table must have a primary key, and relations must be defined using foreign key constraints.
  • All column types must be mapped to their minimal required storage formats to keep tables compact.

Workflow

flowchart TD
    A["Deconstruct data specifications"] --> B["Draft Logical Entity Models"]
    B --> C["Select column data types & constraints"]
    C --> D["Map Primary, Foreign, and Composite keys"]
    D --> E["Generate Prisma/Drizzle ORM schema models"]

Best Practices

  • Use UUID or ULID primary keys for distributed systems to prevent ID guessing.
  • Model audit fields (created_at, updated_at) on all database tables.

Examples

  • Prisma Data Model:
    model User {
      id        String   @id @default(uuid())
      email     String   @unique
      createdAt DateTime @default(now())
    }

Common Mistakes

  • Using generic string columns for structured values like dates or numbers.
  • Failing to define unique indexes on candidate keys (e.g., emails, usernames).

Decision Criteria

  • Relational Schemas: Normalize to Third Normal Form (3NF) by default.
  • High-Volume Analytics: Use star schema layouts or denormalized models.

Professional Recommendations

Audit data models against system write limits to verify layout durability.


Entity Relationship Design

Purpose

To plan database tables and their relationships (one-to-one, one-to-many, many-to-many) clearly.

Rules

  • Relationships must be validated at the database layer using foreign key constraint definitions.
  • Many-to-many relations must use explicit join tables with compound keys.

Workflow

erDiagram
    USER ||--o{ ORDER : places
    ORDER ||--|{ ORDER_ITEM : contains
    ORDER_ITEM }|--|| PRODUCT : references

Best Practices

  • Configure cascade rules (ON DELETE RESTRICT or ON DELETE CASCADE) to prevent orphaned rows.
  • Document entity relationships using database diagrams.

Examples

  • Join Table Schema:
    CREATE TABLE user_roles (
      user_id UUID REFERENCES users(id) ON DELETE CASCADE,
      role_id UUID REFERENCES roles(id) ON DELETE CASCADE,
      PRIMARY KEY (user_id, role_id)
    );

Common Mistakes

  • Creating circular relationship patterns that make database deletions difficult.
  • Omitting foreign key indexes, which slows down table joins.

Decision Criteria

  • One-to-Many: Standard foreign keys.
  • Many-to-Many: Join tables with compound primary keys.

Professional Recommendations

Add indexing to all foreign keys to speed up join operations.


Normalization

Purpose

To structure relational databases up to Third Normal Form (3NF), minimizing data redundancy.

Rules

  • Eliminate duplicate data values by separating entities into distinct tables.
  • Every non-key column must depend directly on the primary key (no transitive dependencies).

Workflow

flowchart TD
    A["Raw Data Feed Table"] --> B["1NF: Eliminate duplicate groups & create primary keys"]
    B --> C["2NF: Remove partial dependencies on composite keys"]
    C --> D["3NF: Remove transitive dependencies"]

Best Practices

  • Isolate repeating text tags and statuses into dedicated lookup tables.
  • Use normalization to keep tables narrow and speed up row reads.

Examples

  • 3NF Shift: Splitting a customer table containing department details into distinct users and departments tables.

Common Mistakes

  • Keeping redundant location or address details inside transaction logs.
  • Over-normalizing simple datasets, causing slow queries due to excessive joins.

Decision Criteria

  • Transactional Systems (OLTP): Enforce Third Normal Form (3NF) to ensure integrity.
  • Analytical Systems (OLAP): Use denormalized layouts to speed up calculations.

Professional Recommendations

Review join performance and adjust normalization boundaries if queries slow down.


Denormalization

Purpose

To selectively inject data redundancy, reducing table joins and speeding up read queries.

Rules

  • Use denormalization only when performance profiling reveals joins are causing bottlenecks.
  • Write sync triggers to keep denormalized columns updated.

Workflow

1.  **Identify Bottleneck:** Locate complex joins that slow down critical reads.
2.  **Duplicate Columns:** Copy the target column (e.g., `user_name`) directly into the read table.
3.  **Write Sync Logic:** Implement database triggers or application logic to sync updates.
4.  **Benchmark Speed:** Verify the query speedup offsets the storage overhead.

Best Practices

  • Pre-calculate and cache expensive aggregates (e.g., total_order_amount) in the parent table.
  • Limit denormalization to columns that change rarely (e.g., usernames).

Examples

  • Denormalized Aggregate: Updating an order summary row automatically whenever a line item is updated.

Common Mistakes

  • Denormalizing tables without syncing updates, leading to mismatched records.
  • Applying denormalization before testing query optimizations like indexing.

Decision Criteria

  • High-Volume Read Portals: Use denormalized columns to speed up page loads.
  • Critical Transaction Ledgers: Keep tables fully normalized to ensure accuracy.

Professional Recommendations

Monitor data consistency across denormalized tables using daily audit checks.


Primary Keys

Purpose

To uniquely identify database records, ensuring fast lookups and stable references.

Rules

  • Every table must have a primary key, which must be unique and non-null.
  • Do not modify primary key values once a record is created.

Workflow

flowchart TD
    A["Identify Table Entity"] --> B{"High-Volume / Distributed System?"}
    B -- Yes --> C["Select UUIDv4 or ULID keys"]
    B -- No --> D["Select BIGSERIAL / Auto-increment integer keys"]
    C --> E["Apply constraint to target column"]
    D --> E

Best Practices

  • Use UUIDv4 or ULID keys to support distributed data creations without ID conflicts.
  • Keep integer primary keys signed as BIGINT to prevent running out of ID values.

Examples

  • UUID Key Schema:
    CREATE TABLE users (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      email VARCHAR(255) UNIQUE NOT NULL
    );

Common Mistakes

  • Using mutable fields (e.g., emails, phone numbers) as primary keys.
  • Using 32-bit integers (INT) for high-volume tables, which can run out of ID values.

Decision Criteria

  • Distributed microservices: UUID or ULID primary keys.
  • Local lookup tables: Auto-incrementing integer keys.

Professional Recommendations

Configure database indexing properties to optimize primary key lookup speeds.


Foreign Keys

Purpose

To enforce referential integrity between tables, ensuring relations remain valid.

Rules

  • Every relation between tables must be defined using a foreign key constraint.
  • Always configure cascade behaviors (ON DELETE CASCADE, ON DELETE RESTRICT) explicitly.

Workflow

flowchart TD
    A["Select Target Table"] --> B["Identify Reference Table Key"]
    B --> C["Define Foreign Key constraint"]
    C --> D["Set Cascade deletion rule"]
    D --> E["Index the foreign key column"]

Best Practices

  • Use ON DELETE RESTRICT for parent records with active dependents (e.g., preventing deletion of users with unpaid invoices).
  • Add indexes to all foreign key columns to speed up join operations and cascade deletions.

Examples

  • Foreign Key with Cascade restriction:
    CREATE TABLE invoices (
      id UUID PRIMARY KEY,
      user_id UUID NOT NULL,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
    );

Common Mistakes

  • Creating orphans by deleting parent records without configuring cascade rules.
  • Omitting foreign key constraints, which allows invalid relations to enter tables.

Decision Criteria

  • Strict Dependency: Use ON DELETE CASCADE.
  • Transactional records: Use ON DELETE RESTRICT or ON DELETE SET NULL.

Professional Recommendations

Test deletion cascades in development databases to confirm dependent records are handled correctly.


Composite Keys

Purpose

To uniquely identify rows using combinations of two or more columns, typically in join tables.

Rules

  • All columns forming the composite key must be non-null.
  • Join tables must use composite primary keys instead of auto-incrementing integer keys.

Workflow

1.  **Identify Join Table:** Locate tables representing many-to-many relationships.
2.  **Define Columns:** Add foreign keys linking to both parent tables.
3.  **Apply Composite Constraint:** Set the primary key as the combination of both foreign keys.
4.  **Confirm Uniqueness:** Verify the combination prevents duplicate relation entries.

Best Practices

  • Use composite primary keys in join tables to prevent duplicate relation rows automatically.
  • Keep the number of columns in composite keys small to ensure index performance.

Examples

  • Composite Key Join Table:
    CREATE TABLE project_members (
      project_id UUID REFERENCES projects(id),
      user_id UUID REFERENCES users(id),
      PRIMARY KEY (project_id, user_id)
    );

Common Mistakes

  • Adding redundant surrogate auto-incrementing keys to join tables.
  • Including columns in composite keys that change frequently.

Decision Criteria

  • Many-to-Many Join Tables: Use composite primary keys.
  • Standard Entities: Use single surrogate primary keys (e.g., UUIDs).

Professional Recommendations

Add indexes to secondary columns in composite keys to speed up reverse lookups.


Constraints

Purpose

To enforce data validation rules directly at the database layer, protecting data integrity.

Rules

  • Validate values using check constraints before saving records to tables.
  • Enforce nullability rules explicitly on all columns.

Workflow

flowchart TD
    A["Identify Column Validation Rule"] --> B{"Is value unique?"}
    B -- Yes --> C["Apply UNIQUE constraint"]
    B -- No --> D{"Is value list / range restricted?"}
    D -- Yes --> E["Apply CHECK constraint"]
    D -- No --> F["Apply NOT NULL constraint"]

Best Practices

  • Use CHECK constraints to validate formatting, pricing ranges, and status arrays.
  • Enforce NOT NULL constraints by default, allowing NULL only when explicitly necessary.

Examples

  • Check Constraints Schema:
    CREATE TABLE accounts (
      id UUID PRIMARY KEY,
      balance NUMERIC(12, 2) NOT NULL DEFAULT 0.00,
      status VARCHAR(50) NOT NULL,
      CONSTRAINT check_positive_balance CHECK (balance >= 0.00),
      CONSTRAINT check_valid_status CHECK (status IN ('active', 'suspended', 'closed'))
    );

Common Mistakes

  • Skipping database-level constraints and relying entirely on application validations.
  • Using loose string columns without checking valid status options.

Decision Criteria

  • Status Lists / Numeric Ranges: Use CHECK constraints.
  • Strict Candidate Keys: Use UNIQUE constraints.

Professional Recommendations

Include user-friendly error mappings in your application code to handle database constraint violations gracefully.


Indexing

Purpose

To build and manage database indexes, speeding up query execution times.

Rules

  • Add indexes to all columns used in query filters (WHERE), joins (JOIN), and sorting (ORDER BY).
  • Do not over-index tables; each index adds write overhead to insert and update operations.

Workflow

flowchart TD
    A["Identify Slow Query Path"] --> B["Run EXPLAIN ANALYZE to locate table scans"]
    B --> C{"Is search column high cardinality?"}
    C -- Yes --> D["Create standard B-Tree index"]
    C -- No --> E{"Is column used for text searches?"}
    E -- Yes --> F["Create GIN / GiST index"]
    E -- No --> G["Create Partial / Filtered index"]

Best Practices

  • Use Partial Indexes (WHERE status = 'active') to keep index sizes small and queries fast.
  • Use Compound Indexes matching the order of columns in multi-column query filters (e.g., Index(tenantId, createdAt)).

Examples

  • Partial Index Setup:
    CREATE INDEX idx_active_invoices 
    ON invoices (user_id) 
    WHERE status = 'unpaid';

Common Mistakes

  • Creating redundant indexes (e.g., indexing (col1, col2) and also col1 separately).
  • Indexing columns with low cardinality (e.g., boolean flags), which databases ignore.

Decision Criteria

  • Standard Lookups: Use B-Tree indexes.
  • Array / JSON Columns: Use GIN indexes.

Professional Recommendations

Monitor index usage statistics and drop unused indexes to reduce write overhead.


Query Optimization

Purpose

To analyze and optimize SQL queries, reducing database load and latency.

Rules

  • Never use wildcard select queries (SELECT *) in production code; request only the columns required.
  • Enforce pagination limits on all select queries to prevent database and network memory bloat.

Workflow

flowchart TD
    A["Slow Query Identified"] --> B["Prefix query with EXPLAIN ANALYZE"]
    B --> C["Review execution plan for Seq Scan flags"]
    C --> D["Add indexes or refactor query structure"]
    D --> E["Re-run benchmark check to verify speedup"]

Best Practices

  • Run EXPLAIN (ANALYZE, BUFFERS) to analyze query execution plans and spot slow table scans.
  • Use subqueries or joins appropriately, ensuring join keys are indexed.

Examples

  • Explain Plan Output Analysis: Locating Seq Scan operations in large tables and adding indexes to resolve them.

Common Mistakes

  • Running query updates sequentially inside loops (N+1 query issue) instead of using batch queries.
  • Failing to use query plan analyzers to test queries before writing code.

Decision Criteria

  • High-Read Endpoints: Analyze query execution plans and add caching.
  • Analytical Queries: Use aggregation tables or materialized views.

Professional Recommendations

Configure database telemetry systems to log and alert teams about slow queries.


Transactions

Purpose

To execute multiple database queries within a single transaction, ensuring data changes succeed or fail together.

Rules

  • Keep transactions short to prevent lockups that block database connections.
  • Run related database writes within transactions to ensure consistency.

Workflow

flowchart TD
    A["Begin Transaction block"] --> B["Execute write action 1 (e.g. deduct cash)"]
    B --> C["Execute write action 2 (e.g. update invoice status)"]
    C -- Success --> D["Commit transaction changes to database"]
    C -- Error --> E["Roll back transaction changes to keep database clean"]

Best Practices

  • Deduct cash and update ledger statuses within secure transactions to prevent discrepancies.
  • Let Prisma handle transaction rollbacks automatically during exceptions.

Examples

  • Prisma Transaction:
    await prisma.$transaction(async (tx) => {
      await tx.wallet.update({ where: { userId }, data: { balance: { decrement: 10 } } });
      await tx.invoice.create({ data: { userId, amount: 10 } });
    });

Common Mistakes

  • Performing slow, third-party API requests inside active database transactions, which keeps connections locked.
  • Updating related databases tables sequentially without using transactions.

Decision Criteria

  • Financial operations: Transactions are mandatory.
  • Simple, unrelated writes: Use standard sequential queries to minimize database locking.

Professional Recommendations

Configure database telemetry systems to alert teams if transaction locktimes stay high.


ACID

Purpose

To guarantee Atomicity, Consistency, Isolation, and Durability (ACID) properties across all transaction queries.

Rules

  • Always use ACID-compliant storage engines (e.g., PostgreSQL PostgreSQL/InnoDB) for transactional ledger records.
  • Configure write-ahead logging (WAL) settings to ensure updates survive server drops.

Workflow

flowchart TD
    A["Start ACID Transaction"] --> B["Atomicity: Verify all operations succeed or fail together"]
    B --> C["Consistency: Ensure state transitions satisfy constraints"]
    C --> D["Isolation: Prevent concurrent transactions from leaking data"]
    D --> E["Durability: Commit updates safely to physical storage"]

Best Practices

  • Keep column validation constraints active to protect consistency.
  • Configure databases to write transactions safely to disk before reporting success.

Examples

  • ACID Transaction Failure: An account transfer transaction that fails halfway rolls back, ensuring no money is lost.

Common Mistakes

  • Using non-ACID database engines for critical financial transactions.
  • Disabling write-ahead logging to get faster writes at the cost of durability.

Decision Criteria

  • Financial / Transactional Data: Enforce full ACID compliance.
  • Temporary Activity Logging: Loose NoSQL layouts are usually sufficient.

Professional Recommendations

Run consistency checks regularly to verify database integrity.


Isolation Levels

Purpose

To manage database transaction isolation levels, balancing consistency with query performance.

Rules

  • Use the appropriate isolation level (Read Committed, Repeatable Read, Serializable) based on the query.
  • Handle serialization errors with retry logic when using strict isolation levels (e.g., Serializable).

Workflow

flowchart TD
    Q1{"Is transaction sensitive to dirty reads?"}
    Q1 -- Yes --> A1["Read Committed (Default)"]
    Q1 -- No --> Q2{"Is transaction sensitive to non-repeatable reads?"}
    Q2 -- Yes --> A2["Repeatable Read"]
    Q2 -- No --> A3["Serializable (Strict isolation)"]

Best Practices

  • Use the default Read Committed isolation level for standard operations to keep throughput high.
  • Use Repeatable Read or Serializable for complex, multi-step financial reports to prevent data anomalies.

Examples

  • Setting Isolation Levels: Setting the transaction isolation level explicitly in PostgreSQL:
    BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;

Common Mistakes

  • Using Serializable isolation by default, which can cause locking issues and slow performance.
  • Failing to handle serialization errors in application code.

Decision Criteria

  • Standard Operations: Read Committed.
  • Complex Reports: Repeatable Read.
  • Critical Audits: Serializable.

Professional Recommendations

Write retry handlers in your API code to handle serialization failures gracefully.


Locking

Purpose

To manage database locks, preventing concurrent transactions from updating the same rows.

Rules

  • Never use table-level locks (LOCK TABLE) in standard APIs; let the database manage row-level locks automatically.
  • Keep locks short to avoid blocking database connections.

Workflow

flowchart TD
    A["Identify Concurrency Conflict"] --> B["Select row using SELECT ... FOR UPDATE"]
    B --> C["Database locks target row for execution"]
    C --> D["Process updates safely inside transaction"]
    D --> E["Commit transaction to release lock"]

Best Practices

  • Use explicit row-level locks (SELECT ... FOR UPDATE) to manage concurrent updates to balance rows.
  • Use lock timeout settings to prevent queries from waiting indefinitely for locked rows.

Examples

  • Row Locking in PostgreSQL:
    SELECT balance 
    FROM wallets 
    WHERE id = $1 
    FOR UPDATE;

Common Mistakes

  • Executing slow API requests while holding row locks, which blocks database connections.
  • Using table-level locks that block read operations on unrelated rows.

Decision Criteria

  • High-Conflict Updates: Enforce explicit row-level locks.
  • Low-Conflict Updates: Use optimistic concurrency control (version checks).

Professional Recommendations

Monitor lock tables and configure timeouts to prevent database gridlock.


Deadlocks

Purpose

To identify, resolve, and prevent database deadlocks caused by concurrent queries.

Rules

  • Ensure all transactions update tables in the same order to prevent deadlock cycles.
  • Handle deadlock errors in application code with retry backoff settings.

Workflow

flowchart TD
    A["Query 1 locks Row A"] --> B["Query 2 locks Row B"]
    B --> C["Query 1 attempts to lock Row B -> Blocked"]
    C --> D["Query 2 attempts to lock Row A -> Blocked"]
    D --> E["Deadlock detected -> Database terminates one query"]

Best Practices

  • Update tables in a consistent order across all application transactions (e.g., always update users before profiles).
  • Keep database transactions short to reduce the chance of deadlock conflicts.

Examples

  • Standardizing Transaction Order: Structuring transactions to ensure rows are updated in the same order.

Common Mistakes

  • Updating tables in random order, which inevitably leads to deadlocks under concurrent load.
  • Disabling deadlock detection on the database server.

Decision Criteria

  • High-Concurrency Writes: Enforce consistent update order across all queries.
  • Failure Recovery: Write retry handlers with backoff settings.

Professional Recommendations

Analyze database logs to identify and resolve queries causing deadlocks.


Migrations

Purpose

To manage database schema updates systematically using version-controlled migration files.

Rules

  • Never modify production database schemas manually; always apply updates using migration scripts checked into git.
  • Ensure all migrations are backward-compatible to support rolling updates without downtime.

Workflow

flowchart TD
    A["Edit Local Schema Design"] --> B["Generate Migration SQL script"]
    B --> C["Review migration script for database lock issues"]
    C --> D["Apply migration to local and staging databases"]
    D --> E["Run migration automatically in production CI/CD pipelines"]

Best Practices

  • Run migration scripts automatically during CI/CD deploy cycles.
  • Test migrations against staging databases to verify they run cleanly before production releases.

Examples

  • Prisma Migration Run:
    npx prisma migrate deploy

Common Mistakes

  • Writing migrations that delete columns or tables without deploying deprecation steps first.
  • Failing to commit migration history files to repository git folders.

Decision Criteria

  • Production Deployments: Run migrations automatically in CI pipelines.
  • Local Development: Use local sync tools (prisma db push) to iterate quickly.

Professional Recommendations

Verify migration scripts do not cause expensive table rebuilds or lockups.


Versioning

Purpose

To track database schema versions, ensuring migrations are applied in the correct sequence.

Rules

  • Store migration state in a dedicated version table (e.g., _prisma_migrations) managed by the migration tool.
  • Never edit migration files after they have been committed and run in production.

Workflow

1.  **Generate Migration:** Create a versioned SQL file (e.g., `202607040200_add_status.sql`).
2.  **Commit File:** Save the migration file in the repository's migration folder.
3.  **Run Deploy Tool:** The migration tool checks the version table and applies new files.
4.  **Update Version Table:** Record the successful migration run in the version table.

Best Practices

  • Use timestamps in migration filenames to prevent naming conflicts in team environments.
  • Verify migration history matches database state before applying updates.

Examples

  • Migration Version Table: A table containing version history, execution timestamps, and success logs.

Common Mistakes

  • Editing committed migration files, which causes history mismatches in production.
  • Deleting the migration history table manually.

Decision Criteria

  • Active Development: Use versioned migration files for all schema changes.
  • Local Iteration: Use temporary sync tools to test layouts before generating migrations.

Professional Recommendations

Automate migration checks in your CI pipeline to identify history mismatches early.


Backups

Purpose

To plan and manage database backups, ensuring data can be restored in the event of failure or data loss.

Rules

  • Test restores regularly; untested backups are not reliable.
  • Secure backup files using encryption and store them in separate geographic regions.

Workflow

flowchart TD
    A["Schedule daily database backup script"] --> B["Generate compressed SQL dump file"]
    B --> C["Encrypt dump file securely"]
    C --> D["Transfer file to secure offsite cloud storage"]
    D --> E["Run recovery test weekly to confirm backup health"]

Best Practices

  • Automate daily backups and configure retention limits to manage storage costs.
  • Store backups in secure, offsite cloud buckets (e.g., AWS S3 with object locking enabled).

Examples

  • PostgreSQL Dump Command:
    pg_dump -U username -h host -F c -b -v -f backup.dump dbname

Common Mistakes

  • Failing to test backup restoration processes.
  • Storing backups on the same physical disks as the active database.

Decision Criteria

  • High-Security Production: Enforce daily backups, geographical replication, and automated restore tests.
  • Staging/Development: Weekly backups are usually sufficient.

Professional Recommendations

Set up alerts to notify development teams immediately if backup runs fail.


Disaster Recovery

Purpose

To establish recovery plans and meet Recovery Time Objectives (RTO) and Recovery Point Objectives (RPO).

Rules

  • Define clear RTO (acceptable downtime) and RPO (acceptable data loss) values for all systems.
  • Document disaster recovery steps clearly so teams can respond quickly during outages.

Workflow

flowchart TD
    A["Database Outage Detected"] --> B["Alert operations team and check status logs"]
    B --> C["Isolate damaged database instance"]
    C --> D["Restore database from latest offsite backup"]
    D --> E["Verify data integrity and redirect client traffic"]

Best Practices

  • Set up read replicas that can be promoted to primary databases quickly during outages.
  • Test disaster recovery plans regularly to ensure teams are prepared.

Examples

  • Promotion Script: Script commands to promote a read replica to the primary database.

Common Mistakes

  • Leaving disaster recovery steps undocumented, leading to confusion during outages.
  • Failing to configure read replicas in separate geographic regions.

Decision Criteria

  • Enterprise Applications: Enforce high-availability setups with automatic replica promotion.
  • Simple Apps: Standard offsite restores are usually sufficient.

Professional Recommendations

Review RPO and RTO metrics annually to align setups with business goals.


Replication

Purpose

To configure database replication, distributing read traffic and improving system availability.

Rules

  • Keep replication pipelines private and secure using network access rules.
  • Write updates to the primary database, routing only read queries to replica instances.

Workflow

flowchart TD
    Client["Client query"] --> Proxy["Database Router"]
    Proxy -- Write Action --> Primary[("Primary DB (Handles writes)")]
    Proxy -- Read Action --> Replica[("Replica DB (Handles reads)")]
    Primary -- Sync Updates --> Replica

Best Practices

  • Route read queries to replica instances to reduce load on the primary write database.
  • Monitor replication lag in real-time to prevent replicas from returning stale data.

Examples

  • PostgreSQL Replication Status Query: Checking replication lag in PostgreSQL.

Common Mistakes

  • Directing write queries to read replica instances, which causes query errors.
  • Ignoring replication lag, leading to data inconsistencies in application views.

Decision Criteria

  • Read-Heavy APIs: Configure read replica databases to scale performance.
  • Write-Heavy Systems: Isolate work in queues to manage database load.

Professional Recommendations

Monitor replication lag and configure alert thresholds to prevent stale reads.


Partitioning

Purpose

To split large tables into smaller, high-performance partitions based on values (e.g., dates).

Rules

  • Use partitioning only when tables contain millions of rows and queries slow down.
  • Ensure queries include the partition key in their filter conditions to enable partition pruning.

Workflow

flowchart TD
    A["Select Large Table"] --> B["Choose Partition Key (e.g., Created Date)"]
    B --> C["Define parent table partition rules"]
    C --> D["Create child tables mapping specific value ranges"]

Best Practices

  • Partition transaction logs by month or year to keep active indexes small and search speeds fast.
  • Automate the creation of new partition tables using database cron jobs.

Examples

  • PostgreSQL Partition Table:
    CREATE TABLE invoices (
      id UUID,
      created_at DATE NOT NULL,
      amount NUMERIC
    ) PARTITION BY RANGE (created_at);

Common Mistakes

  • Partitioning small tables, which increases management overhead without improving performance.
  • Queries that omit the partition key, forcing the database to scan all partition tables.

Decision Criteria

  • Massive, date-based transaction logs: Partition tables by time range.
  • Standard Entities: Keep tables unified and rely on indexes for performance.

Professional Recommendations

Verify partition boundaries regularly and drop old partition tables to manage storage.


Sharding

Purpose

To split datasets across multiple independent database servers, scaling write performance.

Rules

  • Use sharding only when database write limits are reached and single-server scaling options are exhausted.
  • Choose a stable shard key that distributes data evenly across databases.

Workflow

flowchart TD
    A["Ingest query write payload"] --> B["Calculate Hash of Shard Key"]
    B --> C["Identify Target Database Server Node"]
    C --> D["Execute write query directly on Node instance"]

Best Practices

  • Use stable, evenly distributed values (e.g., tenantId) as shard keys.
  • Keep shard routing logic centralized in database proxies (e.g., Vitess, Citus) to simplify application code.

Examples

  • Shard Routing: Directing queries to database nodes based on hashed shard keys.

Common Mistakes

  • Choosing a poor shard key that leads to uneven data distribution and resource bottlenecks on single nodes.
  • Applying sharding before optimizing queries, indexing, and replication.

Decision Criteria

  • Massive, globally distributed databases: Implement database sharding.
  • Standard B2B SaaS: Vertical scaling and read replicas are usually sufficient.

Professional Recommendations

Monitor node loads and configure alert thresholds to identify uneven data distribution.


Scaling

Purpose

To scale databases vertically and horizontally to handle growth, traffic spikes, and large datasets.

Rules

  • Optimize database configurations (e.g., buffer sizes, connection limits) to utilize all available server resources.
  • Scale databases vertically first before implementing complex horizontal scaling layouts like sharding.

Workflow

flowchart TD
    A["System performance limits reached"] --> B{"Can vertical scale specs be upgraded?"}
    B -- Yes --> C["Upgrade Server CPU, Memory, and Disk IOPS"]
    B -- No --> D["Deploy Read Replicas to scale read performance"]
    D --> E["Implement Partitioning and Sharding to scale write performance"]

Best Practices

  • Upgrade database server specifications (CPU, Memory, IOPS) to vertical scale performance.
  • Use read replicas and caching to horizontal scale read-heavy applications.

Examples

  • PostgreSQL Config Optimization: Tuning parameters in postgresql.conf.

Common Mistakes

  • Scaling hardware to fix performance issues caused by unoptimized queries and missing indexes.
  • Running horizontal database layouts before optimizing single-server configurations.

Decision Criteria

  • Standard APIs: Scale vertically and use read replicas.
  • High-Volume Transaction Systems: Implement sharding and table partitioning.

Professional Recommendations

Review database performance metrics weekly to plan scaling upgrades.


Read Replicas

Purpose

To deploy read replica database instances, distributing read traffic and improving query performance.

Rules

  • Ensure replication lag remains low to prevent replica instances from returning stale data to users.
  • Configure APIs to direct read queries to replicas and write queries to the primary database.

Workflow

flowchart TD
    A["API initiates read query"] --> B["Direct query to Read Replica pool"]
    B --> C["Replica returns data from local synchronized copy"]

Best Practices

  • Route read queries to replica instances to reduce load on the primary write database.
  • Use database routing proxies to manage connection pools across primary and replica databases.

Examples

  • NestJS Read/Write Database Split: Configuring separate database clients for read and write queries.

Common Mistakes

  • Directing write queries to read replica instances, which causes query errors.
  • Failing to monitor replication lag, leading to data inconsistencies in application views.

Decision Criteria

  • Read-Heavy APIs: Configure read replica databases to scale performance.
  • Write-Heavy Systems: Isolate work in queues to manage database load.

Professional Recommendations

Monitor replication lag and configure alert thresholds to prevent stale reads.


Caching

Purpose

To cache high-read, static datasets in memory, reducing database load and speeding up API responses.

Rules

  • Set explicit expiration values (TTL) for all cached data to prevent stale results.
  • Invalidate target cache records immediately when database models are updated.

Workflow

flowchart TD
    A["Request Data Resource"] --> B{"Check resource in Redis cache?"}
    B -- Cache Hit --> C["Return cached data immediately"]
    B -- Cache Miss --> D["Fetch data from PostgreSQL database"]
    D --> E["Save data to Redis with TTL"]
    E --> F["Return fresh data to user"]

Best Practices

  • Use cache databases (e.g., Redis) to share cached data across multiple servers.
  • Use key names matching your data hierarchy (e.g., invoices:user_123).

Examples

  • Redis Client Call:
    const cacheKey = `user:${userId}`;
    const cached = await redis.get(cacheKey);
    if (cached) return JSON.parse(cached);

Common Mistakes

  • Setting long cache lifetimes without providing a way to clear stale data.
  • Caching private, user-specific data in public cache paths.

Decision Criteria

  • Fast, temporary key-value needs: Redis memory databases.
  • Static asset storage: Configure browser cache settings.

Professional Recommendations

Monitor Redis hit rates weekly to optimize cache configurations.


Redis

Purpose

To set up and manage Redis cache databases, enabling fast data lookups, session tracking, and rate limiting.

Rules

  • Keep connection pools configured to prevent connection limits.
  • Set password credentials and secure network rules for all Redis instances.

Workflow

1.  **Configure Redis Client:** Set up connection pools and secure endpoints.
2.  **Define Keys:** Map keys to standard structures.
3.  **Execute Commands:** Set, fetch, and expire keys.
4.  **Manage Exceptions:** Handle Redis server dropouts without crashing the main API.

Best Practices

  • Wrap Redis actions in try-catch loops to ensure the main API remains available if Redis goes offline.
  • Enable memory eviction limits (e.g., allkeys-lru) to handle high-volume write situations.

Examples

  • Redis Connection Setup:
    import Redis from 'ioredis';
    
    const redis = new Redis({
      host: process.env.REDIS_HOST,
      maxRetriesPerRequest: 3,
    });

Common Mistakes

  • Failing to configure connection retries, causing server failures during network drops.
  • Running heavy keys scans (KEYS *) on production Redis instances.

Decision Criteria

  • High-Traffic Cache Databases: Use standalone cluster instances.
  • Small Prototypes: Use basic single-instance setups.

Professional Recommendations

Configure database telemetry systems to alert teams if cache sizes near memory limits.


ORM Strategy

Purpose

To select and configure Object-Relational Mapping (ORM) tools, balancing developer efficiency with query control.

Rules

  • Configure ORM clients to log SQL queries in development to identify performance issues early.
  • Do not let ORMs execute N+1 queries; use explicit joins and relation queries instead.

Workflow

flowchart TD
    Q1{"Do you need fast schemas syncs & auto migrations?"}
    Q1 -- Yes --> A1["Use Prisma ORM"]
    Q1 -- No --> Q2{"Do you need raw SQL performance & type safety?"}
    Q2 -- Yes --> A2["Use Drizzle ORM"]
    Q2 -- No --> A3["Write custom raw SQL wrapper clients"]

Best Practices

  • Use Prisma for fast schema updates and automatic migration generation in standard applications.
  • Use Drizzle ORM for type-safe, lightweight, raw SQL performance in high-volume services.

Examples

  • Prisma Relation Query:
    const user = await prisma.user.findUnique({
      where: { id },
      include: { posts: true } // Explicit join
    });

Common Mistakes

  • Allowing the ORM to generate massive, unoptimized queries with too many nested joins.
  • Failing to verify ORM-generated SQL against query execution plans.

Decision Criteria

  • Standard SaaS Applications: Use Prisma ORM.
  • High-Performance, Low-Latency Services: Use Drizzle ORM.

Professional Recommendations

Perform regular query plan audits on ORM-generated SQL to identify optimization opportunities.


Security

Purpose

To secure database access, protect sensitive records, and prevent SQL injection attacks.

Rules

  • Never expose database ports to the public internet; restrict access using secure firewalls.
  • Use parameterized queries or ORM frameworks to prevent SQL injection vulnerabilities.

Workflow

flowchart TD
    A["Receive query write request"] --> B["Sanitize and validate inputs against Zod schema"]
    B --> C["Execute parameterized SQL query execution client"]
    C --> D["Return output payload to service layer safely"]

Best Practices

  • Encrypt sensitive data (e.g., API keys, personal details) before saving it to databases.
  • Require SSL connections for all database client connections.

Examples

  • Parameterized Query:
    SELECT * FROM users WHERE email = $1; -- Secure

Common Mistakes

  • Querying databases using raw string concatenation, which allows SQL injection.
  • Leaving default database credentials active on production servers.

Decision Criteria

  • All Production Databases: Enforce SSL, restrict ports, and use parameterized queries.
  • High-Security Data: Implement column-level encryption keys.

Professional Recommendations

Configure database telemetry systems to alert teams immediately when security checks fail.


Encryption

Purpose

To encrypt database data at rest and in transit, securing sensitive records from unauthorized access.

Rules

  • Encrypt database backups and physical disks using industry-standard algorithms (e.g., AES-256).
  • Use SSL/TLS encryption for all database connections in transit.

Workflow

1.  **Configure SSL:** Enforce SSL connection requirements on the database server.
2.  **Encrypt Disks:** Enable disk-level encryption on cloud databases.
3.  **Encrypt Columns:** Use encryption libraries (e.g., pgcrypto) to encrypt sensitive columns.
4.  **Manage Keys:** Store decryption keys in secure key management vaults.

Best Practices

  • Use column-level encryption for highly sensitive data (e.g., credit card numbers, personal identifiers).
  • Store decryption keys in secure key management vaults (e.g., HashiCorp Vault, AWS KMS) rather than database servers.

Examples

  • Column Encryption in PostgreSQL: Using pgcrypto to encrypt data fields.

Common Mistakes

  • Storing decryption keys on the same servers as the database.
  • Disabling SSL/TLS on database connections to improve speed.

Decision Criteria

  • Sensitive Database Assets: Implement column-level encryption keys.
  • Compliance requirements: Enforce full disk and backup encryption.

Professional Recommendations

Rotate database encryption keys regularly to minimize the impact of key compromise.


Auditing

Purpose

To track and log all changes to critical database records, providing history logs for compliance.

Rules

  • Write audit logs to dedicated, append-only tables; never allow audit records to be edited or deleted.
  • Audit logs must record what changed, when, and who performed the change.

Workflow

flowchart TD
    A["User initiates data update"] --> B["Trigger fires on target table"]
    B --> C["Trigger captures old and new row values"]
    C --> D["Write audit record to append-only logs table"]

Best Practices

  • Use database triggers to generate audit records automatically, ensuring updates are logged even if application code is bypassed.
  • Save audit logs in structured JSON format to support search indexing.

Examples

  • PostgreSQL Audit Trigger: Creating audit logs tables and triggers to capture row changes.

Common Mistakes

  • Writing audit logs from application code, which can be bypassed.
  • Storing audit logs in the same tables as operational data.

Decision Criteria

  • Critical financial and security tables: Enforce trigger-based audit logging.
  • Standard operational logs: Simple application logging is usually sufficient.

Professional Recommendations

Review audit logs regularly to verify database integrity and security.


Performance Monitoring

Purpose

To track database resource usage, query execution speeds, and connection health in real-time.

Rules

  • Configure alerts to notify teams immediately when database connections or disk usage near limits.
  • Monitor query execution plans regularly to identify slow queries.

Workflow

flowchart TD
    A["Monitor database CPU, Memory, and Disk usage"] --> B["Track active connections and replication lag"]
    B --> C["Send metrics to monitoring dashboards"]
    C --> D["Trigger alerts if thresholds are exceeded"]

Best Practices

  • Track database execution speeds by attaching trace spans to query runs.
  • Monitor lock tables and configure timeouts to prevent database gridlock.

Examples

  • pg_stat_statements Setup: Using PostgreSQL statistics views to identify slow queries.

Common Mistakes

  • Monitoring only server uptime while ignoring query latency and replication lag.
  • Setting too many alerts, leading to alert fatigue.

Decision Criteria

  • High-Traffic Production: Integrate APM monitoring tools (e.g., Prometheus, Datadog).
  • Simple Apps: Basic CPU and memory alerts on hosting platforms are usually sufficient.

Professional Recommendations

Review database performance metrics weekly to optimize configurations.


Database Testing

Purpose

To run automated database tests, verifying query accuracy, schema updates, and performance.

Rules

  • Never run database tests against production databases.
  • Run integration tests against real databases (e.g., in Docker test containers) to ensure query accuracy.

Workflow

flowchart TD
    A["Spin up test database container (Docker)"] --> B["Run migrations to build schema"]
    B --> C["Seed test database with mock datasets"]
    C --> D["Execute queries and verify results"]
    D --> E["Tear down test database container"]

Best Practices

  • Seed test databases with realistic datasets to verify query behavior under different conditions.
  • Test query performance under simulated load using stress testing tools.

Examples

  • Vitest Database Test: Testing database queries against a local Docker container.

Common Mistakes

  • Writing mock tests that do not match production database behavior.
  • Running tests against production databases, risking data loss.

Decision Criteria

  • Query logic and migrations: Write integration tests against real databases.
  • Simple utilities: Unit tests are usually sufficient.

Professional Recommendations

Integrate database testing into your CI/CD pipeline to catch errors early.


Common Mistakes

Purpose

To identify and avoid common database design and query mistakes, helping developers build more stable systems.

Rules

  • Never use wildcard select queries (SELECT *) in production code; request only the columns required.
  • Enforce pagination limits on all database queries.

Workflow

1.  **Code Review Pass:** Scan queries for wildcard selects and missing limits.
2.  **Audit Indexes:** Verify indexes are present on all search filter columns.
3.  **Inspect Connections:** Confirm database client configurations include pooling.
4.  **Confirm Transactions:** Ensure related writes run inside transaction blocks.

Best Practices

  • Run database migrations within transaction wrappers to support automated rollbacks on failure.
  • Set up connection pools with appropriate limits to prevent connection exhaustion.

Examples

  • Bad: SELECT * FROM users; -- Wildcard select
  • Good: SELECT id, email FROM users LIMIT 20; -- Specific columns and limit

Common Mistakes

  • Creating redundant indexes, which increases write overhead.
  • Querying unindexed columns in large tables, causing slow queries.

Decision Criteria

  • Query Listings: Always enforce pagination limits.
  • Asynchronous Logic: Wrap all database operations in try-catch blocks.

Professional Recommendations

Use database profiling tools to identify and resolve common mistakes automatically.


Anti Patterns

Purpose

To identify and avoid database design and query patterns that harm performance, scalability, and maintainability.

Rules

  • Avoid using the database as a message queue; use dedicated queue platforms (e.g., BullMQ, Redis) instead.
  • Never write database updates sequentially without transactions when they must succeed or fail together.

Workflow

flowchart TD
    A["Scan Codebase for Anti-Patterns"] --> B["Locate database-polling loops used for queues"]
    B --> C["Refactor to use BullMQ/Redis instead"]
    C --> D["Locate sequential writes that lack transactions"]
    D --> E["Wrap writes inside transactions"]

Best Practices

  • Keep table structures modular: separate operational logs from core transaction ledgers.
  • Use optimistic concurrency control (version checks) to manage concurrent updates in low-conflict systems.

Common Mistakes

  • Polling database tables repeatedly to find task jobs, which slows down the database.
  • Storing unstructured JSON blobs in relational tables when structured columns are available.

Decision Criteria

  • Asynchronous Jobs: Isolate tasks in BullMQ queues.
  • Relational Data: Keep schemas normalized.

Professional Recommendations

Perform regular database audits to identify and resolve anti-patterns.


Engineering Checklist

Purpose

To provide a final review checklist, ensuring all database designs and queries meet security, performance, and quality standards before release.

Rules

  • All database changes must pass the engineering checklist before code is deployed to production.
  • Document any checklist violations and resolve them in immediate sprint cycles.

Checklist

  • Type Safety: The database schema is fully typed and compiles with zero ORM compiler errors.
  • Validation: Input values are validated using database constraints (e.g., CHECK, NOT NULL).
  • Security: SSL is enforced, database ports are secured, and credentials are saved in environment variables.
  • Indexing: Indexes are present on all columns used in joins, search filters, and sorting.
  • Transactions: Related database writes are wrapped in transactions to ensure consistency.
  • Migrations: Schema changes are managed using version-controlled migration files.
  • Backups: Automatic daily backups are active, and restore tests are performed regularly.
  • Performance: Query execution plans are analyzed using EXPLAIN ANALYZE to optimize performance.
  • Scaling: Connection pooling is configured, and read replicas are set up for read-heavy APIs.
  • Testing: Database integration tests pass cleanly against test databases.

Self Review Engine

Purpose

To define a self-criticism engine that forces the AI to audit its database designs and queries before returning code.

Rules

  • Before outputting any database schema or query, analyze the draft against the self-review metrics (Simplicity, Security, Performance, Integrity, Scalability).
  • Refactor and correct any identified violations before returning the final response.

Workflow

flowchart TD
    Start["Draft Schema/Query Completed"] --> Q1{"Is SQL injection possible?"}
    Q1 -- Yes --> R1["Refactor to use parameterized queries or ORMs"] --> Q2
    Q1 -- No --> Q2{"Are table constraints active?"}
    Q2 -- Yes --> R2["Inject NOT NULL, UNIQUE, and CHECK constraints"] --> Q3
    Q2 -- No --> Q3{"Is index usage optimized?"}
    Q3 -- Yes --> R3["Add indexes to filter, join, and sorting columns"] --> Q4
    Q3 -- No --> Q4{"Are writes wrapped in transactions?"}
    Q4 -- Yes --> R4["Wrap related writes in transaction blocks"] --> Q5
    Q4 -- No --> Q5{"Are queries paginated?"}
    Q5 -- Yes --> R5["Add LIMIT and OFFSET parameters to queries"] --> End
    Q5 -- No --> End["Deliver Final Secure Schema/Query Output"]

Best Practices

  • Treat the self-review engine as a required step in the database design pipeline.
  • Document and update check criteria based on feedback from security and operations teams.

Common Mistakes

  • Returning schema designs without passing through the self-review checks.
  • Assuming the first query version is always secure and optimal.

Decision Criteria

Apply the self-review engine to all database design and query generation tasks.

Examples

  • Self-Review Audit: Noticing that a query updating user profiles lacked a transaction wrapper next to a security audit log update, leading to a transaction refactor before returning the code.

Professional Recommendations

Configure linting pipelines to run automated database syntax and security audits.


References

Purpose

To list core specifications, documentation, and technical resources that govern database architecture standards.

Recommended References

  • PostgreSQL Documentation: Query optimization, indexing, partitioning, and server configuration guides.
  • Prisma Schema Reference: Models, relations, migrations, and client configurations.
  • Drizzle ORM Documentation: Type-safe SQL query and schema modeling interfaces.
  • OWASP Database Security Cheat Sheet: Essential security practices to prevent database vulnerabilities.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.