Claude Cursor opencode Skill

database-design

Database design principles and decision-making. Schema design, indexing strategy, ORM selection, serverless databases.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download vodailocz-kilo-kit-mcp-skills_engineering_database-design-0448e6c.zip · 6 KB
Part of vodailocz/kilo-kit-mcp — 142 skills

Install

skills CLI npx skills add https://github.com/VoDaiLocz/kilo-kit-mcp/tree/main/skills/engineering/database-design
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vodailocz-kilo-kit-mcp@llmmart
Git git clone https://github.com/VoDaiLocz/kilo-kit-mcp.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole vodailocz/kilo-kit-mcp collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Database Design

Learn to THINK, not copy SQL patterns.

🎯 Selective Reading Rule

Read ONLY files relevant to the request! Check the content map, find what you need.

File Description When to Read
database-selection.md PostgreSQL vs Neon vs Turso vs SQLite Choosing database
orm-selection.md Drizzle vs Prisma vs Kysely Choosing ORM
schema-design.md Normalization, PKs, relationships Designing schema
indexing.md Index types, composite indexes Performance tuning
optimization.md N+1, EXPLAIN ANALYZE Query optimization
migrations.md Safe migrations, serverless DBs Schema changes

⚠️ Core Principle

  • ASK user for database preferences when unclear
  • Choose database/ORM based on CONTEXT
  • Don't default to PostgreSQL for everything

Decision Checklist

Before designing schema:

  • Asked user about database preference?
  • Chosen database for THIS context?
  • Considered deployment environment?
  • Planned index strategy?
  • Defined relationship types?

Anti-Patterns

❌ Default to PostgreSQL for simple apps (SQLite may suffice) ❌ Skip indexing ❌ Use SELECT * in production ❌ Store JSON when structured data is better ❌ Ignore N+1 queries

Files (kilo-kit-mcp)
  • scripts
    • schema_validator.py 5.2 KB
      #!/usr/bin/env python3
      """
      Schema Validator - Database schema validation
      Validates Prisma schemas and checks for common issues.
      
      Usage:
          python schema_validator.py <project_path>
      
      Checks:
          - Prisma schema syntax
          - Missing relations
          - Index recommendations
          - Naming conventions
      """
      
      import sys
      import json
      import re
      from pathlib import Path
      from datetime import datetime
      
      # Fix Windows console encoding
      try:
          sys.stdout.reconfigure(encoding='utf-8', errors='replace')
      except:
          pass
      
      
      def find_schema_files(project_path: Path) -> list:
          """Find database schema files."""
          schemas = []
          
          # Prisma schema
          prisma_files = list(project_path.glob('**/prisma/schema.prisma'))
          schemas.extend([('prisma', f) for f in prisma_files])
          
          # Drizzle schema files
          drizzle_files = list(project_path.glob('**/drizzle/*.ts'))
          drizzle_files.extend(project_path.glob('**/schema/*.ts'))
          for f in drizzle_files:
              if 'schema' in f.name.lower() or 'table' in f.name.lower():
                  schemas.append(('drizzle', f))
          
          return schemas[:10]  # Limit
      
      
      def validate_prisma_schema(file_path: Path) -> list:
          """Validate Prisma schema file."""
          issues = []
          
          try:
              content = file_path.read_text(encoding='utf-8', errors='ignore')
              
              # Find all models
              models = re.findall(r'model\s+(\w+)\s*{([^}]+)}', content, re.DOTALL)
              
              for model_name, model_body in models:
                  # Check naming convention (PascalCase)
                  if not model_name[0].isupper():
                      issues.append(f"Model '{model_name}' should be PascalCase")
                  
                  # Check for id field
                  if '@id' not in model_body and 'id' not in model_body.lower():
                      issues.append(f"Model '{model_name}' might be missing @id field")
                  
                  # Check for createdAt/updatedAt
                  if 'createdAt' not in model_body and 'created_at' not in model_body:
                      issues.append(f"Model '{model_name}' missing createdAt field (recommended)")
                  
                  # Check for @relation without fields
                  relations = re.findall(r'@relation\([^)]*\)', model_body)
                  for rel in relations:
                      if 'fields:' not in rel and 'references:' not in rel:
                          pass  # Implicit relation, ok
                  
                  # Check for @@index suggestions
                  foreign_keys = re.findall(r'(\w+Id)\s+\w+', model_body)
                  for fk in foreign_keys:
                      if f'@@index([{fk}])' not in content and f'@@index(["{fk}"])' not in content:
                          issues.append(f"Consider adding @@index([{fk}]) for better query performance in {model_name}")
              
              # Check for enum definitions
              enums = re.findall(r'enum\s+(\w+)\s*{', content)
              for enum_name in enums:
                  if not enum_name[0].isupper():
                      issues.append(f"Enum '{enum_name}' should be PascalCase")
              
          except Exception as e:
              issues.append(f"Error reading schema: {str(e)[:50]}")
          
          return issues
      
      
      def main():
          project_path = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
          
          print(f"\n{'='*60}")
          print(f"[SCHEMA VALIDATOR] Database Schema Validation")
          print(f"{'='*60}")
          print(f"Project: {project_path}")
          print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
          print("-"*60)
          
          # Find schema files
          schemas = find_schema_files(project_path)
          print(f"Found {len(schemas)} schema files")
          
          if not schemas:
              output = {
                  "script": "schema_validator",
                  "project": str(project_path),
                  "schemas_checked": 0,
                  "issues_found": 0,
                  "passed": True,
                  "message": "No schema files found"
              }
              print(json.dumps(output, indent=2))
              sys.exit(0)
          
          # Validate each schema
          all_issues = []
          
          for schema_type, file_path in schemas:
              print(f"\nValidating: {file_path.name} ({schema_type})")
              
              if schema_type == 'prisma':
                  issues = validate_prisma_schema(file_path)
              else:
                  issues = []  # Drizzle validation could be added
              
              if issues:
                  all_issues.append({
                      "file": str(file_path.name),
                      "type": schema_type,
                      "issues": issues
                  })
          
          # Summary
          print("\n" + "="*60)
          print("SCHEMA ISSUES")
          print("="*60)
          
          if all_issues:
              for item in all_issues:
                  print(f"\n{item['file']} ({item['type']}):")
                  for issue in item["issues"][:5]:  # Limit per file
                      print(f"  - {issue}")
                  if len(item["issues"]) > 5:
                      print(f"  ... and {len(item['issues']) - 5} more issues")
          else:
              print("No schema issues found!")
          
          total_issues = sum(len(item["issues"]) for item in all_issues)
          # Schema issues are warnings, not failures
          passed = True
          
          output = {
              "script": "schema_validator",
              "project": str(project_path),
              "schemas_checked": len(schemas),
              "issues_found": total_issues,
              "passed": passed,
              "issues": all_issues
          }
          
          print("\n" + json.dumps(output, indent=2))
          
          sys.exit(0)
      
      
      if __name__ == "__main__":
          main()
      
  • database-selection.md 1.1 KB
    # Database Selection (2025)
    
    > Choose database based on context, not default.
    
    ## Decision Tree
    
    ```
    What are your requirements?
    │
    ├── Full relational features needed
    │   ├── Self-hosted → PostgreSQL
    │   └── Serverless → Neon, Supabase
    │
    ├── Edge deployment / Ultra-low latency
    │   └── Turso (edge SQLite)
    │
    ├── AI / Vector search
    │   └── PostgreSQL + pgvector
    │
    ├── Simple / Embedded / Local
    │   └── SQLite
    │
    └── Global distribution
        └── PlanetScale, CockroachDB, Turso
    ```
    
    ## Comparison
    
    | Database | Best For | Trade-offs |
    |----------|----------|------------|
    | **PostgreSQL** | Full features, complex queries | Needs hosting |
    | **Neon** | Serverless PG, branching | PG complexity |
    | **Turso** | Edge, low latency | SQLite limitations |
    | **SQLite** | Simple, embedded, local | Single-writer |
    | **PlanetScale** | MySQL, global scale | No foreign keys |
    
    ## Questions to Ask
    
    1. What's the deployment environment?
    2. How complex are the queries?
    3. Is edge/serverless important?
    4. Vector search needed?
    5. Global distribution required?
    
  • indexing.md 892 B
    # Indexing Principles
    
    > When and how to create indexes effectively.
    
    ## When to Create Indexes
    
    ```
    Index these:
    ├── Columns in WHERE clauses
    ├── Columns in JOIN conditions
    ├── Columns in ORDER BY
    ├── Foreign key columns
    └── Unique constraints
    
    Don't over-index:
    ├── Write-heavy tables (slower inserts)
    ├── Low-cardinality columns
    ├── Columns rarely queried
    ```
    
    ## Index Type Selection
    
    | Type | Use For |
    |------|---------|
    | **B-tree** | General purpose, equality & range |
    | **Hash** | Equality only, faster |
    | **GIN** | JSONB, arrays, full-text |
    | **GiST** | Geometric, range types |
    | **HNSW/IVFFlat** | Vector similarity (pgvector) |
    
    ## Composite Index Principles
    
    ```
    Order matters for composite indexes:
    ├── Equality columns first
    ├── Range columns last
    ├── Most selective first
    └── Match query pattern
    ```
    
  • migrations.md 1.1 KB
    # Migration Principles
    
    > Safe migration strategy for zero-downtime changes.
    
    ## Safe Migration Strategy
    
    ```
    For zero-downtime changes:
    │
    ├── Adding column
    │   └── Add as nullable → backfill → add NOT NULL
    │
    ├── Removing column
    │   └── Stop using → deploy → remove column
    │
    ├── Adding index
    │   └── CREATE INDEX CONCURRENTLY (non-blocking)
    │
    └── Renaming column
        └── Add new → migrate data → deploy → drop old
    ```
    
    ## Migration Philosophy
    
    - Never make breaking changes in one step
    - Test migrations on data copy first
    - Have rollback plan
    - Run in transaction when possible
    
    ## Serverless Databases
    
    ### Neon (Serverless PostgreSQL)
    
    | Feature | Benefit |
    |---------|---------|
    | Scale to zero | Cost savings |
    | Instant branching | Dev/preview |
    | Full PostgreSQL | Compatibility |
    | Autoscaling | Traffic handling |
    
    ### Turso (Edge SQLite)
    
    | Feature | Benefit |
    |---------|---------|
    | Edge locations | Ultra-low latency |
    | SQLite compatible | Simple |
    | Generous free tier | Cost |
    | Global distribution | Performance |
    
  • optimization.md 902 B
    # Query Optimization
    
    > N+1 problem, EXPLAIN ANALYZE, optimization priorities.
    
    ## N+1 Problem
    
    ```
    What is N+1?
    ├── 1 query to get parent records
    ├── N queries to get related records
    └── Very slow!
    
    Solutions:
    ├── JOIN → Single query with all data
    ├── Eager loading → ORM handles JOIN
    ├── DataLoader → Batch and cache (GraphQL)
    └── Subquery → Fetch related in one query
    ```
    
    ## Query Analysis Mindset
    
    ```
    Before optimizing:
    ├── EXPLAIN ANALYZE the query
    ├── Look for Seq Scan (full table scan)
    ├── Check actual vs estimated rows
    └── Identify missing indexes
    ```
    
    ## Optimization Priorities
    
    1. **Add missing indexes** (most common issue)
    2. **Select only needed columns** (not SELECT *)
    3. **Use proper JOINs** (avoid subqueries when possible)
    4. **Limit early** (pagination at database level)
    5. **Cache** (when appropriate)
    
  • orm-selection.md 771 B
    # ORM Selection (2025)
    
    > Choose ORM based on deployment and DX needs.
    
    ## Decision Tree
    
    ```
    What's the context?
    │
    ├── Edge deployment / Bundle size matters
    │   └── Drizzle (smallest, SQL-like)
    │
    ├── Best DX / Schema-first
    │   └── Prisma (migrations, studio)
    │
    ├── Maximum control
    │   └── Raw SQL with query builder
    │
    └── Python ecosystem
        └── SQLAlchemy 2.0 (async support)
    ```
    
    ## Comparison
    
    | ORM | Best For | Trade-offs |
    |-----|----------|------------|
    | **Drizzle** | Edge, TypeScript | Newer, less examples |
    | **Prisma** | DX, schema management | Heavier, not edge-ready |
    | **Kysely** | Type-safe SQL builder | Manual migrations |
    | **Raw SQL** | Complex queries, control | Manual type safety |
    
  • schema-design.md 1.4 KB
    # Schema Design Principles
    
    > Normalization, primary keys, timestamps, relationships.
    
    ## Normalization Decision
    
    ```
    When to normalize (separate tables):
    ├── Data is repeated across rows
    ├── Updates would need multiple changes
    ├── Relationships are clear
    └── Query patterns benefit
    
    When to denormalize (embed/duplicate):
    ├── Read performance critical
    ├── Data rarely changes
    ├── Always fetched together
    └── Simpler queries needed
    ```
    
    ## Primary Key Selection
    
    | Type | Use When |
    |------|----------|
    | **UUID** | Distributed systems, security |
    | **ULID** | UUID + sortable by time |
    | **Auto-increment** | Simple apps, single database |
    | **Natural key** | Rarely (business meaning) |
    
    ## Timestamp Strategy
    
    ```
    For every table:
    ├── created_at → When created
    ├── updated_at → Last modified
    └── deleted_at → Soft delete (if needed)
    
    Use TIMESTAMPTZ (with timezone) not TIMESTAMP
    ```
    
    ## Relationship Types
    
    | Type | When | Implementation |
    |------|------|----------------|
    | **One-to-One** | Extension data | Separate table with FK |
    | **One-to-Many** | Parent-children | FK on child table |
    | **Many-to-Many** | Both sides have many | Junction table |
    
    ## Foreign Key ON DELETE
    
    ```
    ├── CASCADE → Delete children with parent
    ├── SET NULL → Children become orphans
    ├── RESTRICT → Prevent delete if children exist
    └── SET DEFAULT → Children get default value
    ```
    
  • SKILL.md 1.5 KB
    ---
    name: database-design
    description: Database design principles and decision-making. Schema design, indexing strategy, ORM selection, serverless databases.
    allowed-tools: Read, Write, Edit, Glob, Grep
    ---
    
    # Database Design
    
    > **Learn to THINK, not copy SQL patterns.**
    
    ## 🎯 Selective Reading Rule
    
    **Read ONLY files relevant to the request!** Check the content map, find what you need.
    
    | File | Description | When to Read |
    |------|-------------|--------------|
    | `database-selection.md` | PostgreSQL vs Neon vs Turso vs SQLite | Choosing database |
    | `orm-selection.md` | Drizzle vs Prisma vs Kysely | Choosing ORM |
    | `schema-design.md` | Normalization, PKs, relationships | Designing schema |
    | `indexing.md` | Index types, composite indexes | Performance tuning |
    | `optimization.md` | N+1, EXPLAIN ANALYZE | Query optimization |
    | `migrations.md` | Safe migrations, serverless DBs | Schema changes |
    
    ---
    
    ## ⚠️ Core Principle
    
    - ASK user for database preferences when unclear
    - Choose database/ORM based on CONTEXT
    - Don't default to PostgreSQL for everything
    
    ---
    
    ## Decision Checklist
    
    Before designing schema:
    
    - [ ] Asked user about database preference?
    - [ ] Chosen database for THIS context?
    - [ ] Considered deployment environment?
    - [ ] Planned index strategy?
    - [ ] Defined relationship types?
    
    ---
    
    ## Anti-Patterns
    
    ❌ Default to PostgreSQL for simple apps (SQLite may suffice)
    ❌ Skip indexing
    ❌ Use SELECT * in production
    ❌ Store JSON when structured data is better
    ❌ Ignore N+1 queries
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related