[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6WZE3RKKPJS90C2EFGVNP0Z":3,"skill-same:01M6WZE3RKKPJS90C2EFGVNP0Z":89},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":62,"commitSha":63,"skillDirectory":64,"forksCount":14,"repositoryHtmlUrl":65,"repositoryHomepageUrl":66,"ownerHtmlUrl":67,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":68,"install":69,"resources":82},"01M6WZE3RKKPJS90C2EFGVNP0Z","database-modeling",null,"Data modeling — ER diagrams, normalization, denormalization trade-offs, relationship patterns, and schema evolution. Use when designing a new schema, critiquing an existing data model, choosing between normalized and denormalized designs, or modeling complex relationships like polymorphism, hierarchy, or temporal data.","projectious-work\u002Fprocesskit","projectious-work","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F263889726?v=4","01M6N97TJJ118WQ35CHRV8RD0E","projectious.work","01M6N97TPWJPF0BMKYQ4PBY5W8",0,"MIT","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Farchive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.18.1\u002Fcontext\u002Fskills\u002Fengineering\u002Fdatabase-modeling\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"database","modeling","database modeling","data modeling","when","data model","polymorphism","hierarchy","trade-offs","Existing","v1","denormalization","model","normalization","relationship","er","diagrams","schema","use","work","2026-11-10 10:12:30",false,"---\nname: database-modeling\ndescription: |\n  Data modeling — ER diagrams, normalization, denormalization trade-offs, relationship patterns, and schema evolution. Use when designing a new schema, critiquing an existing data model, choosing between normalized and denormalized designs, or modeling complex relationships like polymorphism, hierarchy, or temporal data.\nmetadata:\n  processkit:\n    apiVersion: processkit.projectious.work\u002Fv1\n    id: SKILL-database-modeling\n    version: \"1.1.0\"\n    created: 2026-04-06T00:00:00Z\n    category: engineering\n---\n\n# Database Modeling\n\n## Intro\n\nA good schema is shaped by access patterns, invariants, and expected\ngrowth — not by the first ER diagram that comes to mind. Start from\nthe requirements, normalize to 3NF, and only denormalize against a\nmeasured problem with a documented sync strategy.\n\n## Overview\n\n### Gather requirements first\n\nBefore drawing any schema, pin down five things:\n\n1. **Entities and relationships** — what are the nouns and how do\n   they relate?\n2. **Cardinality** — one-to-one, one-to-many, many-to-many?\n3. **Access patterns** — what queries run most often, and what is\n   the read\u002Fwrite ratio?\n4. **Data volume** — rows per table now and in two years?\n5. **Consistency requirements** — which invariants must the database\n   itself enforce?\n\n### Conceptual model\n\nStart with an ER diagram. Mermaid keeps it text-based and reviewable:\n\n```mermaid\nerDiagram\n    CUSTOMER ||--o{ ORDER : places\n    ORDER ||--|{ ORDER_ITEM : contains\n    PRODUCT ||--o{ ORDER_ITEM : \"appears in\"\n    CUSTOMER {\n        bigint id PK\n        text name\n        text email\n    }\n    ORDER {\n        bigint id PK\n        bigint customer_id FK\n        timestamptz created_at\n        text status\n    }\n```\n\nNotation: `||` = exactly one, `o{` = zero or more, `|{` = one or\nmore.\n\n### Normalize to 3NF\n\n- **1NF** — every column holds a single atomic value. No arrays,\n  comma-separated lists, or repeating groups.\n- **2NF** — every non-key column depends on the entire primary key\n  (relevant for composite keys).\n- **3NF** — no transitive dependencies. Non-key columns depend only\n  on the key.\n\nTest each table with the rhyme: \"every non-key column describes the\nkey, the whole key, and nothing but the key.\"\n\n### Denormalize deliberately\n\nDenormalize only when you can answer \"yes\" to all of:\n\n- Have you measured a real performance problem?\n- Is the duplicated data updated infrequently?\n- Do you have a strategy to keep copies in sync (trigger, app code,\n  scheduled job)?\n\nCommon techniques:\n\n- **Summary tables** — precomputed aggregates refreshed on a\n  schedule.\n- **Embedded lookups** — store `category_name` alongside\n  `category_id` to skip a join.\n- **Materialized views** — database-managed denormalization with\n  refresh control.\n\n### Relationship patterns at a glance\n\n| Pattern | Use when |\n|---------|----------|\n| Junction table | Many-to-many (standard) |\n| Polymorphic associations | One table references multiple parent types |\n| Single-table inheritance | Few subtypes, similar columns |\n| Class-table inheritance | Many subtypes, different columns |\n| Adjacency list | Simple tree, frequent edits |\n| Nested sets | Read-heavy tree, rare updates |\n| Materialized path | Tree with path queries \u002F breadcrumbs |\n| JSONB column | Sparse or schema-less attributes |\n\nSee `references\u002Fmodeling-patterns.md` for full implementations.\n\n### Plan for schema evolution\n\nSchemas always change. Design for it:\n\n- Add columns as nullable or with safe defaults — never lock the\n  table.\n- Prefer additive changes (new columns, new tables) over destructive\n  ones.\n- Version your API and your schema independently.\n- Use expand\u002Fcontract for non-trivial changes: add new structure,\n  backfill, then remove the old.\n\n## Gotchas\n\nAgent-specific failure modes — provider-neutral pause-and-self-check items:\n\n- **Premature denormalization for performance.** Denormalizing before you have measured a query performance problem introduces update anomalies — the same fact stored in multiple places must be kept in sync, and it will eventually drift. Model normalized first; denormalize only specific read paths after profiling shows the join is actually slow.\n- **Storing monetary values as FLOAT or DOUBLE.** Floating-point types cannot represent most decimal fractions exactly, so `0.10 + 0.20` may evaluate to `0.30000000000000004`. Always use a fixed-point type (`DECIMAL`, `NUMERIC`) or store amounts as integer cents in the application's smallest currency unit.\n- **Omitting foreign key constraints \"for flexibility.\"** Foreign keys without database-enforced referential integrity allow orphaned rows to accumulate silently — orders with no customer, line items with no product. The constraint is not optional; it is the mechanism that makes the relationship reliable. Add them unless you have a specific, documented reason not to.\n- **Comma-separated lists in a column.** Storing `\"tag1,tag2,tag3\"` in a TEXT column means queries must parse strings rather than use indexes, and adding or removing a value requires a string manipulation that cannot be done atomically. Use a junction table or, if the database supports it, an array or JSONB column with a GIN index.\n- **Entity-Attribute-Value (EAV) tables without considering JSONB.** An EAV table (`entity_id`, `attribute_name`, `value`) is a hand-rolled sparse schema that requires joining for every attribute read and prevents meaningful indexing. Modern databases (PostgreSQL, MySQL 8) offer JSONB\u002FJSON columns with indexes that achieve the same flexibility with far better query performance.\n- **Not modeling for the actual access patterns.** A schema designed only from domain entities without considering how the application queries it often leads to expensive multi-table joins on the hot path. Before finalizing the schema, list the top 5 queries by frequency and write them out — then design the schema so each can use an index.\n- **Storing hierarchies without choosing the correct hierarchy pattern.** Representing a tree with a naive `parent_id` self-reference makes querying all descendants require a recursive CTE or application-side recursion. For deep or frequently-traversed hierarchies, consider a closure table, nested sets, or ltree, depending on the read\u002Fwrite balance.\n\n## Full reference\n\n### Polymorphic associations\n\nThree approaches when one table references rows in multiple parents:\n\n**Type + ID columns (application-enforced):**\n\n```sql\nCREATE TABLE comments (\n    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n    body TEXT NOT NULL,\n    commentable_type TEXT NOT NULL,  -- 'post', 'image', 'video'\n    commentable_id BIGINT NOT NULL,\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\nCREATE INDEX idx_comments_target\n    ON comments (commentable_type, commentable_id);\n```\n\nSimple, single table — but no foreign-key enforcement.\n\n**Separate nullable foreign keys:**\n\n```sql\nCREATE TABLE comments (\n    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n    body TEXT NOT NULL,\n    post_id BIGINT REFERENCES posts(id),\n    image_id BIGINT REFERENCES images(id),\n    video_id BIGINT REFERENCES videos(id),\n    CONSTRAINT chk_single_parent CHECK (\n        (post_id IS NOT NULL)::int + (image_id IS NOT NULL)::int\n        + (video_id IS NOT NULL)::int = 1\n    )\n);\n```\n\nReal foreign keys, but grows awkward beyond 3-4 parent types.\n\n**Shared base table:** every parent has a row in\n`commentable_entities`; the comment FK points there. Adds a join but\nkeeps integrity and stays extensible.\n\n### Hierarchies\n\n| Approach | Best for | Trade-off |\n|---|---|---|\n| Adjacency list (`parent_id`) | Frequent inserts\u002Fmoves, shallow trees | Subtree queries need recursive CTEs |\n| Nested sets (`lft`\u002F`rgt`) | Read-heavy trees, deep subtree queries | Inserts\u002Fmoves renumber many rows |\n| Materialized path (`\u002F1\u002F4\u002F10\u002F`) | Breadcrumbs, prefix queries | Path updates cascade to descendants |\n\nAdjacency list with a recursive CTE handles most application-level\nhierarchies; reach for nested sets only when read patterns clearly\ndemand it.\n\n### Temporal data\n\nTrack historical state with effective-time ranges:\n\n```sql\nCREATE TABLE prices (\n    product_id BIGINT NOT NULL REFERENCES products(id),\n    price DECIMAL(10,2) NOT NULL,\n    valid_from DATE NOT NULL,\n    valid_to DATE NOT NULL DEFAULT '9999-12-31',\n    PRIMARY KEY (product_id, valid_from),\n    EXCLUDE USING gist (\n        product_id WITH =,\n        daterange(valid_from, valid_to) WITH &&\n    )\n);\n```\n\nThe `EXCLUDE` constraint prevents overlapping validity ranges for\nthe same product. Bi-temporal designs add a second range for\ntransaction time when you need to reconstruct what the system knew\nat any point.\n\n### Star schema for analytics\n\nSeparate facts (events\u002Fmeasures) from dimensions (descriptive\nattributes):\n\n```sql\nCREATE TABLE dim_product (\n    product_key SERIAL PRIMARY KEY,\n    name TEXT, category TEXT\n);\nCREATE TABLE dim_date (\n    date_key INT PRIMARY KEY,\n    full_date DATE, year INT, quarter INT, month INT\n);\nCREATE TABLE fact_sales (\n    sale_id BIGINT GENERATED ALWAYS AS IDENTITY,\n    product_key INT REFERENCES dim_product,\n    date_key INT REFERENCES dim_date,\n    quantity INT NOT NULL,\n    revenue DECIMAL(12,2) NOT NULL\n);\n```\n\nKeep fact tables narrow (keys + measures); push descriptive\nattributes into dimensions.\n\n### JSONB for sparse attributes\n\nPrefer JSONB over Entity-Attribute-Value tables when attributes vary\nper row but do not need relational integrity:\n\n```sql\nALTER TABLE products\n    ADD COLUMN attributes JSONB NOT NULL DEFAULT '{}';\nCREATE INDEX idx_products_attrs\n    ON products USING GIN (attributes);\n\nSELECT * FROM products WHERE attributes @> '{\"color\": \"red\"}';\n```\n\nGuidelines: keep JSONB to a handful of varying keys; if a key is\nqueried in every request, promote it to a real column; validate\nstructure in the application or with `CHECK` constraints.\n\n### Polyglot persistence\n\nNot everything belongs in a relational database — but default to\nPostgreSQL until you have a measured reason otherwise.\n\n| Data type | Storage |\n|-----------|---------|\n| Structured, relational, transactional | PostgreSQL, MySQL |\n| Full-text search | Elasticsearch, PostgreSQL FTS |\n| Session \u002F cache | Redis |\n| Time-series metrics | TimescaleDB, InfluxDB |\n| Graph traversals | Neo4j (or recursive CTEs for simple cases) |\n| Unstructured documents | MongoDB, or JSONB in PostgreSQL |\n| Event streams | Kafka, or append-only tables |\n\n### Anti-patterns\n\n- **EAV without strong justification** — use JSONB instead.\n- **Storing money as floats** — use `DECIMAL(19,4)` or integer cents.\n- **Missing foreign keys \"for flexibility\"** — the database should\n  enforce integrity.\n- **Comma-separated lists in a column** — violates 1NF; use a join\n  table or array type.\n- **Soft deletes everywhere** — adds a `WHERE deleted_at IS NULL` to\n  every query; consider an archive table instead.\n","# Database Modeling\n\n## Intro\n\nA good schema is shaped by access patterns, invariants, and expected\ngrowth — not by the first ER diagram that comes to mind. Start from\nthe requirements, normalize to 3NF, and only denormalize against a\nmeasured problem with a documented sync strategy.\n\n## Overview\n\n### Gather requirements first\n\nBefore drawing any schema, pin down five things:\n\n1. **Entities and relationships** — what are the nouns and how do\n   they relate?\n2. **Cardinality** — one-to-one, one-to-many, many-to-many?\n3. **Access patterns** — what queries run most often, and what is\n   the read\u002Fwrite ratio?\n4. **Data volume** — rows per table now and in two years?\n5. **Consistency requirements** — which invariants must the database\n   itself enforce?\n\n### Conceptual model\n\nStart with an ER diagram. Mermaid keeps it text-based and reviewable:\n\n```mermaid\nerDiagram\n    CUSTOMER ||--o{ ORDER : places\n    ORDER ||--|{ ORDER_ITEM : contains\n    PRODUCT ||--o{ ORDER_ITEM : \"appears in\"\n    CUSTOMER {\n        bigint id PK\n        text name\n        text email\n    }\n    ORDER {\n        bigint id PK\n        bigint customer_id FK\n        timestamptz created_at\n        text status\n    }\n```\n\nNotation: `||` = exactly one, `o{` = zero or more, `|{` = one or\nmore.\n\n### Normalize to 3NF\n\n- **1NF** — every column holds a single atomic value. No arrays,\n  comma-separated lists, or repeating groups.\n- **2NF** — every non-key column depends on the entire primary key\n  (relevant for composite keys).\n- **3NF** — no transitive dependencies. Non-key columns depend only\n  on the key.\n\nTest each table with the rhyme: \"every non-key column describes the\nkey, the whole key, and nothing but the key.\"\n\n### Denormalize deliberately\n\nDenormalize only when you can answer \"yes\" to all of:\n\n- Have you measured a real performance problem?\n- Is the duplicated data updated infrequently?\n- Do you have a strategy to keep copies in sync (trigger, app code,\n  scheduled job)?\n\nCommon techniques:\n\n- **Summary tables** — precomputed aggregates refreshed on a\n  schedule.\n- **Embedded lookups** — store `category_name` alongside\n  `category_id` to skip a join.\n- **Materialized views** — database-managed denormalization with\n  refresh control.\n\n### Relationship patterns at a glance\n\n| Pattern | Use when |\n|---------|----------|\n| Junction table | Many-to-many (standard) |\n| Polymorphic associations | One table references multiple parent types |\n| Single-table inheritance | Few subtypes, similar columns |\n| Class-table inheritance | Many subtypes, different columns |\n| Adjacency list | Simple tree, frequent edits |\n| Nested sets | Read-heavy tree, rare updates |\n| Materialized path | Tree with path queries \u002F breadcrumbs |\n| JSONB column | Sparse or schema-less attributes |\n\nSee `references\u002Fmodeling-patterns.md` for full implementations.\n\n### Plan for schema evolution\n\nSchemas always change. Design for it:\n\n- Add columns as nullable or with safe defaults — never lock the\n  table.\n- Prefer additive changes (new columns, new tables) over destructive\n  ones.\n- Version your API and your schema independently.\n- Use expand\u002Fcontract for non-trivial changes: add new structure,\n  backfill, then remove the old.\n\n## Gotchas\n\nAgent-specific failure modes — provider-neutral pause-and-self-check items:\n\n- **Premature denormalization for performance.** Denormalizing before you have measured a query performance problem introduces update anomalies — the same fact stored in multiple places must be kept in sync, and it will eventually drift. Model normalized first; denormalize only specific read paths after profiling shows the join is actually slow.\n- **Storing monetary values as FLOAT or DOUBLE.** Floating-point types cannot represent most decimal fractions exactly, so `0.10 + 0.20` may evaluate to `0.30000000000000004`. Always use a fixed-point type (`DECIMAL`, `NUMERIC`) or store amounts as integer cents in the application's smallest currency unit.\n- **Omitting foreign key constraints \"for flexibility.\"** Foreign keys without database-enforced referential integrity allow orphaned rows to accumulate silently — orders with no customer, line items with no product. The constraint is not optional; it is the mechanism that makes the relationship reliable. Add them unless you have a specific, documented reason not to.\n- **Comma-separated lists in a column.** Storing `\"tag1,tag2,tag3\"` in a TEXT column means queries must parse strings rather than use indexes, and adding or removing a value requires a string manipulation that cannot be done atomically. Use a junction table or, if the database supports it, an array or JSONB column with a GIN index.\n- **Entity-Attribute-Value (EAV) tables without considering JSONB.** An EAV table (`entity_id`, `attribute_name`, `value`) is a hand-rolled sparse schema that requires joining for every attribute read and prevents meaningful indexing. Modern databases (PostgreSQL, MySQL 8) offer JSONB\u002FJSON columns with indexes that achieve the same flexibility with far better query performance.\n- **Not modeling for the actual access patterns.** A schema designed only from domain entities without considering how the application queries it often leads to expensive multi-table joins on the hot path. Before finalizing the schema, list the top 5 queries by frequency and write them out — then design the schema so each can use an index.\n- **Storing hierarchies without choosing the correct hierarchy pattern.** Representing a tree with a naive `parent_id` self-reference makes querying all descendants require a recursive CTE or application-side recursion. For deep or frequently-traversed hierarchies, consider a closure table, nested sets, or ltree, depending on the read\u002Fwrite balance.\n\n## Full reference\n\n### Polymorphic associations\n\nThree approaches when one table references rows in multiple parents:\n\n**Type + ID columns (application-enforced):**\n\n```sql\nCREATE TABLE comments (\n    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n    body TEXT NOT NULL,\n    commentable_type TEXT NOT NULL,  -- 'post', 'image', 'video'\n    commentable_id BIGINT NOT NULL,\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\nCREATE INDEX idx_comments_target\n    ON comments (commentable_type, commentable_id);\n```\n\nSimple, single table — but no foreign-key enforcement.\n\n**Separate nullable foreign keys:**\n\n```sql\nCREATE TABLE comments (\n    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n    body TEXT NOT NULL,\n    post_id BIGINT REFERENCES posts(id),\n    image_id BIGINT REFERENCES images(id),\n    video_id BIGINT REFERENCES videos(id),\n    CONSTRAINT chk_single_parent CHECK (\n        (post_id IS NOT NULL)::int + (image_id IS NOT NULL)::int\n        + (video_id IS NOT NULL)::int = 1\n    )\n);\n```\n\nReal foreign keys, but grows awkward beyond 3-4 parent types.\n\n**Shared base table:** every parent has a row in\n`commentable_entities`; the comment FK points there. Adds a join but\nkeeps integrity and stays extensible.\n\n### Hierarchies\n\n| Approach | Best for | Trade-off |\n|---|---|---|\n| Adjacency list (`parent_id`) | Frequent inserts\u002Fmoves, shallow trees | Subtree queries need recursive CTEs |\n| Nested sets (`lft`\u002F`rgt`) | Read-heavy trees, deep subtree queries | Inserts\u002Fmoves renumber many rows |\n| Materialized path (`\u002F1\u002F4\u002F10\u002F`) | Breadcrumbs, prefix queries | Path updates cascade to descendants |\n\nAdjacency list with a recursive CTE handles most application-level\nhierarchies; reach for nested sets only when read patterns clearly\ndemand it.\n\n### Temporal data\n\nTrack historical state with effective-time ranges:\n\n```sql\nCREATE TABLE prices (\n    product_id BIGINT NOT NULL REFERENCES products(id),\n    price DECIMAL(10,2) NOT NULL,\n    valid_from DATE NOT NULL,\n    valid_to DATE NOT NULL DEFAULT '9999-12-31',\n    PRIMARY KEY (product_id, valid_from),\n    EXCLUDE USING gist (\n        product_id WITH =,\n        daterange(valid_from, valid_to) WITH &&\n    )\n);\n```\n\nThe `EXCLUDE` constraint prevents overlapping validity ranges for\nthe same product. Bi-temporal designs add a second range for\ntransaction time when you need to reconstruct what the system knew\nat any point.\n\n### Star schema for analytics\n\nSeparate facts (events\u002Fmeasures) from dimensions (descriptive\nattributes):\n\n```sql\nCREATE TABLE dim_product (\n    product_key SERIAL PRIMARY KEY,\n    name TEXT, category TEXT\n);\nCREATE TABLE dim_date (\n    date_key INT PRIMARY KEY,\n    full_date DATE, year INT, quarter INT, month INT\n);\nCREATE TABLE fact_sales (\n    sale_id BIGINT GENERATED ALWAYS AS IDENTITY,\n    product_key INT REFERENCES dim_product,\n    date_key INT REFERENCES dim_date,\n    quantity INT NOT NULL,\n    revenue DECIMAL(12,2) NOT NULL\n);\n```\n\nKeep fact tables narrow (keys + measures); push descriptive\nattributes into dimensions.\n\n### JSONB for sparse attributes\n\nPrefer JSONB over Entity-Attribute-Value tables when attributes vary\nper row but do not need relational integrity:\n\n```sql\nALTER TABLE products\n    ADD COLUMN attributes JSONB NOT NULL DEFAULT '{}';\nCREATE INDEX idx_products_attrs\n    ON products USING GIN (attributes);\n\nSELECT * FROM products WHERE attributes @> '{\"color\": \"red\"}';\n```\n\nGuidelines: keep JSONB to a handful of varying keys; if a key is\nqueried in every request, promote it to a real column; validate\nstructure in the application or with `CHECK` constraints.\n\n### Polyglot persistence\n\nNot everything belongs in a relational database — but default to\nPostgreSQL until you have a measured reason otherwise.\n\n| Data type | Storage |\n|-----------|---------|\n| Structured, relational, transactional | PostgreSQL, MySQL |\n| Full-text search | Elasticsearch, PostgreSQL FTS |\n| Session \u002F cache | Redis |\n| Time-series metrics | TimescaleDB, InfluxDB |\n| Graph traversals | Neo4j (or recursive CTEs for simple cases) |\n| Unstructured documents | MongoDB, or JSONB in PostgreSQL |\n| Event streams | Kafka, or append-only tables |\n\n### Anti-patterns\n\n- **EAV without strong justification** — use JSONB instead.\n- **Storing money as floats** — use `DECIMAL(19,4)` or integer cents.\n- **Missing foreign keys \"for flexibility\"** — the database should\n  enforce integrity.\n- **Comma-separated lists in a column** — violates 1NF; use a join\n  table or array type.\n- **Soft deletes everywhere** — adds a `WHERE deleted_at IS NULL` to\n  every query; consider an archive table instead.\n",{"name":5,"metadata":54,"description":61},{"processkit":55},{"id":56,"created":57,"version":58,"category":59,"apiVersion":60},"SKILL-database-modeling",1775433600000,"1.1.0","engineering","processkit.projectious.work\u002Fv1","Data modeling — ER diagrams, normalization, denormalization trade-offs, relationship patterns, and schema evolution. Use when designing a new schema, critiquing an existing data model, choosing between normalized and denormalized designs, or modeling complex relationships like polymorphism, hierarchy, or temporal data.\n","main","4876a92620ee792aac2ac9a1a806322d8a572367","archive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.18.1\u002Fcontext\u002Fskills\u002Fengineering\u002Fdatabase-modeling","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit","https:\u002F\u002Fprojectious-work.github.io\u002Fprocesskit\u002F","https:\u002F\u002Fgithub.com\u002Fprojectious-work","2026-11-11 23:24:18",{"source":8,"skillName":5,"commands":70,"prompt":80,"zipAvailable":81},[71,74,77],{"tool":72,"command":73},"npx","npx skills add projectious-work\u002Fprocesskit --skill database-modeling",{"tool":75,"command":76},"bunx","bunx skills add projectious-work\u002Fprocesskit --skill database-modeling",{"tool":78,"command":79},"pnpm","pnpm dlx skills add projectious-work\u002Fprocesskit --skill database-modeling","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Farchive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.18.1\u002Fcontext\u002Fskills\u002Fengineering\u002Fdatabase-modeling\u002FSKILL.md",true,[83],{"path":84,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":87,"sourceHtmlUrl":88},"references\u002Fmodeling-patterns.md","REFERENCE","参考文档",6897,"https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Farchive\u002Fprocesskit-install-20261101\u002Fcontext\u002Ftemplates\u002Fprocesskit\u002Fv0.18.1\u002Fcontext\u002Fskills\u002Fengineering\u002Fdatabase-modeling\u002Freferences\u002Fmodeling-patterns.md",[90,114,133,154,171,189],{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":99,"publishedAt":49},"01M6X5MTC89B4ZGXW3JVSQCPF8","skill-management","Manage Skill package manifests as v1 ontology entities.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fskill-management\u002FSKILL.md",[96],{"categoryNo":97,"categoryName":98,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[100,101,102,103,104,105,48,106,107,108,92,109,110,111,39,112,113],"management","skill management","create","update","package","alpha","list","manage","ontology","get","as","manifests","skill package","transition",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":121,"publishedAt":49},"01M6X5MCV74NHW5MEDNHZRF2C8","schema-management","Manage generated processkit schema contracts through deterministic MCP rebuild and inspection workflows.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fschema-management\u002FSKILL.md",[120],{"categoryNo":97,"categoryName":98,"taxonomyType":21,"taxonomyTypeDesc":22},[100,46,122,123,124,125,105,48,126,127,107,128,129,130,109,131,132],"schema management","MCP","workflows","validation","generated","rebuild","contracts","wed","deterministic","contract","mode",{"skillNo":134,"name":135,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":139,"publishedAt":49},"01M6X5M5G6YJ96AMZGSCZJ1D13","proposition-management","Record claims, risks, beliefs, world facts, WSJF estimates, and assumptions through the Proposition interface.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fproposition-management\u002FSKILL.md",[],[100,140,141,102,103,142,105,48,143,144,145,146,109,147,148,149,150,151,152,153],"proposition","proposition management","index","log","world","record","query","creation","event","interface","updates","facts","claims","WSJF",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":160,"publishedAt":49},"01M6X5KMQ83QN9M6MPWZM7344F","ontology-management","Manage generated v1 ontology entities that do not require a dedicated domain server.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fontology-management\u002FSKILL.md",[],[100,108,161,102,105,162,163,126,164,143,107,165,166,109,167,168,148,169,39,170],"ontology management","lifecycle","archive","roadmap","do","domain","iteration","keep","measurement","generic",{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":49},"01M6X5KCY2DN3SM21RERSFNEBT","okf-compatibility","Import, export, and validate conformant Open Knowledge Format bundles.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fokf-compatibility\u002FSKILL.md",[],[178,179,180,181,105,182,183,184,48,185,186,187,188],"okf","compatibility","okf compatibility","validate","open","knowledge","format","export","bundles","bundle","import",{"skillNo":190,"name":191,"nameZh":6,"description":192,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":193,"categories":194,"keywords":195,"publishedAt":49},"01M6X5JA8S5PNGJVFW4EQY8T83","capability-management","Manage versioned Capability entities and their governed lifecycle.","https:\u002F\u002Fgithub.com\u002Fprojectious-work\u002Fprocesskit\u002Fblob\u002Fmain\u002Fsrc\u002Fcontext\u002Fskills\u002Fprocesskit\u002Fcapability-management\u002FSKILL.md",[],[100,196,197,102,103,142,105,162,48,106,143,198,107,145,109,168,148,149,199,113],"capability","capability management","queries","changes"]