chore: add skills library
This commit is contained in:
parent
a7ebfc5223
commit
cf358053f0
1 changed files with 79 additions and 0 deletions
79
claude-skills/design-postgres-tables.md
Normal file
79
claude-skills/design-postgres-tables.md
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
---
|
||||||
|
name: design-postgres-tables
|
||||||
|
description: Design PostgreSQL table schemas. Use when modeling new data, adding tables, or reviewing/improving existing schema design.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Design Postgres Tables Skill
|
||||||
|
|
||||||
|
Use when: designing new tables, modeling relationships, reviewing schema, or planning migrations.
|
||||||
|
|
||||||
|
## Column Conventions
|
||||||
|
- **Primary key**: `id UUID PRIMARY KEY DEFAULT gen_random_uuid()` (prefer UUID over serial for distributed systems; use BIGSERIAL if you need sortable IDs)
|
||||||
|
- **Timestamps**: always include `created_at TIMESTAMPTZ DEFAULT NOW()` and `updated_at TIMESTAMPTZ DEFAULT NOW()`
|
||||||
|
- **Soft delete**: `deleted_at TIMESTAMPTZ DEFAULT NULL` (NULL = active)
|
||||||
|
- **Foreign keys**: name as `<table_singular>_id`, e.g. `user_id`, `project_id`
|
||||||
|
- Use `TEXT` over `VARCHAR(n)` unless you need DB-enforced length limits
|
||||||
|
- Use `BOOLEAN` not `SMALLINT` for true/false
|
||||||
|
- Use `NUMERIC(precision, scale)` for money, never `FLOAT`
|
||||||
|
|
||||||
|
## Naming Conventions
|
||||||
|
- Tables: `snake_case`, plural: `users`, `project_sessions`, `api_tokens`
|
||||||
|
- Columns: `snake_case`, singular
|
||||||
|
- Indexes: `idx_<table>_<column(s)>`: `idx_users_email`
|
||||||
|
- Foreign keys: `fk_<table>_<referenced_table>`: `fk_orders_users`
|
||||||
|
- Unique constraints: `uq_<table>_<column(s)>`: `uq_users_email`
|
||||||
|
|
||||||
|
## Standard Table Template
|
||||||
|
```sql
|
||||||
|
CREATE TABLE items (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
-- Business columns
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'active'
|
||||||
|
CHECK (status IN ('active', 'inactive', 'archived')),
|
||||||
|
|
||||||
|
-- Relationships
|
||||||
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
-- Metadata
|
||||||
|
metadata JSONB DEFAULT '{}',
|
||||||
|
|
||||||
|
-- Audit
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
deleted_at TIMESTAMPTZ
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Indexes
|
||||||
|
CREATE INDEX idx_items_user_id ON items(user_id);
|
||||||
|
CREATE INDEX idx_items_status ON items(status) WHERE deleted_at IS NULL;
|
||||||
|
CREATE INDEX idx_items_created_at ON items(created_at DESC);
|
||||||
|
|
||||||
|
-- Auto-update updated_at
|
||||||
|
CREATE TRIGGER items_updated_at
|
||||||
|
BEFORE UPDATE ON items
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Relationship Patterns
|
||||||
|
- **One-to-many**: FK on the "many" side
|
||||||
|
- **Many-to-many**: junction table with `<a>_id` + `<b>_id` + its own PK + timestamps
|
||||||
|
- **Polymorphic**: `entity_type TEXT + entity_id UUID` (add check constraint for valid types)
|
||||||
|
|
||||||
|
## Index Strategy
|
||||||
|
- Index all foreign keys
|
||||||
|
- Index columns used in WHERE clauses with high selectivity
|
||||||
|
- Partial indexes for filtered queries: `WHERE deleted_at IS NULL`
|
||||||
|
- Composite indexes: put equality columns first, range columns last
|
||||||
|
- JSONB: use GIN index for `@>` containment queries
|
||||||
|
|
||||||
|
## Design Checklist
|
||||||
|
- [ ] Every table has UUID PK + created_at + updated_at
|
||||||
|
- [ ] Foreign keys have explicit ON DELETE behavior (CASCADE vs RESTRICT vs SET NULL)
|
||||||
|
- [ ] Enum-like columns use CHECK constraints or a lookup table
|
||||||
|
- [ ] Money stored as NUMERIC not FLOAT
|
||||||
|
- [ ] Indexes on all FK columns
|
||||||
|
- [ ] No storing arrays as comma-separated strings (use ARRAY[] or junction table)
|
||||||
|
- [ ] JSONB for truly dynamic/schemaless data only — not as a crutch
|
||||||
Loading…
Reference in a new issue