[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-ac2ad625-2378-490a-a522-98faa43fd667":3,"$fKkNpOAjwOLlbKN8EtYQECOrm-CCnbkUlqlG-FH2kgwA":42},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":33},"ac2ad625-2378-490a-a522-98faa43fd667","database-schema-designer","当用户请求创建ERD图、规范化数据库模式、设计表关系或规划模式迁移时使用。","cat_coding_backend","mod_coding","alirezarezvani,coding","---\nname: \"database-schema-designer\"\ndescription: \"Use when the user asks to create ERD diagrams, normalize database schemas, design table relationships, or plan schema migrations.\"\n---\n\n# Database Schema Designer\n\n**Tier:** POWERFUL  \n**Category:** Engineering  \n**Domain:** Data Architecture \u002F Backend  \n\n---\n\n## Overview\n\nDesign relational database schemas from requirements and generate migrations, TypeScript\u002FPython types, seed data, RLS policies, and indexes. Handles multi-tenancy, soft deletes, audit trails, versioning, and polymorphic associations.\n\n## Core Capabilities\n\n- **Schema design** — normalize requirements into tables, relationships, constraints\n- **Migration generation** — Drizzle, Prisma, TypeORM, Alembic\n- **Type generation** — TypeScript interfaces, Python dataclasses\u002FPydantic models\n- **RLS policies** — Row-Level Security for multi-tenant apps\n- **Index strategy** — composite indexes, partial indexes, covering indexes\n- **Seed data** — realistic test data generation\n- **ERD generation** — Mermaid diagram from schema\n\n---\n\n## When to Use\n\n- Designing a new feature that needs database tables\n- Reviewing a schema for performance or normalization issues\n- Adding multi-tenancy to an existing schema\n- Generating TypeScript types from a Prisma schema\n- Planning a schema migration for a breaking change\n\n---\n\n## Schema Design Process\n\n### Step 1: Requirements → Entities\n\nGiven requirements:\n> \"Users can create projects. Each project has tasks. Tasks can have labels. Tasks can be assigned to users. We need a full audit trail.\"\n\nExtract entities:\n```\nUser, Project, Task, Label, TaskLabel (junction), TaskAssignment, AuditLog\n```\n\n### Step 2: Identify Relationships\n\n```\nUser 1──* Project         (owner)\nProject 1──* Task\nTask *──* Label            (via TaskLabel)\nTask *──* User            (via TaskAssignment)\nUser 1──* AuditLog\n```\n\n### Step 3: Add Cross-cutting Concerns\n\n- Multi-tenancy: add `organization_id` to all tenant-scoped tables\n- Soft deletes: add `deleted_at TIMESTAMPTZ` instead of hard deletes\n- Audit trail: add `created_by`, `updated_by`, `created_at`, `updated_at`\n- Versioning: add `version INTEGER` for optimistic locking\n\n---\n\n## Full Schema Example (Task Management SaaS)\n→ See references\u002Ffull-schema-examples.md for details\n\n## Row-Level Security (RLS) Policies\n\n```sql\n-- Enable RLS\nALTER TABLE tasks ENABLE ROW LEVEL SECURITY;\nALTER TABLE projects ENABLE ROW LEVEL SECURITY;\n\n-- Create app role\nCREATE ROLE app_user;\n\n-- Users can only see tasks in their organization's projects\nCREATE POLICY tasks_org_isolation ON tasks\n  FOR ALL TO app_user\n  USING (\n    project_id IN (\n      SELECT p.id FROM projects p\n      JOIN organization_members om ON om.organization_id = p.organization_id\n      WHERE om.user_id = current_setting('app.current_user_id')::text\n    )\n  );\n\n-- Soft delete: never show deleted records\nCREATE POLICY tasks_no_deleted ON tasks\n  FOR SELECT TO app_user\n  USING (deleted_at IS NULL);\n\n-- Only task creator or admin can delete\nCREATE POLICY tasks_delete_policy ON tasks\n  FOR DELETE TO app_user\n  USING (\n    created_by_id = current_setting('app.current_user_id')::text\n    OR EXISTS (\n      SELECT 1 FROM organization_members om\n      JOIN projects p ON p.organization_id = om.organization_id\n      WHERE p.id = tasks.project_id\n        AND om.user_id = current_setting('app.current_user_id')::text\n        AND om.role IN ('owner', 'admin')\n    )\n  );\n\n-- Set user context (call at start of each request)\nSELECT set_config('app.current_user_id', $1, true);\n```\n\n---\n\n## Seed Data Generation\n\n```typescript\n\u002F\u002F db\u002Fseed.ts\nimport { faker } from '@faker-js\u002Ffaker'\nimport { db } from '.\u002Fclient'\nimport { organizations, users, projects, tasks } from '.\u002Fschema'\nimport { createId } from '@paralleldrive\u002Fcuid2'\nimport { hashPassword } from '..\u002Fsrc\u002Flib\u002Fauth'\n\nasync function seed() {\n  console.log('Seeding database...')\n\n  \u002F\u002F Create org\n  const [org] = await db.insert(organizations).values({\n    id: createId(),\n    name: \"acme-corp\",\n    slug: 'acme',\n    plan: 'growth',\n  }).returning()\n\n  \u002F\u002F Create users\n  const adminUser = await db.insert(users).values({\n    id: createId(),\n    email: 'admin@acme.com',\n    name: \"alice-admin\",\n    passwordHash: await hashPassword('password123'),\n  }).returning().then(r => r[0])\n\n  \u002F\u002F Create projects\n  const projectsData = Array.from({ length: 3 }, () => ({\n    id: createId(),\n    organizationId: org.id,\n    ownerId: adminUser.id,\n    name: \"fakercompanycatchphrase\"\n    description: faker.lorem.paragraph(),\n    status: 'active' as const,\n  }))\n\n  const createdProjects = await db.insert(projects).values(projectsData).returning()\n\n  \u002F\u002F Create tasks for each project\n  for (const project of createdProjects) {\n    const tasksData = Array.from({ length: faker.number.int({ min: 5, max: 20 }) }, (_, i) => ({\n      id: createId(),\n      projectId: project.id,\n      title: faker.hacker.phrase(),\n      description: faker.lorem.sentences(2),\n      status: faker.helpers.arrayElement(['todo', 'in_progress', 'done'] as const),\n      priority: faker.helpers.arrayElement(['low', 'medium', 'high'] as const),\n      position: i * 1000,\n      createdById: adminUser.id,\n      updatedById: adminUser.id,\n    }))\n\n    await db.insert(tasks).values(tasksData)\n  }\n\n  console.log(`✅ Seeded: 1 org, ${projectsData.length} projects, tasks`)\n}\n\nseed().catch(console.error).finally(() => process.exit(0))\n```\n\n---\n\n## ERD Generation (Mermaid)\n\n```\nerDiagram\n    Organization ||--o{ OrganizationMember : has\n    Organization ||--o{ Project : owns\n    User ||--o{ OrganizationMember : joins\n    User ||--o{ Task : \"created by\"\n    Project ||--o{ Task : contains\n    Task ||--o{ TaskAssignment : has\n    Task ||--o{ TaskLabel : has\n    Task ||--o{ Comment : has\n    Task ||--o{ Attachment : has\n    Label ||--o{ TaskLabel : \"applied to\"\n    User ||--o{ TaskAssignment : assigned\n\n    Organization {\n        string id PK\n        string name\n        string slug\n        string plan\n    }\n\n    Task {\n        string id PK\n        string project_id FK\n        string title\n        string status\n        string priority\n        timestamp due_date\n        timestamp deleted_at\n        int version\n    }\n```\n\nGenerate from Prisma:\n```bash\nnpx prisma-erd-generator\n# or: npx @dbml\u002Fcli prisma2dbml -i schema.prisma | npx dbml-to-mermaid\n```\n\n---\n\n## Common Pitfalls\n\n- **Soft delete without index** — `WHERE deleted_at IS NULL` without index = full scan\n- **Missing composite indexes** — `WHERE org_id = ? AND status = ?` needs a composite index\n- **Mutable surrogate keys** — never use email or slug as PK; use UUID\u002FCUID\n- **Non-nullable without default** — adding a NOT NULL column to existing table requires default or migration plan\n- **No optimistic locking** — concurrent updates overwrite each other; add `version` column\n- **RLS not tested** — always test RLS with a non-superuser role\n\n---\n\n## Best Practices\n\n1. **Timestamps everywhere** — `created_at`, `updated_at` on every table\n2. **Soft deletes for auditable data** — `deleted_at` instead of DELETE\n3. **Audit log for compliance** — log before\u002Fafter JSON for regulated domains\n4. **UUIDs or CUIDs as PKs** — avoid sequential integer leakage\n5. **Index foreign keys** — every FK column should have an index\n6. **Partial indexes** — use `WHERE deleted_at IS NULL` for active-only queries\n7. **RLS over application-level filtering** — database enforces tenancy, not just app code\n","","imported","https:\u002F\u002Fgithub.com\u002Falirezarezvani\u002Fclaude-skills","user_system_seed","SkillOPIC",true,206,204,"2026-05-16 13:53:34",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":25,"skillCount":32,"createdAt":26},"后端开发","backend","mdi-server","API、数据库、服务端架构",296,[34],{"id":35,"skillId":4,"version":36,"fileName":37,"fileSize":38,"filePath":39,"fileHash":40,"manifest":41,"createdAt":19},"6b357235-2321-45c7-9b07-08004aa458ef","1.0.0","database-schema-designer.zip",6222,"uploads\u002Fskills\u002Fac2ad625-2378-490a-a522-98faa43fd667\u002Fdatabase-schema-designer.zip","270ad053e242e49b8ff78fc17eae13b67078021aed120a82925210b263578bd7","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":7502},{\"path\":\"references\u002Ffull-schema-examples.md\",\"isDirectory\":false,\"size\":10443}]",{"code":43,"message":44,"data":45},200,"success",{"items":46,"stats":47,"page":50},[],{"averageRating":48,"totalRatings":48,"ratingCounts":49},0,[48,48,48,48,48],{"limit":51,"offset":48,"hasMore":52,"nextOffset":51,"ratedOnly":16},15,false]