skilldrop-cli 0.16.12 → 0.16.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/skilldrop.js +36 -11
- package/catalogue.json +8 -6
- package/contracts/catalogue.schema.json +15 -1
- package/model-routing.json +1 -17
- package/package.json +1 -1
- package/packs/ai-engineering/skills/ai-readiness-assessment/SKILL.md +1 -1
- package/packs/ai-engineering/skills/ai-readiness-assessment/manifest.json +2 -3
- package/packs/ai-engineering/skills/llm-eval-harness/SKILL.md +1 -1
- package/packs/ai-engineering/skills/llm-eval-harness/manifest.json +2 -2
- package/packs/api-builder/pack.json +1 -1
- package/packs/api-builder/skills/eval-harness-generator/SKILL.md +1 -1
- package/packs/api-builder/skills/eval-harness-generator/manifest.json +2 -2
- package/packs/api-builder/skills/tool-use-schema-writer/SKILL.md +3 -3
- package/packs/api-builder/skills/tool-use-schema-writer/evals/evals.json +1 -1
- package/packs/api-builder/skills/tool-use-schema-writer/manifest.json +2 -2
- package/packs/core/skills/brief-intake/SKILL.md +2 -2
- package/packs/core/skills/brief-intake/manifest.json +3 -3
- package/packs/core/skills/brief-intake/templates/brief-tech-comparison.md +1 -1
- package/packs/core/skills/council-review/SKILL.md +2 -2
- package/packs/core/skills/council-review/manifest.json +2 -2
- package/packs/core/skills/council-review/reference.md +0 -1
- package/packs/core/skills/doc-critique/SKILL.md +1 -1
- package/packs/core/skills/doc-critique/manifest.json +2 -2
- package/packs/core/skills/doc-critique/rubrics/tech-comparison.md +1 -1
- package/packs/data-analytics/pack.json +8 -14
- package/packs/data-analytics/skills/dashboard-spec/SKILL.md +2 -2
- package/packs/data-analytics/skills/dashboard-spec/examples/support-staffing.md +1 -1
- package/packs/data-analytics/skills/dashboard-spec/manifest.json +1 -10
- package/packs/data-analytics/skills/dashboard-spec/templates/dashboard-spec.md +1 -1
- package/packs/data-analytics/skills/sql-review/SKILL.md +2 -2
- package/packs/data-analytics/skills/sql-review/manifest.json +1 -11
- package/packs/dev-team/skills/migration-plan/SKILL.md +1 -1
- package/packs/dev-team/skills/migration-plan/manifest.json +2 -2
- package/packs/product-manager/skills/business-case/SKILL.md +2 -2
- package/packs/product-manager/skills/business-case/manifest.json +3 -3
- package/packs/product-manager/skills/strategy-analysis/SKILL.md +3 -3
- package/packs/product-manager/skills/strategy-analysis/evals/evals.json +1 -1
- package/packs/product-manager/skills/strategy-analysis/manifest.json +2 -3
- package/packs/research/pack.json +2 -2
- package/packs/research/skills/hypothesis-comparison/SKILL.md +3 -3
- package/packs/research/skills/hypothesis-comparison/manifest.json +2 -3
- package/packs/research/skills/research-plan/SKILL.md +0 -1
- package/packs/research/skills/research-plan/manifest.json +2 -3
- package/packs/research/skills/source-synthesis/SKILL.md +103 -100
- package/packs/research/skills/source-synthesis/evals/evals.json +28 -0
- package/packs/research/skills/source-synthesis/evals/files/6/client-survey-summary.md +15 -0
- package/packs/research/skills/source-synthesis/evals/files/6/fenwick-lane-call-notes.txt +10 -0
- package/packs/research/skills/source-synthesis/evals/files/6/finance-email.txt +21 -0
- package/packs/research/skills/source-synthesis/evals/files/6/practice-ledger-article.md +13 -0
- package/packs/research/skills/source-synthesis/evals/files/6/wcapa-benchmarking-extract.md +12 -0
- package/packs/research/skills/source-synthesis/manifest.json +3 -3
- package/packs/skill-engineering/skills/skill-author/SKILL.md +1 -1
- package/packs/skill-engineering/skills/skill-author/manifest.json +1 -2
- package/packs/skill-engineering/skills/skill-review/SKILL.md +1 -1
- package/packs/skill-engineering/skills/skill-review/manifest.json +1 -2
- package/packs/solution-architect/skills/api-contract-draft/SKILL.md +1 -1
- package/packs/solution-architect/skills/api-contract-draft/manifest.json +2 -2
- package/packs/data-analytics/skills/metric-definition/SKILL.md +0 -92
- package/packs/data-analytics/skills/metric-definition/evals/eval_queries.json +0 -34
- package/packs/data-analytics/skills/metric-definition/evals/evals.json +0 -79
- package/packs/data-analytics/skills/metric-definition/evals/files/2/tables.md +0 -42
- package/packs/data-analytics/skills/metric-definition/evals/files/2/thread.md +0 -40
- package/packs/data-analytics/skills/metric-definition/evals/files/4/tables.md +0 -32
- package/packs/data-analytics/skills/metric-definition/evals/files/4/thread.md +0 -31
- package/packs/data-analytics/skills/metric-definition/examples/refund-rate.md +0 -104
- package/packs/data-analytics/skills/metric-definition/manifest.json +0 -41
- package/packs/data-analytics/skills/metric-definition/reference.md +0 -67
- package/packs/data-analytics/skills/metric-definition/templates/metric-spec.md +0 -70
- package/packs/dev-team/skills/contribution-wizard/SKILL.md +0 -142
- package/packs/dev-team/skills/contribution-wizard/evals/eval_queries.json +0 -30
- package/packs/dev-team/skills/contribution-wizard/evals/evals.json +0 -78
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/AGENTS.md +0 -9
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/CATALOG.md +0 -18
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/CONTRIBUTING.md +0 -45
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/OWNERS.md +0 -7
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/detention-claim-letter/INSTRUCTIONS.md +0 -20
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/detention-claim-letter/skill.yaml +0 -11
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/detention-claim-letter/tests/cases.yaml +0 -25
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/rate-con-extractor/INSTRUCTIONS.md +0 -20
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/rate-con-extractor/skill.yaml +0 -8
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/rate-con-extractor/tests/cases.yaml +0 -32
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/CONTRIBUTING.md +0 -63
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/registry.json +0 -15
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/PROMPT.md +0 -10
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/01-expected.md +0 -2
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/01-input.md +0 -3
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/02-expected.md +0 -1
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/02-input.md +0 -2
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/03-expected.md +0 -1
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/03-input.md +0 -2
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/meta.json +0 -7
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/PROMPT.md +0 -11
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/01-expected.md +0 -4
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/01-input.md +0 -4
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/02-expected.md +0 -6
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/02-input.md +0 -2
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/03-expected.md +0 -1
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/03-input.md +0 -1
- package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/skill.toml +0 -6
- package/packs/dev-team/skills/contribution-wizard/manifest.json +0 -11
- package/packs/solution-architect/skills/db-schema-design/SKILL.md +0 -76
- package/packs/solution-architect/skills/db-schema-design/evals/eval_queries.json +0 -34
- package/packs/solution-architect/skills/db-schema-design/evals/evals.json +0 -75
- package/packs/solution-architect/skills/db-schema-design/evals/files/2/current_tables.sql +0 -29
- package/packs/solution-architect/skills/db-schema-design/evals/files/2/notes.md +0 -53
- package/packs/solution-architect/skills/db-schema-design/evals/files/4/finance-email.md +0 -18
- package/packs/solution-architect/skills/db-schema-design/evals/files/4/members_sample.csv +0 -5
- package/packs/solution-architect/skills/db-schema-design/evals/files/4/points_txn_sample.csv +0 -17
- package/packs/solution-architect/skills/db-schema-design/evals/files/4/requirements.md +0 -28
- package/packs/solution-architect/skills/db-schema-design/manifest.json +0 -11
- package/packs/solution-architect/skills/db-schema-design/reference.md +0 -56
- package/packs/solution-architect/skills/db-schema-design/templates/schema-design.md +0 -75
- package/packs/solution-architect/skills/tech-comparison-matrix/SKILL.md +0 -64
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/eval_queries.json +0 -30
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/evals.json +0 -76
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/files/2/requirements.md +0 -20
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/files/2/vendor-notes.md +0 -29
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/files/4/mobile-options.md +0 -45
- package/packs/solution-architect/skills/tech-comparison-matrix/examples/queue-selection.md +0 -41
- package/packs/solution-architect/skills/tech-comparison-matrix/manifest.json +0 -11
- package/packs/solution-architect/skills/tech-comparison-matrix/templates/matrix.md +0 -45
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "contribution-wizard",
|
|
3
|
-
"version": "1.0.5",
|
|
4
|
-
"description": "Guides an author through creating a new skilldrop skill from scratch — generates the manifest, SKILL.md, eval cases, and skill-catalogue entry from a plain-language description of the skill's purpose. Use when authoring a new skill for this repo or a private fork, ensuring a new skill meets the schema and validation requirements before submission.",
|
|
5
|
-
"entrypoint": "SKILL.md",
|
|
6
|
-
"deps": { "npm": [], "pip": [] },
|
|
7
|
-
"env": { "required": [], "optional": [] },
|
|
8
|
-
"related": ["eval-harness-generator"],
|
|
9
|
-
"tags": ["meta", "authoring", "contribution", "skilldrop-meta"],
|
|
10
|
-
"model": { "tier": "standard", "rationale": "Intake + structured generation — standard tier covers the template-filling and schema-adherence judgment this requires." }
|
|
11
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: db-schema-design
|
|
3
|
-
description: Design a database schema from access patterns — paradigm chosen deliberately (relational/document/key-value/wide-column/graph), keys and partitioning driven by the actual queries, indexes mapped to predicates, money/time types right, and every read path verified to have a supporting access path. Use when the user is designing a data model, schema, or tables for a feature, choosing a database, or asks how to structure/store data.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# db-schema-design
|
|
7
|
-
|
|
8
|
-
Designs the storage layer **from the queries backward** — because a schema is right or wrong only relative to how it's read and written, and the most expensive schema mistakes are the access paths nobody designed for. Distinct from `data-contract` (the guarantee on a *published* dataset) and `api-contract-draft` (the sync interface): this is the table/collection/key design underneath. Hands evolution off to `migration-plan` and the published-dataset guarantee to `data-contract`.
|
|
9
|
-
|
|
10
|
-
## How to respond
|
|
11
|
-
|
|
12
|
-
**Four rules come before the steps and outrank them:**
|
|
13
|
-
|
|
14
|
-
- **Answer what was asked, first.** Open with the answer, the decision or the artifact, in plain words. Scores, matrices, frameworks and tags come after it, and anything that doesn't change the answer is cut.
|
|
15
|
-
- **Use only what you were given.** Don't add facts, names, numbers, incidents, history, steps or sections the input doesn't contain. What you need and don't have is left out of the artifact and listed once at the end under "To confirm".
|
|
16
|
-
- **Deliver from what you have.** When the request gives you something to work on, state your assumptions in a line and produce the result. When it gives you nothing to work on, ask for it in one or two plain sentences and say what you will do once you have it.
|
|
17
|
-
- **Write for someone who has never heard of this skill.** No skill names, no paths or scripts from this folder, no internal terms, and nothing about how the run was set up. A next step is one plain sentence at the end that describes the work.
|
|
18
|
-
- **For this skill:** Give DDL that runs, and the query for each access pattern the user named. Leave out multitenancy, partitioning, rollups and reconciliation unless they asked or a named query needs them.
|
|
19
|
-
|
|
20
|
-
1. **Collect the access patterns before drawing a single table.** The deliverable starts as a list: each read and write the feature needs, with **frequency**, **latency sensitivity**, **selectivity** (one row / a range / a scan), and **consistency need** (read-your-writes? eventual ok?). Ask at most 2 questions, spent on the highest-frequency query and the largest-growth entity. A schema designed from the entity diagram instead of the queries is how you get a clean model that can't serve its hottest path.
|
|
21
|
-
|
|
22
|
-
2. **Choose the paradigm deliberately, with a reason** (selection matrix in [`reference.md`](reference.md)). Relational is the correct default for most transactional features and needs no defense; reaching *past* it does. ✅ *"Document store — the entity is read and written whole, no cross-entity queries, and the shape varies per type"* — ❌ *"NoSQL because scale"* (scale is a property of access patterns and data size, not a vibe). For NoSQL especially, the access patterns *are* the schema — you cannot add a query later for free the way SQL lets you.
|
|
23
|
-
|
|
24
|
-
3. **Design keys from the queries.**
|
|
25
|
-
- **Relational:** surrogate key (e.g. `bigint`/ULID) as PK by default; natural keys get a unique constraint, not the clustered PK. Avoid random UUIDv4 as a clustered/primary key — it scatters writes and splits pages; use a time-ordered ID (ULID/UUIDv7) when you need a UUID and ordered inserts.
|
|
26
|
-
- **NoSQL:** partition key + sort key derived directly from the access patterns, chosen to spread load (no hot partition) and to co-locate what's read together. State the query each key shape serves.
|
|
27
|
-
|
|
28
|
-
4. **Normalize to 3NF, then denormalize only for a named read pattern — and name the sync obligation.** 3NF is the default because it makes writes correct and anomalies impossible. Every denormalization is a deliberate trade for a specific hot read, and it incurs a duplicate-keeping-in-sync debt that must be stated: ✅ *"Cache `order_count` on `customer` for the dashboard's top query; kept in sync by the order-write transaction / a trigger"* — ❌ a denormalized field with no answer to "what updates the copy?".
|
|
29
|
-
|
|
30
|
-
5. **Index for the actual predicates, joins, and sorts — not speculatively.** Every index pays a write cost and storage; an unused index is pure overhead. Rules (full set in [`reference.md`](reference.md)): index the columns in `WHERE`/`JOIN`/`ORDER BY` of real queries; **composite index column order is equality-first, then range, then sort**; consider a covering index for a hot read; don't index low-selectivity columns alone. Map each index to the query it serves — an index with no query is a guess.
|
|
31
|
-
|
|
32
|
-
6. **Get the types and constraints right at the schema, not in app code.** Money as integer minor units or `decimal`, **never float** (echoes `data-contract`); timestamps with explicit timezone (store UTC); enums as a constrained type or lookup table, not free strings; `NOT NULL` + defaults + `CHECK` + foreign keys express invariants the database enforces for every writer, including the ones you'll add later. Right-size types (don't `text` a 2-char country code).
|
|
33
|
-
|
|
34
|
-
7. **State the scale and multitenancy decisions.** Name the table that grows unbounded and its plan (partition by time, archive cold data); the partition/shard strategy if any (and why it's not premature); and the **multitenancy isolation model** (shared-table + `tenant_id` with row-level security / schema-per-tenant / db-per-tenant) with its trade — this is an early decision that's brutal to reverse, so it's explicit, not defaulted.
|
|
35
|
-
|
|
36
|
-
8. **Verify every access pattern has a supporting path, and emit with [`templates/schema-design.md`](templates/schema-design.md)** in one message: access-pattern table, paradigm + rationale, the schema (tables/collections with columns, types, keys, constraints), relationships/cardinality, indexes mapped to queries, scale + multitenancy decisions, and the **verification table** — each access pattern → the key or index that serves it, with any that fall to a full scan flagged. Evolution → `migration-plan`; published-to-consumers → `data-contract`.
|
|
37
|
-
|
|
38
|
-
## Useful references in this skill
|
|
39
|
-
|
|
40
|
-
- [`reference.md`](reference.md) — paradigm-selection matrix, key-design rules, the normalization/denormalization ladder, indexing rules, multitenancy options, and the schema anti-pattern catalog
|
|
41
|
-
- [`templates/schema-design.md`](templates/schema-design.md) — the design skeleton with access-pattern, schema, index, and verification tables
|
|
42
|
-
|
|
43
|
-
## Quality bar
|
|
44
|
-
|
|
45
|
-
- **Access patterns are listed before the schema**, with frequency and selectivity. A schema with no query list was designed blind.
|
|
46
|
-
- **The paradigm choice has a reason tied to access patterns** — and relational-by-default needs none while every move past it does.
|
|
47
|
-
- **Keys are justified by queries**, and no random UUIDv4 sits as a clustered PK without a noted reason.
|
|
48
|
-
- **Every index maps to a real query**; every denormalization names what keeps the copy in sync.
|
|
49
|
-
- **Money is never float, timestamps carry timezone, invariants are DB constraints** — not left to application discipline.
|
|
50
|
-
- **Multitenancy and the unbounded-growth table have explicit plans.** The expensive-to-reverse decisions are made on purpose.
|
|
51
|
-
- **The verification table shows each access pattern's supporting path**, with full scans flagged rather than hidden.
|
|
52
|
-
|
|
53
|
-
## When to use this skill
|
|
54
|
-
|
|
55
|
-
- ✅ Designing tables/collections/keys for a new feature or service
|
|
56
|
-
- ✅ Choosing a database paradigm for a known set of access patterns
|
|
57
|
-
- ✅ "How should I structure / store this data?" with real queries in mind
|
|
58
|
-
- ✅ Reworking a schema whose hot query has no supporting index
|
|
59
|
-
|
|
60
|
-
## When NOT to use this skill
|
|
61
|
-
|
|
62
|
-
- ❌ Governing a dataset other teams consume (quality SLAs, evolution policy) — that's `data-contract`
|
|
63
|
-
- ❌ The sync API/event shape over the data — that's `api-contract-draft`
|
|
64
|
-
- ❌ Executing a schema change on a live system (expand/backfill/contract) — that's `migration-plan`
|
|
65
|
-
- ❌ Picking a specific managed product (Aurora vs Cloud SQL) — that's `tech-comparison-matrix`; this designs the model, not the vendor
|
|
66
|
-
|
|
67
|
-
## Anti-patterns to avoid
|
|
68
|
-
|
|
69
|
-
- ❌ **Entity-first, query-never.** A beautiful normalized ER diagram whose top query needs four joins and a full scan. Design from the access patterns.
|
|
70
|
-
- ❌ **"NoSQL for scale" with no access-pattern argument.** NoSQL trades ad-hoc query flexibility for scale on *known* patterns; choosing it blind buys the downside without the upside.
|
|
71
|
-
- ❌ **UUIDv4 as the clustered primary key.** Random keys scatter inserts and fragment the index; use a time-ordered ID when you need a UUID.
|
|
72
|
-
- ❌ **EAV / the god table.** Entity-attribute-value "flexible" schemas and 80-column catch-all tables are queryability and integrity sold for a flexibility you'll regret.
|
|
73
|
-
- ❌ **JSON-blob-as-schema-avoidance.** Dumping everything in a `jsonb` column to skip design, then writing queries that dig into it with no index — schema design deferred, not avoided, and now unindexable.
|
|
74
|
-
- ❌ **Speculative indexing.** Indexing every column "to be safe" taxes every write and bloats storage; index the queries you have.
|
|
75
|
-
- ❌ **Float money / naked timestamps / stringly-typed enums.** The same three regrets as `data-contract`, baked in at the storage layer where they're hardest to fix.
|
|
76
|
-
- ❌ **Deferring the multitenancy decision.** Shared-table-vs-isolated is near-impossible to change after data lands; an unmade decision is the riskiest one.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"query": "Design the database schema for this feature",
|
|
4
|
-
"should_trigger": true
|
|
5
|
-
},
|
|
6
|
-
{
|
|
7
|
-
"query": "What tables, keys, and indexes do I need for these queries?",
|
|
8
|
-
"should_trigger": true
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"query": "Should this be relational or document, given our access patterns?",
|
|
12
|
-
"should_trigger": true
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"query": "Model the data layer for this access pattern list",
|
|
16
|
-
"should_trigger": true
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"query": "Write a data contract for the table our consumers read",
|
|
20
|
-
"should_trigger": false
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"query": "Draft the OpenAPI contract for the service",
|
|
24
|
-
"should_trigger": false
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"query": "Diagram our system architecture",
|
|
28
|
-
"should_trigger": false
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"query": "Plan the migration from the old schema",
|
|
32
|
-
"should_trigger": false
|
|
33
|
-
}
|
|
34
|
-
]
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"skill_name": "db-schema-design",
|
|
3
|
-
"evals": [
|
|
4
|
-
{
|
|
5
|
-
"id": 1,
|
|
6
|
-
"prompt": "Design the schema for an order-history feature. Queries: fetch one order by id, list a customer's orders newest-first, and report daily totals by region.",
|
|
7
|
-
"assertions": [
|
|
8
|
-
"Access patterns are listed before the schema, with frequency and selectivity",
|
|
9
|
-
"The paradigm choice is justified against those access patterns — relational-by-default needs no defence, every move past it does",
|
|
10
|
-
"Keys and partitioning are justified by the actual queries; a random UUIDv4 clustered primary key is not used without a stated reason",
|
|
11
|
-
"Every index maps to a real predicate from the listed queries rather than being speculative",
|
|
12
|
-
"Denormalization, where proposed, names the read it serves and the write cost it adds"
|
|
13
|
-
]
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"id": 2,
|
|
17
|
-
"held_out": "2026-10-05",
|
|
18
|
-
"prompt": "We're rebuilding the booking system for our vet clinics and I need the database tables designed properly this time. My notes on what it has to do are in notes.md and the tables we have today are in current_tables.sql. Can you give me the new schema, with the SQL to create it and the queries for the screens and the report?",
|
|
19
|
-
"assertions": [
|
|
20
|
-
"It includes CREATE TABLE statements for the new schema, with owners and pets as their own tables instead of the owner_name, owner_phone and pet_name columns repeated on each appointment",
|
|
21
|
-
"Double-booking a vet is prevented by a database constraint that handles appointments of different lengths (for example an exclusion constraint on a time range, or one row per time slot with a unique key), not only by an application check or by a unique key on vet and start time alone",
|
|
22
|
-
"Cancelled appointments are excluded from that constraint, so a cancelled time can be booked again",
|
|
23
|
-
"It points out that the notes say Postgres 15 while the contractor says the current app runs on MySQL 8, and states which one the SQL is written for",
|
|
24
|
-
"Prices are stored as an exact type (integer cents or a decimal/numeric), not FLOAT, and the price is modelled per appointment type per clinic",
|
|
25
|
-
"Appointment times are stored with a time zone or in UTC with each clinic's time zone recorded, and it notes that storing Sydney local time is wrong for the Brisbane clinics",
|
|
26
|
-
"It says the no-show report cannot be produced from the current statuses (booked, cancelled, completed) and adds a no-show status or an equivalent field",
|
|
27
|
-
"It gives a query or a named index for the vet's-day screen that leads on the vet and the appointment start time, and does not add tables for invoicing, payments, stock or clinical records"
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"id": 3,
|
|
32
|
-
"held_out": "2026-10-05",
|
|
33
|
-
"prompt": "need somewhere to store sensor readings from our greenhouses. about 200 sensors, each does temperature + humidity, a reading every minute or so I think. I want to chart the last 24h for any one sensor and get an alert when something goes out of range. haven't picked a database yet. what tables do I need?",
|
|
34
|
-
"assertions": [
|
|
35
|
-
"It gives concrete table definitions (SQL or an equivalent column-by-column layout) in the reply, and does not stop to ask questions before delivering them",
|
|
36
|
-
"The readings table has a key or index on the sensor and the reading time together, and the reply ties it to the last-24-hours chart for one sensor",
|
|
37
|
-
"It works out the volume from the numbers given: about 288,000 readings a day (roughly 105 million a year) at one reading per sensor per minute, or an equivalent calculation",
|
|
38
|
-
"It names a database to use, or says which one it assumed, with a reason linked to the chart and alert queries",
|
|
39
|
-
"It says how long readings should be kept is not known and lists it as something to decide, without stating a retention period as if it had been given",
|
|
40
|
-
"It stores the allowed range somewhere (per sensor, per greenhouse or per sensor type) and says the actual range values were not given; any numbers shown are labelled as examples",
|
|
41
|
-
"Reading times are stored with a time zone or in UTC"
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"id": 4,
|
|
46
|
-
"held_out": "2026-10-06",
|
|
47
|
-
"prompt": "We're rebuilding the loyalty points system at Greenlane Markets (220 stores). My notes are in requirements.md, finance's email is in finance-email.md, and there's a small export of what we have today in members_sample.csv and points_txn_sample.csv. Can you design the new tables? I need the SQL and a short note on the decisions and anything in there that looks off — not an essay.",
|
|
48
|
-
"assertions": [
|
|
49
|
-
"It includes CREATE TABLE statements in which points movements (earn, redeem, expire, adjust) are rows in a ledger that is only ever added to, and a member's balance is either computed from those rows or kept as a stored total that it says how to keep in step with them",
|
|
50
|
-
"It points out that member M-1042's entries in the sample add up to 1,340 points while the members table says 1,410, a difference of 70",
|
|
51
|
-
"A duplicate till submission is blocked by a unique constraint or key built on the receipt reference (with store and/or till), and it notes that receipt R-88213 appears twice in the sample",
|
|
52
|
-
"It flags that the notes say points expire after 24 months and finance says 18, does not silently pick one, and stores an expiry date (or the earn date plus a configurable period) per earned lot so either rule can be applied",
|
|
53
|
-
"It says points by household cannot be produced because nothing in the data identifies a household, and it does not treat a shared postcode as a household",
|
|
54
|
-
"It points out that 400k transactions a day is about 146 million a year, not the 50 million in the notes",
|
|
55
|
-
"Points are stored as integers and money amounts as an exact type (numeric/decimal or integer pence), not FLOAT, and the value of a point is not hard-coded as 0.5p in the schema",
|
|
56
|
-
"It shows how the liability report can be run as at a past month end by store where earned, and gives an index or key on member and time for the newest-first history screen"
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"id": 5,
|
|
61
|
-
"held_out": "2026-10-06",
|
|
62
|
-
"prompt": "we're a building firm, about 30 of us. right now who-has-what kit is tracked on a whiteboard in the yard and it's useless. I want a little internal tool: where is each thing right now, and where has it been / who had it. stuff isn't always on a site, sometimes it's in someone's van or at the repair shop. also need to know when things are due their safety test. few hundred items I'd guess? the IT guy set up a Postgres for the timesheets I think, could use that. what tables do I need",
|
|
63
|
-
"assertions": [
|
|
64
|
-
"It gives concrete table definitions (SQL or a column-by-column layout) in the reply, and does not stop to ask questions before delivering them",
|
|
65
|
-
"There is a movements or assignments table with one row per hand-over recording the item, where it went, who has it and when, so an item's full history can be listed",
|
|
66
|
-
"It says how 'where is it right now' is answered (the latest movement row, or a current-location column) and, if both are stored, how they are kept consistent",
|
|
67
|
-
"The design can record an item being somewhere that is not a site, such as a van or the repair shop, without leaving the location empty",
|
|
68
|
-
"It stores a test due date or last-tested date per item and says the test interval was not given; any interval shown is labelled as an example or assumption",
|
|
69
|
-
"It says it has assumed each item is tracked individually, or flags that it is not known whether some kit is counted in bulk (for example a box of identical items)",
|
|
70
|
-
"It says Postgres is assumed from 'I think' and should be confirmed, and does not recommend partitioning, sharding or a non-relational database for a few hundred items",
|
|
71
|
-
"It does not state a number of sites, vans or items as fact beyond the 'few hundred' guess given"
|
|
72
|
-
]
|
|
73
|
-
}
|
|
74
|
-
]
|
|
75
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
-- Dump of the tables the current booking app uses. Schema only.
|
|
2
|
-
-- NOTE (Devraj): all times are stored as Sydney local time, for every clinic.
|
|
3
|
-
|
|
4
|
-
CREATE TABLE clinics (
|
|
5
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
6
|
-
name VARCHAR(80) NOT NULL,
|
|
7
|
-
city VARCHAR(40) NOT NULL
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
CREATE TABLE vets (
|
|
11
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
12
|
-
full_name VARCHAR(120) NOT NULL,
|
|
13
|
-
clinic_id INT NOT NULL -- home clinic only
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
CREATE TABLE appointments (
|
|
17
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
18
|
-
clinic_id INT NOT NULL,
|
|
19
|
-
vet_id INT NOT NULL,
|
|
20
|
-
appt_time DATETIME NOT NULL, -- start time, Sydney local
|
|
21
|
-
appt_type VARCHAR(40) NOT NULL, -- free text: 'consult', 'Consult', 'vacc', ...
|
|
22
|
-
price FLOAT,
|
|
23
|
-
owner_name VARCHAR(120),
|
|
24
|
-
owner_phone VARCHAR(40),
|
|
25
|
-
pet_name VARCHAR(80),
|
|
26
|
-
status VARCHAR(20) NOT NULL -- 'booked', 'cancelled', 'completed'
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
-- no indexes other than the primary keys
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# Pawsley Vets: booking rebuild, working notes
|
|
2
|
-
|
|
3
|
-
Written by Imogen Tarrant (practice systems lead), last touched 22 Sept 2026.
|
|
4
|
-
|
|
5
|
-
## Who we are
|
|
6
|
-
|
|
7
|
-
- 6 clinics. Four around Sydney (Marrickville, Newtown, Manly, Parramatta) and two in
|
|
8
|
-
Brisbane (Paddington, West End).
|
|
9
|
-
- About 38 vets. Seven of them work at two clinics on different days of the week.
|
|
10
|
-
- Roughly 450 appointments a day across the group.
|
|
11
|
-
- About 21,000 active pets belonging to about 15,000 owners. An owner can have several pets.
|
|
12
|
-
|
|
13
|
-
## Appointment types
|
|
14
|
-
|
|
15
|
-
| Type | Length |
|
|
16
|
-
|---|---|
|
|
17
|
-
| Consult | 15 min |
|
|
18
|
-
| Vaccination | 15 min |
|
|
19
|
-
| Extended consult | 30 min |
|
|
20
|
-
| Surgery consult | 60 min |
|
|
21
|
-
|
|
22
|
-
Lengths will probably change (we are talking about 20-minute consults). Each type has a price,
|
|
23
|
-
and the price is different at each clinic.
|
|
24
|
-
|
|
25
|
-
## What the new system has to do
|
|
26
|
-
|
|
27
|
-
1. **A vet's day.** Reception pulls up every appointment for one vet on one date, in time
|
|
28
|
-
order. This is the screen that is open all day at every front desk and refreshes every few
|
|
29
|
-
seconds. It has to feel instant.
|
|
30
|
-
2. **A clinic's day.** Same thing but for every vet working at one clinic that day.
|
|
31
|
-
3. **Owner portal.** An owner logs in and sees the upcoming appointments for all of their pets.
|
|
32
|
-
4. **Free slots.** Given a vet (or a clinic) and a date, what times are still open.
|
|
33
|
-
5. **Monthly report.** No-show rate per clinic per month. The directors ask for this every
|
|
34
|
-
month and today somebody counts it by hand from the paper diary.
|
|
35
|
-
6. **No double-booking a vet. Ever.** It happened 11 times last quarter. The current app checks
|
|
36
|
-
whether the slot is free and then inserts, and two receptionists at different desks can both
|
|
37
|
-
get through. If an appointment is cancelled, that time has to become bookable again.
|
|
38
|
-
|
|
39
|
-
## Stack
|
|
40
|
-
|
|
41
|
-
Database: Postgres 15 on the managed service (that is what the hosting invoice says).
|
|
42
|
-
|
|
43
|
-
Pasted from Devraj (contractor who maintains the current app), 18 Sept:
|
|
44
|
-
|
|
45
|
-
> the current booking app is on MySQL 8, has been since 2021. I'd just keep it there tbh,
|
|
46
|
-
> no reason to move
|
|
47
|
-
|
|
48
|
-
I have not chased up which of those is right.
|
|
49
|
-
|
|
50
|
-
## Other
|
|
51
|
-
|
|
52
|
-
- The existing tables are in current_tables.sql. I know they are not great.
|
|
53
|
-
- Not in scope for this piece of work: invoicing and payments, stock, clinical records.
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
From: Ines Okonjo-Bright (Financial Controller)
|
|
2
|
-
To: Tomasz Wierzba
|
|
3
|
-
Date: 29 September 2026
|
|
4
|
-
Subject: Loyalty rebuild - what finance needs
|
|
5
|
-
|
|
6
|
-
Tomasz,
|
|
7
|
-
|
|
8
|
-
Three things before you design anything.
|
|
9
|
-
|
|
10
|
-
1. The balances do not tie to the log. In the audit sample, member M-1042 shows 1,410 points on the members table. I added up the log myself and I do not get that. The auditors want every balance to be provable from the entries behind it.
|
|
11
|
-
|
|
12
|
-
2. Since the January change, points expire after 18 months, not 24. Please make sure the new system does that.
|
|
13
|
-
|
|
14
|
-
3. The liability report (unexpired points by the store where they were earned) has to be re-runnable as at any past month end. The auditors asked us to re-run March in July and we could not, because the old numbers had been overwritten.
|
|
15
|
-
|
|
16
|
-
Also, the value of a point is a pricing decision and it may change next year. Do not bake 0.5p in.
|
|
17
|
-
|
|
18
|
-
Ines
|
package/packs/solution-architect/skills/db-schema-design/evals/files/4/points_txn_sample.csv
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
txn_id,member_id,store_id,till_id,receipt_ref,type,points,basket_value,created_at
|
|
2
|
-
90001,M-1042,S014,T03,R-51120,earn,84,84.19999999999999,2026-05-02 10:14:51
|
|
3
|
-
90002,M-1042,S014,T01,R-51877,earn,126,126.45,2026-05-16 18:02:33
|
|
4
|
-
90003,M-1042,S014,,,bonus,500,,2026-05-20 00:05:00
|
|
5
|
-
90004,M-1042,S031,T07,R-60233,earn,97,97.30000000000001,2026-06-06 12:40:09
|
|
6
|
-
90005,M-1042,S014,T02,R-52990,redeem,-400,61.75,2026-06-20 16:21:47
|
|
7
|
-
90006,M-1042,S014,T02,R-53641,earn,143,143.08,2026-07-11 09:55:12
|
|
8
|
-
90007,M-1042,,,,adjust,250,,2026-07-15 14:30:00
|
|
9
|
-
90008,M-1042,S014,,,bonus,540,,2026-08-01 00:05:00
|
|
10
|
-
90009,M-2077,S102,T04,R-88213,earn,85,85.6,2026-08-09 19:03:21
|
|
11
|
-
90010,M-2077,S102,T04,R-88213,earn,85,85.6,2026-08-09 19:03:25
|
|
12
|
-
90011,M-2077,S102,T01,R-88590,earn,40,40.15,2026-08-23 11:12:02
|
|
13
|
-
90012,M-3310,S014,T03,R-54002,earn,52,52.0,2026-07-04 13:08:40
|
|
14
|
-
90013,M-3310,S057,T02,R-71455,earn,71,71.89999999999999,2026-07-18 17:45:16
|
|
15
|
-
90014,M-3310,S057,T02,R-71901,redeem,-100,33.2,2026-08-01 12:02:58
|
|
16
|
-
90015,M-0456,S031,T05,R-40118,earn,66,66.4,2024-08-30 15:27:03
|
|
17
|
-
90016,M-0456,,,,expire,-66,,2026-08-31 02:00:00
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# Greenlane Rewards rebuild — my notes (Tomasz, platform team)
|
|
2
|
-
|
|
3
|
-
Greenlane Markets: 220 stores, about 1.8M loyalty members.
|
|
4
|
-
|
|
5
|
-
## What we have today
|
|
6
|
-
- `members` table with a `points_balance` column. The tills update it directly.
|
|
7
|
-
- `points_txn` log table, bolted on in 2023. Nothing enforces that it agrees with the balance.
|
|
8
|
-
- `basket_value` is a FLOAT. Timestamps are whatever the till's clock said, no zone.
|
|
9
|
-
|
|
10
|
-
## What the new one has to do
|
|
11
|
-
1. Till scans a loyalty card -> look up the member by card number and show the balance. Needs to be fast (under 100 ms), it happens on every loyalty basket.
|
|
12
|
-
2. Till earns points on a basket, or redeems points against a basket.
|
|
13
|
-
3. App: member sees their points history, newest first, 20 rows at a time.
|
|
14
|
-
4. Points expire 24 months after they were earned. A nightly job expires them. Oldest points get spent first.
|
|
15
|
-
5. Customer services can make a manual adjustment. We need the reason and who did it.
|
|
16
|
-
6. Finance: month-end liability = unexpired points outstanding, split by the store where they were earned.
|
|
17
|
-
7. Marketing (Dalia) wants points by household.
|
|
18
|
-
|
|
19
|
-
## Numbers
|
|
20
|
-
- About 400k loyalty transactions a day, so roughly 50 million a year.
|
|
21
|
-
- 1 point per whole pound spent. A point is worth 0.5p when redeemed.
|
|
22
|
-
|
|
23
|
-
## Known problems
|
|
24
|
-
- Tills retry on timeout because store networks are flaky. We have definitely had the same receipt sent twice.
|
|
25
|
-
- Balances drift. Finance are not happy, see their email.
|
|
26
|
-
|
|
27
|
-
## Decided
|
|
28
|
-
- Postgres 16 (managed). Not changing.
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "db-schema-design",
|
|
3
|
-
"version": "0.1.1",
|
|
4
|
-
"description": "Design a database schema from access patterns — paradigm chosen deliberately (relational/document/key-value/wide-column/graph), keys and partitioning driven by the actual queries, indexes mapped to predicates, money/time types right, and every read path verified to have a supporting access path. Use when the user is designing a data model, schema, or tables for a feature, choosing a database, or asks how to structure/store data.",
|
|
5
|
-
"entrypoint": "SKILL.md",
|
|
6
|
-
"deps": { "npm": [], "pip": [] },
|
|
7
|
-
"env": { "required": [], "optional": [] },
|
|
8
|
-
"related": ["api-contract-draft", "data-contract", "migration-plan", "tech-comparison-matrix"],
|
|
9
|
-
"tags": ["database", "schema-design", "data-model", "indexing", "sql", "nosql"],
|
|
10
|
-
"model": { "tier": "standard", "rationale": "Design synthesis from access patterns against a fixed paradigm/indexing/anti-pattern reference. Paradigm and denormalization judgment is bounded; escalate via ambiguous-input on contested scale/consistency tradeoffs." }
|
|
11
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# db-schema-design reference — paradigm matrix, keys, indexing, multitenancy, anti-patterns
|
|
2
|
-
|
|
3
|
-
## Paradigm-selection matrix (relational is the default; justify moving past it)
|
|
4
|
-
|
|
5
|
-
| Paradigm | Fits when | Access-pattern signal | Cost of choosing it |
|
|
6
|
-
|---|---|---|---|
|
|
7
|
-
| **Relational** (Postgres, MySQL) | transactional data, ad-hoc queries, joins, strong consistency | "we'll query this many ways, some not yet known"; integrity matters | vertical-scale ceiling (far off for most); needs sharding eventually at very high write volume |
|
|
8
|
-
| **Document** (Mongo, DynamoDB doc, Firestore) | entity read/written whole, varying shape per item, few cross-entity queries | "always fetch the whole order with its lines by order id" | ad-hoc cross-document queries are slow/absent; you design for the queries you know |
|
|
9
|
-
| **Key-value** (Redis, DynamoDB KV) | get/put by a single key, caching, sessions, very high throughput | "look up by exact id, nothing else" | no querying beyond the key; not a system of record alone |
|
|
10
|
-
| **Wide-column** (Cassandra, Bigtable) | massive write volume, time-series-ish, known query keys, linear scale | "billions of rows, query by partition+time, no joins" | one table per query pattern; data duplicated across tables; eventual consistency |
|
|
11
|
-
| **Graph** (Neo4j) | relationship traversal is the query (friends-of-friends, paths, recommendations) | "find all X connected to Y within N hops" | overkill for tabular data; operational maturity cost |
|
|
12
|
-
| **Time-series** (Timescale, Influx) | append-heavy metrics/events keyed by time, downsampling, retention | "ingest events, query ranges, roll up by window" | narrow purpose; pair with a relational store for the rest |
|
|
13
|
-
|
|
14
|
-
Polyglot is legitimate (Postgres for the system of record + Redis cache + a search index) — but each store needs its own access-pattern justification, and you now own the consistency between them.
|
|
15
|
-
|
|
16
|
-
## Key design
|
|
17
|
-
|
|
18
|
-
- **Surrogate vs natural (relational):** surrogate PK (`bigint` identity, or ULID/UUIDv7) by default — stable, opaque, join-friendly. Natural keys (email, SKU) get a `UNIQUE` constraint, not the role of clustered PK (they change, and they leak into URLs/logs).
|
|
19
|
-
- **Avoid random UUIDv4 as a clustered/primary key:** random order scatters inserts across the B-tree, causing page splits and write amplification. Use **UUIDv7/ULID** (time-ordered) when you need a UUID with ordered inserts, or a `bigint` sequence.
|
|
20
|
-
- **NoSQL partition + sort key:** derive from access patterns. Partition key must spread load — a low-cardinality or monotonically-increasing partition key creates a **hot partition**. Sort key co-locates and orders what's read together (e.g. PK=`customer_id`, SK=`order#<ts>` to list a customer's orders by time). One access pattern that doesn't fit the key shape = a new table or a secondary index, decided now.
|
|
21
|
-
- **Composite/natural uniqueness:** enforce real-world uniqueness (one active subscription per customer) with a partial/unique index, not app-code checks that race.
|
|
22
|
-
|
|
23
|
-
## Normalization / denormalization ladder
|
|
24
|
-
|
|
25
|
-
1. **Start at 3NF.** Each fact in one place; no update anomalies. This is the correct default for a system of record.
|
|
26
|
-
2. **Denormalize only for a named hot read**, and only after the normalized form is shown to be the bottleneck (or obviously will be). Examples: a counter cache (`order_count`), a duplicated display field to avoid a join on the top query, a materialized view.
|
|
27
|
-
3. **Every denormalization states its sync mechanism** — transaction, trigger, application code, or scheduled rebuild — and accepts the staleness window. A duplicated value with no sync owner *will* drift.
|
|
28
|
-
4. **NoSQL is denormalized by design** — you duplicate across items/tables to serve each access pattern; the "sync obligation" becomes a write-path responsibility (write to all copies, or accept eventual reconciliation).
|
|
29
|
-
|
|
30
|
-
## Indexing rules
|
|
31
|
-
|
|
32
|
-
- Index the columns that appear in `WHERE`, `JOIN`, and `ORDER BY` of **actual** queries.
|
|
33
|
-
- **Composite column order: equality predicates first, then the range predicate, then the sort column.** `WHERE tenant_id = ? AND created_at > ? ORDER BY created_at` → index `(tenant_id, created_at)`.
|
|
34
|
-
- A **covering index** (includes the selected columns) turns a hot read into an index-only scan — worth it for a top query, costly to maintain for a rare one.
|
|
35
|
-
- **Don't index low-selectivity columns alone** (a boolean, a 3-value status) — the scan is cheaper than the index hop; combine with a selective column instead, or use a partial index (`WHERE status = 'active'`).
|
|
36
|
-
- Every index taxes **every write** and consumes storage. The right count is "one per real query shape," not zero and not all-columns.
|
|
37
|
-
- Foreign-key columns are usually worth indexing (joins + cascade performance).
|
|
38
|
-
|
|
39
|
-
## Multitenancy isolation (decide early — expensive to reverse)
|
|
40
|
-
|
|
41
|
-
| Model | Isolation | Cost / blast radius | Fits |
|
|
42
|
-
|---|---|---|---|
|
|
43
|
-
| Shared table + `tenant_id` (+ row-level security) | logical, enforced by RLS/query | cheapest; a query bug = cross-tenant leak (see `threat-model`) | many small tenants, SaaS default |
|
|
44
|
-
| Schema-per-tenant | stronger; separate tables per tenant | migrations × N schemas; noisy-neighbor still shared | tens–hundreds of mid tenants |
|
|
45
|
-
| Database-per-tenant | strongest; separate DBs | highest ops cost; per-tenant backup/restore is a feature | few large/regulated/enterprise tenants |
|
|
46
|
-
|
|
47
|
-
State the choice and its trade. If shared-table, the `tenant_id` predicate is non-negotiable on every query and belongs in RLS, not developer discipline.
|
|
48
|
-
|
|
49
|
-
## Schema anti-pattern catalog
|
|
50
|
-
|
|
51
|
-
- **EAV (entity-attribute-value)** — rows of `(entity, attribute, value)` to be "flexible." Kills types, constraints, and queryability. Use real columns, or a typed `jsonb` column with documented shape and expression indexes — not a generic triple store.
|
|
52
|
-
- **The god table** — 60+ columns, half null for any given row, modeling several entities at once. Split by entity.
|
|
53
|
-
- **JSON-blob-as-schema-avoidance** — `jsonb` for everything to skip modeling, then unindexed queries digging into it. JSON is for genuinely variable/sparse sub-structure, with expression indexes on what you query.
|
|
54
|
-
- **Premature sharding** — operational complexity for scale you don't have. Vertical + read replicas + partitioning usually buy years first.
|
|
55
|
-
- **Index-everything / index-nothing** — both are failures; index the real query shapes.
|
|
56
|
-
- **Soft-delete everywhere without thought** — `is_deleted` flags leak into every query and every unique constraint; decide per table, and use partial indexes (`WHERE NOT is_deleted`).
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# Schema-design template
|
|
2
|
-
|
|
3
|
-
Access patterns first, schema second, verification last — every query must end the document with a supporting path.
|
|
4
|
-
|
|
5
|
-
```markdown
|
|
6
|
-
# Schema design: {feature / domain}
|
|
7
|
-
|
|
8
|
-
**Paradigm:** {relational | document | key-value | wide-column | graph | time-series}
|
|
9
|
-
**Rationale:** {tied to the access patterns below — relational needs none; anything else justifies}
|
|
10
|
-
**Engine (if decided):** {Postgres 16 | DynamoDB | …} `[assumption if not confirmed]`
|
|
11
|
-
|
|
12
|
-
## Access patterns (the spec the schema is judged against)
|
|
13
|
-
|
|
14
|
-
| # | Query / write | R/W | Frequency | Selectivity | Latency | Consistency |
|
|
15
|
-
|---|---|---|---|---|---|---|
|
|
16
|
-
| Q1 | get order with lines by order id | R | very high | 1 row + children | <50ms | read-your-writes |
|
|
17
|
-
| Q2 | list a customer's orders, newest first | R | high | range | <200ms | eventual ok |
|
|
18
|
-
| W1 | create order + lines | W | high | — | — | atomic |
|
|
19
|
-
|
|
20
|
-
## Schema
|
|
21
|
-
|
|
22
|
-
### {table / collection: orders}
|
|
23
|
-
|
|
24
|
-
| Column | Type | Null | Key/constraint | Notes |
|
|
25
|
-
|---|---|---|---|---|
|
|
26
|
-
| id | bigint / ULID | no | PK | surrogate; time-ordered |
|
|
27
|
-
| customer_id | bigint | no | FK → customers(id), indexed | |
|
|
28
|
-
| total_minor | bigint | no | CHECK (>= 0) | minor units, currency below — never float |
|
|
29
|
-
| currency | char(3) | no | CHECK (ISO-4217) | |
|
|
30
|
-
| status | text | no | CHECK in (pending,paid,shipped,cancelled) | enum, not free string |
|
|
31
|
-
| created_at | timestamptz | no | default now() | UTC |
|
|
32
|
-
|
|
33
|
-
{Repeat per table/collection. For NoSQL: state PK (partition) + SK (sort) and the access pattern each serves.}
|
|
34
|
-
|
|
35
|
-
## Relationships
|
|
36
|
-
|
|
37
|
-
- customers 1 —< orders 1 —< order_lines (cascade: delete order → delete its lines)
|
|
38
|
-
- {cardinality + cascade/restrict per relationship}
|
|
39
|
-
|
|
40
|
-
## Indexes (each maps to a query)
|
|
41
|
-
|
|
42
|
-
| Index | Columns (order matters) | Serves | Type |
|
|
43
|
-
|---|---|---|---|
|
|
44
|
-
| idx_orders_customer_created | (customer_id, created_at) | Q2 (equality then sort) | btree |
|
|
45
|
-
| pk_orders | (id) | Q1 | primary key (clustered/index-organized only on engines that support it — Postgres heaps don't) |
|
|
46
|
-
|
|
47
|
-
{Note any covering/partial index and why. No index without a query.}
|
|
48
|
-
|
|
49
|
-
## Denormalizations (if any)
|
|
50
|
-
|
|
51
|
-
| Field | On | For query | Kept in sync by |
|
|
52
|
-
|---|---|---|---|
|
|
53
|
-
| order_count | customers | dashboard top read | order-write transaction |
|
|
54
|
-
|
|
55
|
-
## Scale & multitenancy
|
|
56
|
-
|
|
57
|
-
- **Unbounded-growth table:** {orders} — plan: {partition by created_at month; archive > 24mo to cold storage}.
|
|
58
|
-
- **Partition/shard:** {none yet — vertical + read replica suffices to ~Nx; revisit at {trigger}} or {strategy + why not premature}.
|
|
59
|
-
- **Multitenancy:** {shared-table + tenant_id + RLS | schema-per-tenant | db-per-tenant} — trade: {…}. `tenant_id` predicate enforced by {RLS policy}.
|
|
60
|
-
|
|
61
|
-
## Verification — every access pattern has a path
|
|
62
|
-
|
|
63
|
-
| # | Supported by | Full scan? |
|
|
64
|
-
|---|---|---|
|
|
65
|
-
| Q1 | pk_orders + FK index on lines | no |
|
|
66
|
-
| Q2 | idx_orders_customer_created | no |
|
|
67
|
-
| W1 | insert; FK indexes present | no |
|
|
68
|
-
|
|
69
|
-
⚠ {Any pattern with no supporting index/key — flag it and resolve before build.}
|
|
70
|
-
|
|
71
|
-
## Evolution
|
|
72
|
-
|
|
73
|
-
- Migrations / rollout of changes → `migration-plan`.
|
|
74
|
-
- If this data is published to other teams → wrap it in a `data-contract`.
|
|
75
|
-
```
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: tech-comparison-matrix
|
|
3
|
-
description: Produce a weighted comparison matrix for a technology selection question (e.g., "Postgres vs DynamoDB", "Kafka vs Kinesis vs RabbitMQ", "Snowflake vs Databricks"). Surfaces criteria, weights, per-option scores, totals, and a recommended pick. Use when the user is choosing between technologies, vendors, frameworks, or architectural approaches.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# tech-comparison-matrix
|
|
7
|
-
|
|
8
|
-
You help the user make defensible tech-selection decisions by producing a weighted comparison matrix that they can paste into a design doc, ADR, or steering-committee deck.
|
|
9
|
-
|
|
10
|
-
## How to respond
|
|
11
|
-
|
|
12
|
-
**Four rules come before the steps and outrank them:**
|
|
13
|
-
|
|
14
|
-
- **Answer what was asked, first.** Open with the answer, the decision or the artifact, in plain words. Scores, matrices, frameworks and tags come after it, and anything that doesn't change the answer is cut.
|
|
15
|
-
- **Use only what you were given.** Don't add facts, names, numbers, incidents, history, steps or sections the input doesn't contain. What you need and don't have is left out of the artifact and listed once at the end under "To confirm".
|
|
16
|
-
- **Deliver from what you have.** When the request gives you something to work on, state your assumptions in a line and produce the result. When it gives you nothing to work on, ask for it in one or two plain sentences and say what you will do once you have it.
|
|
17
|
-
- **Write for someone who has never heard of this skill.** No skill names, no paths or scripts from this folder, no internal terms, and nothing about how the run was set up. A next step is one plain sentence at the end that describes the work.
|
|
18
|
-
- **For this skill:** Lead with the recommendation and the two or three facts that decide it. Include the matrix only when it shows something those facts don't, and leave out weighted scores when one constraint settles the question.
|
|
19
|
-
|
|
20
|
-
1. **Pin down the question.** Make sure you have:
|
|
21
|
-
- **The options** (2–5 — past 5 the matrix becomes noise; cut the long-shots first)
|
|
22
|
-
- **The use case in one sentence** ("primary OLTP store for a multi-tenant SaaS app, ~10k writes/sec, latency p99 < 50ms")
|
|
23
|
-
- **Hard constraints** (e.g., "must run on-prem", "must be open source", "team has zero ops capacity for self-hosting")
|
|
24
|
-
|
|
25
|
-
Ask at most 2 clarifying questions. If the user only gave you the options without a use case, ask for the use case — it determines the criteria.
|
|
26
|
-
|
|
27
|
-
2. **Pick the criteria.** Default to a balanced set across these axes (8–10 criteria is the sweet spot — fewer feels shallow, more becomes noise):
|
|
28
|
-
|
|
29
|
-
| Axis | Example criteria |
|
|
30
|
-
|---|---|
|
|
31
|
-
| **Capability fit** | Throughput, latency, query model, consistency model, schema flexibility |
|
|
32
|
-
| **Operational** | Self-hosted vs managed, scaling story, backup/restore, observability |
|
|
33
|
-
| **Cost** | License, infrastructure, support, total cost of ownership at scale |
|
|
34
|
-
| **Risk** | Vendor lock-in, ecosystem maturity, hiring market, our team's familiarity |
|
|
35
|
-
|
|
36
|
-
Mention any criteria you intentionally **excluded** so the user can challenge it. ("I left out 'community size' — let me know if that matters for you.")
|
|
37
|
-
|
|
38
|
-
3. **Apply weights.** Use 1–5 (5 = critical to the decision, 1 = nice-to-have). Tie the weights to the use case in writing. *"Latency is weighted 5 because the use case demands sub-50ms p99"* makes the matrix audit-able; bare numbers don't.
|
|
39
|
-
|
|
40
|
-
4. **Score each option per criterion** on a 1–5 scale. Justify every 5 and every 1 in one phrase — the body of the deliverable is the *reasoning*, not the numbers.
|
|
41
|
-
|
|
42
|
-
5. **Total it up.** `Total = sum(weight × score)`. Highest total ≠ automatic winner — if the gap is small (< 5%), call that out and let the user pick on gut feel.
|
|
43
|
-
|
|
44
|
-
6. **Recommend explicitly.** End with a "Recommendation" paragraph: which option, why, and what would change the answer.
|
|
45
|
-
|
|
46
|
-
## Output format
|
|
47
|
-
|
|
48
|
-
Use [`templates/matrix.md`](templates/matrix.md) as the skeleton. The deliverable should fit on **one screen** when rendered — if it doesn't, you have too many criteria.
|
|
49
|
-
|
|
50
|
-
## Quality bar
|
|
51
|
-
|
|
52
|
-
- **Every score has a one-line justification.** A bare "4/5" is not a comparison.
|
|
53
|
-
- **Tie scores are fine** — don't force differentiation that isn't there.
|
|
54
|
-
- **The recommendation is one sentence, not a paragraph of hedging.**
|
|
55
|
-
- **Show your weights** — a matrix with hidden weights is just an opinion.
|
|
56
|
-
- **No false precision.** If a number is a guess, say "rough" or "directional".
|
|
57
|
-
|
|
58
|
-
## Anti-patterns to avoid
|
|
59
|
-
|
|
60
|
-
- ❌ Scoring every criterion 3/5 ("balanced") — the matrix exists to differentiate, not to be polite.
|
|
61
|
-
- ❌ Picking criteria that all favour the option you secretly want to win.
|
|
62
|
-
- ❌ Including "community popularity" as a top-weighted criterion when the use case doesn't care.
|
|
63
|
-
- ❌ Recommending an option whose score wasn't highest, without explaining the override.
|
|
64
|
-
- ❌ Inventing benchmarks. If you don't have a number, say "estimated" and source the estimate.
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"query": "Postgres vs DynamoDB for our multi-tenant OLTP store — build me a weighted matrix",
|
|
4
|
-
"should_trigger": true
|
|
5
|
-
},
|
|
6
|
-
{
|
|
7
|
-
"query": "We're choosing between Snowflake and Databricks; score them against our criteria",
|
|
8
|
-
"should_trigger": true
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"query": "Compare three observability vendors and recommend one for our team",
|
|
12
|
-
"should_trigger": true
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"query": "Which frontend framework should we pick — React, Vue, or Svelte — for this app? Show the scoring",
|
|
16
|
-
"should_trigger": true
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"query": "Write the business case for whether to invest in a data platform at all",
|
|
20
|
-
"should_trigger": false
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"query": "Record the decision to adopt Kafka as an architecture decision record",
|
|
24
|
-
"should_trigger": false
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"query": "Write a design doc proposing the new event-driven architecture for review",
|
|
28
|
-
"should_trigger": false
|
|
29
|
-
}
|
|
30
|
-
]
|