一键导入
data-model
Use when designing database schema, entity relationships, or index strategy before writing migrations — for PostgreSQL with Go or Python
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when designing database schema, entity relationships, or index strategy before writing migrations — for PostgreSQL with Go or Python
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when the user wants to free disk space, investigate disk usage, clean caches, remove unused artifacts, or when disk capacity is high. Also use when asked to "clean up", "free space", "disk full", or "what's using disk space". Always uses AskUserQuestion for every deletion decision.
Use at the start of every conversation and for every user message — orchestrates the full engineering skills suite by understanding intent, clarifying requirements interactively, and invoking the right skills
Use when refactoring Go code, cleaning up legacy codebases, optimizing performance, or enforcing clean architecture boundaries in a Go/Fiber backend
Use when refactoring Python code, cleaning up legacy codebases, optimizing performance, enforcing type safety, or improving clean architecture in a FastAPI backend
Use when refactoring React components, cleaning up legacy frontends, optimizing performance, improving component architecture, or reducing bundle size
Use when reviewing changed code before committing or after completing a feature — checks performance, architecture, type safety, and code quality against project standards
| name | data-model |
| description | Use when designing database schema, entity relationships, or index strategy before writing migrations — for PostgreSQL with Go or Python |
Design your database schema before writing migrations. Think about entities, relationships, access patterns, and indexes upfront.
Core principle: Your schema is your most permanent decision. Code is easy to refactor, schema migrations on production data are not.
From user stories, extract the nouns — these are your entities:
"User creates an organization and invites members"
→ Entities: User, Organization, Membership, Invitation
"User writes posts and receives comments"
→ Entities: User, Post, Comment
For each entity, define columns with types:
## Users
| Column | Type | Constraints | Notes |
|--------|------|------------|-------|
| id | UUID | PK, default gen_random_uuid() | |
| email | TEXT | NOT NULL, UNIQUE | |
| name | TEXT | NOT NULL | |
| role | user_role ENUM | NOT NULL, default 'member' | admin, member, viewer |
| avatar_url | TEXT | nullable | |
| metadata | JSONB | NOT NULL, default '{}' | extensible fields |
| created_at | TIMESTAMPTZ | NOT NULL, default NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL, default NOW() | |
Type conventions (PostgreSQL):
| Use Case | Type | Not |
|---|---|---|
| Identifiers | UUID | SERIAL, BIGINT (unless performance-critical) |
| Text | TEXT | VARCHAR(n) (Postgres treats them identically) |
| Timestamps | TIMESTAMPTZ | TIMESTAMP (always include timezone) |
| Money | BIGINT (cents) or NUMERIC | FLOAT, DOUBLE |
| Booleans | BOOLEAN | INT |
| Flexible data | JSONB | JSON (JSONB is indexed, JSON is not) |
| Enums | CREATE TYPE ... AS ENUM | TEXT with CHECK |
| Arrays | TEXT[], UUID[] | Separate table (unless truly array data) |
## Relationships
### One-to-Many
- Organization (1) → Users (N) — via org_id FK on users
- User (1) → Posts (N) — via author_id FK on posts
### Many-to-Many
- User ↔ Organization — via memberships junction table
- memberships(user_id, org_id, role, joined_at)
- UNIQUE(user_id, org_id)
### One-to-One
- User (1) → Profile (1) — via user_id UNIQUE FK on profiles
Junction table rules:
created_at (when was this relationship created?)deleted_at)Rule: Every WHERE, JOIN ON, and ORDER BY column needs an index if the table will grow beyond 10k rows.
## Indexes
### users
- email (UNIQUE) — login lookup
- org_id — list users by org
- created_at — sort/filter by date
### posts
- author_id — user's posts
- (org_id, created_at DESC) — feed query
- (org_id, status) WHERE status = 'published' — partial index
### memberships
- (user_id, org_id) UNIQUE — prevent duplicates
- org_id — list org members
Index types:
| Type | When |
|---|---|
| B-tree (default) | Equality, range, sorting |
| GIN | JSONB fields, array fields, full-text search |
Partial (WHERE condition) | Queries that filter on a specific value |
Composite (a, b) | Queries that filter on a + b together |
Before finalizing, list the queries your app will run and verify each one is covered:
## Access Patterns
| Query | Frequency | Indexed? |
|-------|-----------|----------|
| Get user by email | Very high (every auth) | ✅ users.email UNIQUE |
| List org members | High | ✅ memberships.org_id |
| Get user's orgs | High | ✅ memberships.user_id |
| Feed: org posts by date | High | ✅ posts(org_id, created_at DESC) |
| Search posts by title | Medium | ❌ Need GIN index on title |
| Count users by plan | Low (admin) | ❌ OK — sequential scan fine |
## Deletion Strategy
| Entity | Strategy | Reason |
|--------|----------|--------|
| User | Soft (deleted_at) | Legal retention, audit trail |
| Post | Soft (deleted_at) | User might want to recover |
| Session | Hard | No retention need, high volume |
| Invitation | Hard after expiry | Short-lived, no audit need |
Soft delete pattern:
-- Add to table
deleted_at TIMESTAMPTZ DEFAULT NULL
-- Partial index (only query active records)
CREATE INDEX idx_users_active ON users (email) WHERE deleted_at IS NULL;
-- All queries must include WHERE deleted_at IS NULL
id UUID PRIMARY KEY DEFAULT gen_random_uuid()created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()ON DELETE behavior (CASCADE, SET NULL, or RESTRICT)VARCHAR(n) — use TEXTTIMESTAMP — use TIMESTAMPTZproduct-spec for user stories, system-design for architecturedb-migrate or py-migrate to implement the schemaadr for significant schema decisions