Database design
Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/database-design
A curated pack of custom Claude Code skills for developers — installable as a Claude Code plugin marketplace.
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill database-designAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
When to activate: schema design, normalization, ERD, soft delete, temporal tables, audit log, database modeling
SKILL.md
4.3 KB, 985 tokens by cl100k_base, as published. Nobody here has run it
Database Design Patterns
Normalization vs Denormalization
-- 3NF: separate concerns, eliminate redundancy
CREATE TABLE users (id BIGSERIAL PRIMARY KEY, name TEXT, email TEXT UNIQUE);
CREATE TABLE products (id BIGSERIAL PRIMARY KEY, name TEXT, price DECIMAL(10,2));
CREATE TABLE orders (id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users, created_at TIMESTAMPTZ);
CREATE TABLE order_items (order_id BIGINT REFERENCES orders, product_id BIGINT REFERENCES products,
qty INT, unit_price DECIMAL(10,2));
-- Denormalize for read performance (snapshot price at order time — already above)
-- Materialized: store user_name on orders for fast listing without JOIN
ALTER TABLE orders ADD COLUMN user_name TEXT; -- updated via trigger or app
Soft Delete
-- Pattern 1: deleted_at timestamp
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMPTZ;
CREATE INDEX idx_users_active ON users (id) WHERE deleted_at IS NULL;
-- All queries must include WHERE deleted_at IS NULL
-- Use a view to enforce
CREATE VIEW active_users AS SELECT * FROM users WHERE deleted_at IS NULL;
-- Soft delete
UPDATE users SET deleted_at = NOW() WHERE id = $1;
-- Pattern 2: is_deleted boolean (simpler, less info)
ALTER TABLE users ADD COLUMN is_deleted BOOLEAN NOT NULL DEFAULT FALSE;
Temporal Tables (Audit History)
-- System-period temporal table (valid time via trigger)
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
price DECIMAL(10,2),
valid_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
valid_to TIMESTAMPTZ NOT NULL DEFAULT 'infinity'
);
CREATE TABLE products_history (LIKE products INCLUDING ALL);
-- Trigger to move old version to history on update
CREATE OR REPLACE FUNCTION products_history_trigger() RETURNS trigger AS $$
BEGIN
INSERT INTO products_history SELECT OLD.*;
NEW.valid_from := NOW();
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER products_versioning
BEFORE UPDATE ON products
FOR EACH ROW EXECUTE FUNCTION products_history_trigger();
-- Query at a point in time
SELECT * FROM products_history
WHERE id = 42 AND valid_from <= '2024-06-01' AND valid_to > '2024-06-01';
Audit Log Pattern
CREATE TABLE audit_log (
id BIGSERIAL PRIMARY KEY,
table_name TEXT NOT NULL,
record_id BIGINT NOT NULL,
action TEXT NOT NULL CHECK (action IN ('INSERT','UPDATE','DELETE')),
old_data JSONB,
new_data JSONB,
changed_by BIGINT, -- user id
changed_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE OR REPLACE FUNCTION audit_trigger() RETURNS trigger AS $$
BEGIN
INSERT INTO audit_log (table_name, record_id, action, old_data, new_data)
VALUES (TG_TABLE_NAME,
COALESCE(NEW.id, OLD.id),
TG_OP,
CASE WHEN TG_OP != 'INSERT' THEN to_jsonb(OLD) END,
CASE WHEN TG_OP != 'DELETE' THEN to_jsonb(NEW) END);
RETURN NEW;
END $$ LANGUAGE plpgsql;
Common Schema Patterns
-- UUID primary keys (globally unique, safe for distributed systems)
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
...
);
-- Polymorphic association (with type discriminator)
CREATE TABLE attachments (
id BIGSERIAL PRIMARY KEY,
resource_type TEXT NOT NULL, -- 'Post', 'Comment', 'User'
resource_id BIGINT NOT NULL,
url TEXT NOT NULL,
UNIQUE (resource_type, resource_id, url)
);
CREATE INDEX ON attachments (resource_type, resource_id);
-- ULID-style sortable IDs (time-ordered UUIDs)
-- Use pg_ulid extension or encode timestamp into UUID v7
Design Checklist
- Every table has
id,created_at,updated_at - Foreign keys have indexes
- Soft delete uses partial index on
deleted_at IS NULL - Enums as
CHECKconstraints or lookup tables, not magic strings - Monetary values as
DECIMAL(19,4), neverFLOAT - Time stored as
TIMESTAMPTZ(UTC), notTIMESTAMP - Audit log on all business-critical tables
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.