tribunal-kit 2.4.6 → 3.0.0
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/.agent/agents/accessibility-reviewer.md +220 -134
- package/.agent/agents/ai-code-reviewer.md +233 -129
- package/.agent/agents/backend-specialist.md +238 -178
- package/.agent/agents/code-archaeologist.md +181 -119
- package/.agent/agents/database-architect.md +207 -164
- package/.agent/agents/debugger.md +218 -151
- package/.agent/agents/dependency-reviewer.md +136 -55
- package/.agent/agents/devops-engineer.md +238 -175
- package/.agent/agents/documentation-writer.md +221 -137
- package/.agent/agents/explorer-agent.md +180 -142
- package/.agent/agents/frontend-reviewer.md +194 -80
- package/.agent/agents/frontend-specialist.md +237 -188
- package/.agent/agents/game-developer.md +52 -184
- package/.agent/agents/logic-reviewer.md +149 -78
- package/.agent/agents/mobile-developer.md +223 -152
- package/.agent/agents/mobile-reviewer.md +195 -79
- package/.agent/agents/orchestrator.md +211 -170
- package/.agent/agents/penetration-tester.md +174 -131
- package/.agent/agents/performance-optimizer.md +203 -139
- package/.agent/agents/performance-reviewer.md +211 -108
- package/.agent/agents/product-manager.md +162 -108
- package/.agent/agents/project-planner.md +162 -142
- package/.agent/agents/qa-automation-engineer.md +242 -138
- package/.agent/agents/security-auditor.md +194 -170
- package/.agent/agents/seo-specialist.md +213 -132
- package/.agent/agents/sql-reviewer.md +194 -73
- package/.agent/agents/supervisor-agent.md +203 -156
- package/.agent/agents/test-coverage-reviewer.md +193 -81
- package/.agent/agents/type-safety-reviewer.md +208 -65
- package/.agent/scripts/__pycache__/auto_preview.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/bundle_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/checklist.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/dependency_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/session_manager.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/skill_integrator.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/swarm_dispatcher.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/verify_all.cpython-311.pyc +0 -0
- package/.agent/skills/agent-organizer/SKILL.md +126 -132
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +155 -66
- package/.agent/skills/api-patterns/SKILL.md +289 -257
- package/.agent/skills/api-security-auditor/SKILL.md +172 -70
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +1 -1
- package/.agent/skills/appflow-wireframe/SKILL.md +107 -100
- package/.agent/skills/architecture/SKILL.md +331 -200
- package/.agent/skills/authentication-best-practices/SKILL.md +168 -67
- package/.agent/skills/bash-linux/SKILL.md +154 -215
- package/.agent/skills/brainstorming/SKILL.md +104 -210
- package/.agent/skills/building-native-ui/SKILL.md +169 -70
- package/.agent/skills/clean-code/SKILL.md +360 -206
- package/.agent/skills/config-validator/SKILL.md +141 -165
- package/.agent/skills/csharp-developer/SKILL.md +528 -107
- package/.agent/skills/database-design/SKILL.md +455 -275
- package/.agent/skills/deployment-procedures/SKILL.md +145 -188
- package/.agent/skills/devops-engineer/SKILL.md +332 -134
- package/.agent/skills/devops-incident-responder/SKILL.md +113 -98
- package/.agent/skills/edge-computing/SKILL.md +157 -213
- package/.agent/skills/extract-design-system/SKILL.md +129 -69
- package/.agent/skills/framer-motion-expert/SKILL.md +939 -0
- package/.agent/skills/game-design-expert/SKILL.md +105 -0
- package/.agent/skills/game-engineering-expert/SKILL.md +122 -0
- package/.agent/skills/geo-fundamentals/SKILL.md +124 -215
- package/.agent/skills/github-operations/SKILL.md +314 -354
- package/.agent/skills/gsap-expert/SKILL.md +901 -0
- package/.agent/skills/i18n-localization/SKILL.md +138 -216
- package/.agent/skills/intelligent-routing/SKILL.md +127 -139
- package/.agent/skills/llm-engineering/SKILL.md +357 -258
- package/.agent/skills/local-first/SKILL.md +154 -203
- package/.agent/skills/mcp-builder/SKILL.md +118 -224
- package/.agent/skills/nextjs-react-expert/SKILL.md +783 -203
- package/.agent/skills/nodejs-best-practices/SKILL.md +559 -280
- package/.agent/skills/observability/SKILL.md +330 -285
- package/.agent/skills/parallel-agents/SKILL.md +122 -181
- package/.agent/skills/performance-profiling/SKILL.md +254 -197
- package/.agent/skills/plan-writing/SKILL.md +118 -188
- package/.agent/skills/platform-engineer/SKILL.md +123 -135
- package/.agent/skills/playwright-best-practices/SKILL.md +157 -76
- package/.agent/skills/powershell-windows/SKILL.md +146 -230
- package/.agent/skills/python-pro/SKILL.md +879 -114
- package/.agent/skills/react-specialist/SKILL.md +931 -108
- package/.agent/skills/realtime-patterns/SKILL.md +304 -296
- package/.agent/skills/rust-pro/SKILL.md +701 -240
- package/.agent/skills/seo-fundamentals/SKILL.md +154 -181
- package/.agent/skills/server-management/SKILL.md +190 -212
- package/.agent/skills/shadcn-ui-expert/SKILL.md +201 -68
- package/.agent/skills/sql-pro/SKILL.md +633 -104
- package/.agent/skills/swiftui-expert/SKILL.md +171 -70
- package/.agent/skills/systematic-debugging/SKILL.md +118 -186
- package/.agent/skills/tailwind-patterns/SKILL.md +576 -232
- package/.agent/skills/tdd-workflow/SKILL.md +137 -209
- package/.agent/skills/testing-patterns/SKILL.md +573 -205
- package/.agent/skills/vue-expert/SKILL.md +964 -119
- package/.agent/skills/vulnerability-scanner/SKILL.md +269 -316
- package/.agent/skills/web-accessibility-auditor/SKILL.md +188 -71
- package/.agent/skills/webapp-testing/SKILL.md +145 -236
- package/.agent/workflows/api-tester.md +151 -279
- package/.agent/workflows/audit.md +138 -168
- package/.agent/workflows/brainstorm.md +110 -146
- package/.agent/workflows/changelog.md +112 -144
- package/.agent/workflows/create.md +124 -139
- package/.agent/workflows/debug.md +189 -196
- package/.agent/workflows/deploy.md +189 -153
- package/.agent/workflows/enhance.md +151 -139
- package/.agent/workflows/fix.md +135 -143
- package/.agent/workflows/generate.md +157 -164
- package/.agent/workflows/migrate.md +160 -163
- package/.agent/workflows/orchestrate.md +168 -151
- package/.agent/workflows/performance-benchmarker.md +123 -305
- package/.agent/workflows/plan.md +173 -151
- package/.agent/workflows/preview.md +80 -137
- package/.agent/workflows/refactor.md +183 -153
- package/.agent/workflows/review-ai.md +129 -140
- package/.agent/workflows/review.md +116 -155
- package/.agent/workflows/session.md +94 -154
- package/.agent/workflows/status.md +79 -125
- package/.agent/workflows/strengthen-skills.md +139 -99
- package/.agent/workflows/swarm.md +179 -194
- package/.agent/workflows/test.md +211 -166
- package/.agent/workflows/tribunal-backend.md +113 -111
- package/.agent/workflows/tribunal-database.md +115 -132
- package/.agent/workflows/tribunal-frontend.md +118 -115
- package/.agent/workflows/tribunal-full.md +133 -136
- package/.agent/workflows/tribunal-mobile.md +119 -123
- package/.agent/workflows/tribunal-performance.md +133 -152
- package/.agent/workflows/ui-ux-pro-max.md +143 -171
- package/README.md +11 -15
- package/package.json +1 -1
- package/.agent/skills/dotnet-core-expert/SKILL.md +0 -103
- package/.agent/skills/framer-motion-animations/SKILL.md +0 -74
- package/.agent/skills/game-development/2d-games/SKILL.md +0 -119
- package/.agent/skills/game-development/3d-games/SKILL.md +0 -135
- package/.agent/skills/game-development/SKILL.md +0 -236
- package/.agent/skills/game-development/game-art/SKILL.md +0 -185
- package/.agent/skills/game-development/game-audio/SKILL.md +0 -190
- package/.agent/skills/game-development/game-design/SKILL.md +0 -129
- package/.agent/skills/game-development/mobile-games/SKILL.md +0 -108
- package/.agent/skills/game-development/multiplayer/SKILL.md +0 -132
- package/.agent/skills/game-development/pc-games/SKILL.md +0 -144
- package/.agent/skills/game-development/vr-ar/SKILL.md +0 -123
- package/.agent/skills/game-development/web-games/SKILL.md +0 -150
|
@@ -1,275 +1,455 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: database-design
|
|
3
|
-
description: Database design
|
|
4
|
-
allowed-tools: Read, Write, Edit, Glob, Grep
|
|
5
|
-
version:
|
|
6
|
-
last-updated: 2026-
|
|
7
|
-
applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Database Design
|
|
11
|
-
|
|
12
|
-
> A schema is
|
|
13
|
-
> Design
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
--
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
--
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
--
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
--
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
1
|
+
---
|
|
2
|
+
name: database-design
|
|
3
|
+
description: Database design mastery. Schema design with normalization, denormalization strategies, indexing, migration pipelines, ORM selection (Prisma/Drizzle/SQLAlchemy/EF Core), connection pooling, soft deletes, audit trails, multi-tenancy, and serverless database patterns. Use when designing schemas, choosing databases, planning migrations, or architecting data layers.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep
|
|
5
|
+
version: 2.0.0
|
|
6
|
+
last-updated: 2026-04-01
|
|
7
|
+
applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Database Design — Schema & Architecture Mastery
|
|
11
|
+
|
|
12
|
+
> A schema is a contract. Every column name is an API. Every missing index is a production incident waiting to happen.
|
|
13
|
+
> Design for reads first. Normalize until it hurts, then denormalize until it works.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Database Selection Matrix
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
21
|
+
│ Which Database Do You Need? │
|
|
22
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
23
|
+
│ │
|
|
24
|
+
│ What's the primary access pattern? │
|
|
25
|
+
│ ├── Relational queries (JOINs, transactions, reports) │
|
|
26
|
+
│ │ ├── High consistency + complex queries → PostgreSQL │
|
|
27
|
+
│ │ ├── Simple CRUD + familiar → MySQL / MariaDB │
|
|
28
|
+
│ │ └── Embedded / edge / serverless → SQLite / Turso │
|
|
29
|
+
│ │ │
|
|
30
|
+
│ ├── Key-value lookups (cache, sessions, counters) │
|
|
31
|
+
│ │ ├── In-memory speed → Redis / Valkey │
|
|
32
|
+
│ │ └── Persistent KV → DynamoDB / Upstash │
|
|
33
|
+
│ │ │
|
|
34
|
+
│ ├── Document store (flexible schema, nested objects) │
|
|
35
|
+
│ │ └── MongoDB / Firestore │
|
|
36
|
+
│ │ │
|
|
37
|
+
│ ├── Full-text search │
|
|
38
|
+
│ │ ├── Built-in (good enough) → PostgreSQL tsvector │
|
|
39
|
+
│ │ └── Dedicated search → Elasticsearch / Meilisearch / Typesense│
|
|
40
|
+
│ │ │
|
|
41
|
+
│ ├── Time-series (metrics, IoT, logs) │
|
|
42
|
+
│ │ └── TimescaleDB (PostgreSQL ext) / ClickHouse / InfluxDB │
|
|
43
|
+
│ │ │
|
|
44
|
+
│ ├── Graph (relationships, social networks) │
|
|
45
|
+
│ │ └── Neo4j / Amazon Neptune │
|
|
46
|
+
│ │ │
|
|
47
|
+
│ └── Vector (AI embeddings, semantic search) │
|
|
48
|
+
│ └── pgvector (PostgreSQL ext) / Pinecone / Weaviate │
|
|
49
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Schema Design Patterns
|
|
55
|
+
|
|
56
|
+
### Naming Conventions
|
|
57
|
+
|
|
58
|
+
```sql
|
|
59
|
+
-- ✅ RULES:
|
|
60
|
+
-- Tables: plural, snake_case (users, order_items)
|
|
61
|
+
-- Columns: singular, snake_case (first_name, created_at)
|
|
62
|
+
-- Primary key: id (BIGINT or UUID)
|
|
63
|
+
-- Foreign key: {referenced_table_singular}_id (user_id, order_id)
|
|
64
|
+
-- Timestamps: created_at, updated_at (TIMESTAMPTZ, not TIMESTAMP)
|
|
65
|
+
-- Booleans: is_{adjective} or has_{noun} (is_active, has_paid)
|
|
66
|
+
-- Status/enum columns: status, role, type (not state, kind)
|
|
67
|
+
|
|
68
|
+
-- ❌ BAD naming:
|
|
69
|
+
-- tbl_Users, UserID, DateCreated, active, isdeleted, userId
|
|
70
|
+
-- ✅ GOOD naming:
|
|
71
|
+
-- users, id, created_at, is_active, is_deleted, user_id
|
|
72
|
+
|
|
73
|
+
-- ❌ HALLUCINATION TRAP: Always use TIMESTAMPTZ (with timezone), not TIMESTAMP
|
|
74
|
+
-- TIMESTAMP without timezone is ambiguous and causes bugs across timezones
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Standard Table Template
|
|
78
|
+
|
|
79
|
+
```sql
|
|
80
|
+
CREATE TABLE users (
|
|
81
|
+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
82
|
+
-- OR: id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
83
|
+
|
|
84
|
+
-- Core fields
|
|
85
|
+
email TEXT NOT NULL UNIQUE,
|
|
86
|
+
name TEXT NOT NULL,
|
|
87
|
+
role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('admin', 'user', 'moderator')),
|
|
88
|
+
|
|
89
|
+
-- Status fields
|
|
90
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
91
|
+
|
|
92
|
+
-- Metadata
|
|
93
|
+
metadata JSONB DEFAULT '{}',
|
|
94
|
+
|
|
95
|
+
-- Timestamps (ALWAYS include these)
|
|
96
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
97
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
-- Auto-update updated_at trigger
|
|
101
|
+
CREATE OR REPLACE FUNCTION update_updated_at()
|
|
102
|
+
RETURNS TRIGGER AS $$
|
|
103
|
+
BEGIN
|
|
104
|
+
NEW.updated_at = now();
|
|
105
|
+
RETURN NEW;
|
|
106
|
+
END;
|
|
107
|
+
$$ LANGUAGE plpgsql;
|
|
108
|
+
|
|
109
|
+
CREATE TRIGGER trg_users_updated_at
|
|
110
|
+
BEFORE UPDATE ON users
|
|
111
|
+
FOR EACH ROW
|
|
112
|
+
EXECUTE FUNCTION update_updated_at();
|
|
113
|
+
|
|
114
|
+
-- Essential indexes
|
|
115
|
+
CREATE INDEX idx_users_email ON users (email);
|
|
116
|
+
CREATE INDEX idx_users_role ON users (role) WHERE is_active = true;
|
|
117
|
+
CREATE INDEX idx_users_created_at ON users (created_at DESC);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### ID Strategy
|
|
121
|
+
|
|
122
|
+
```sql
|
|
123
|
+
-- Option 1: BIGINT auto-increment (recommended for most cases)
|
|
124
|
+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
|
|
125
|
+
-- Pros: compact, sortable, fast joins, natural ordering
|
|
126
|
+
-- Cons: exposes record count, sequential guessing
|
|
127
|
+
|
|
128
|
+
-- Option 2: UUID v7 (recommended for distributed systems)
|
|
129
|
+
id UUID DEFAULT gen_random_uuid() PRIMARY KEY
|
|
130
|
+
-- Pros: globally unique, no coordination needed, safe to expose
|
|
131
|
+
-- Cons: larger (16 bytes), slower joins, random order (use UUIDv7 for time-ordering)
|
|
132
|
+
|
|
133
|
+
-- Option 3: ULID / NanoID (application-generated)
|
|
134
|
+
-- Pros: sortable, URL-safe, customizable length
|
|
135
|
+
-- Cons: requires application logic, not DB-native
|
|
136
|
+
|
|
137
|
+
-- ❌ HALLUCINATION TRAP: UUID v4 is randomly ordered — kills index performance
|
|
138
|
+
-- ✅ Use UUID v7 (time-ordered) if you need UUIDs
|
|
139
|
+
-- UUID v7 has a timestamp prefix → sequential inserts → B-tree friendly
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Relationships
|
|
143
|
+
|
|
144
|
+
```sql
|
|
145
|
+
-- One-to-Many: foreign key on the "many" side
|
|
146
|
+
CREATE TABLE posts (
|
|
147
|
+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
148
|
+
author_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
149
|
+
title TEXT NOT NULL,
|
|
150
|
+
body TEXT NOT NULL,
|
|
151
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
152
|
+
);
|
|
153
|
+
CREATE INDEX idx_posts_author_id ON posts (author_id);
|
|
154
|
+
|
|
155
|
+
-- Many-to-Many: junction table
|
|
156
|
+
CREATE TABLE post_tags (
|
|
157
|
+
post_id BIGINT NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
|
|
158
|
+
tag_id BIGINT NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
159
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
160
|
+
PRIMARY KEY (post_id, tag_id)
|
|
161
|
+
);
|
|
162
|
+
CREATE INDEX idx_post_tags_tag_id ON post_tags (tag_id);
|
|
163
|
+
|
|
164
|
+
-- ❌ HALLUCINATION TRAP: Every foreign key column MUST have an index
|
|
165
|
+
-- Without it, cascading deletes on the parent do a full table scan on the child
|
|
166
|
+
-- PostgreSQL does NOT auto-index foreign keys (MySQL InnoDB does)
|
|
167
|
+
|
|
168
|
+
-- Self-referential (tree/hierarchy)
|
|
169
|
+
CREATE TABLE categories (
|
|
170
|
+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
171
|
+
parent_id BIGINT REFERENCES categories(id) ON DELETE SET NULL,
|
|
172
|
+
name TEXT NOT NULL,
|
|
173
|
+
depth INT NOT NULL DEFAULT 0
|
|
174
|
+
);
|
|
175
|
+
CREATE INDEX idx_categories_parent_id ON categories (parent_id);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Soft Deletes
|
|
181
|
+
|
|
182
|
+
```sql
|
|
183
|
+
-- Soft delete pattern
|
|
184
|
+
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMPTZ;
|
|
185
|
+
|
|
186
|
+
-- Partial index — queries against active records are fast
|
|
187
|
+
CREATE INDEX idx_users_active ON users (email) WHERE deleted_at IS NULL;
|
|
188
|
+
|
|
189
|
+
-- "Delete" = set timestamp
|
|
190
|
+
UPDATE users SET deleted_at = now() WHERE id = 42;
|
|
191
|
+
|
|
192
|
+
-- All queries must filter:
|
|
193
|
+
SELECT * FROM users WHERE deleted_at IS NULL;
|
|
194
|
+
|
|
195
|
+
-- OR: Use a view for convenience
|
|
196
|
+
CREATE VIEW active_users AS
|
|
197
|
+
SELECT * FROM users WHERE deleted_at IS NULL;
|
|
198
|
+
|
|
199
|
+
-- ❌ HALLUCINATION TRAP: Soft deletes add complexity to EVERY query
|
|
200
|
+
-- Every SELECT, JOIN, and COUNT must include WHERE deleted_at IS NULL
|
|
201
|
+
-- Consider using a view or audit_log table instead when possible
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Audit Trail
|
|
207
|
+
|
|
208
|
+
```sql
|
|
209
|
+
-- Append-only audit log
|
|
210
|
+
CREATE TABLE audit_log (
|
|
211
|
+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
212
|
+
table_name TEXT NOT NULL,
|
|
213
|
+
record_id BIGINT NOT NULL,
|
|
214
|
+
action TEXT NOT NULL CHECK (action IN ('INSERT', 'UPDATE', 'DELETE')),
|
|
215
|
+
old_data JSONB,
|
|
216
|
+
new_data JSONB,
|
|
217
|
+
changed_by BIGINT REFERENCES users(id),
|
|
218
|
+
changed_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
-- Partition by month for performance
|
|
222
|
+
-- CREATE TABLE audit_log (...) PARTITION BY RANGE (changed_at);
|
|
223
|
+
|
|
224
|
+
CREATE INDEX idx_audit_log_table_record ON audit_log (table_name, record_id);
|
|
225
|
+
CREATE INDEX idx_audit_log_changed_at ON audit_log USING brin (changed_at);
|
|
226
|
+
|
|
227
|
+
-- Auto-audit trigger
|
|
228
|
+
CREATE OR REPLACE FUNCTION audit_trigger()
|
|
229
|
+
RETURNS TRIGGER AS $$
|
|
230
|
+
BEGIN
|
|
231
|
+
INSERT INTO audit_log (table_name, record_id, action, old_data, new_data, changed_by)
|
|
232
|
+
VALUES (
|
|
233
|
+
TG_TABLE_NAME,
|
|
234
|
+
COALESCE(NEW.id, OLD.id),
|
|
235
|
+
TG_OP,
|
|
236
|
+
CASE WHEN TG_OP IN ('UPDATE', 'DELETE') THEN to_jsonb(OLD) END,
|
|
237
|
+
CASE WHEN TG_OP IN ('INSERT', 'UPDATE') THEN to_jsonb(NEW) END,
|
|
238
|
+
current_setting('app.current_user_id', true)::bigint
|
|
239
|
+
);
|
|
240
|
+
RETURN COALESCE(NEW, OLD);
|
|
241
|
+
END;
|
|
242
|
+
$$ LANGUAGE plpgsql;
|
|
243
|
+
|
|
244
|
+
CREATE TRIGGER trg_users_audit
|
|
245
|
+
AFTER INSERT OR UPDATE OR DELETE ON users
|
|
246
|
+
FOR EACH ROW EXECUTE FUNCTION audit_trigger();
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Multi-Tenancy Patterns
|
|
252
|
+
|
|
253
|
+
```sql
|
|
254
|
+
-- Pattern 1: Shared table with tenant_id (simplest, most common)
|
|
255
|
+
CREATE TABLE projects (
|
|
256
|
+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
257
|
+
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
|
|
258
|
+
name TEXT NOT NULL,
|
|
259
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
260
|
+
);
|
|
261
|
+
CREATE INDEX idx_projects_tenant ON projects (tenant_id, created_at DESC);
|
|
262
|
+
-- ‼️ Every query MUST include WHERE tenant_id = ? — enforce via RLS
|
|
263
|
+
|
|
264
|
+
-- Row Level Security (PostgreSQL)
|
|
265
|
+
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
|
|
266
|
+
|
|
267
|
+
CREATE POLICY tenant_isolation ON projects
|
|
268
|
+
USING (tenant_id = current_setting('app.current_tenant_id')::bigint);
|
|
269
|
+
|
|
270
|
+
-- Pattern 2: Schema per tenant (better isolation)
|
|
271
|
+
CREATE SCHEMA tenant_acme;
|
|
272
|
+
CREATE TABLE tenant_acme.projects (...);
|
|
273
|
+
|
|
274
|
+
-- Pattern 3: Database per tenant (maximum isolation, hardest to manage)
|
|
275
|
+
-- Only for compliance/regulatory requirements
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## ORM Selection
|
|
281
|
+
|
|
282
|
+
### Prisma (TypeScript/Node.js)
|
|
283
|
+
|
|
284
|
+
```prisma
|
|
285
|
+
// prisma/schema.prisma
|
|
286
|
+
generator client {
|
|
287
|
+
provider = "prisma-client-js"
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
datasource db {
|
|
291
|
+
provider = "postgresql"
|
|
292
|
+
url = env("DATABASE_URL")
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
model User {
|
|
296
|
+
id Int @id @default(autoincrement())
|
|
297
|
+
email String @unique
|
|
298
|
+
name String
|
|
299
|
+
posts Post[]
|
|
300
|
+
createdAt DateTime @default(now()) @map("created_at")
|
|
301
|
+
updatedAt DateTime @updatedAt @map("updated_at")
|
|
302
|
+
|
|
303
|
+
@@map("users")
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Usage:
|
|
309
|
+
const user = await prisma.user.findUnique({
|
|
310
|
+
where: { email: "alice@test.com" },
|
|
311
|
+
include: { posts: { take: 10, orderBy: { createdAt: "desc" } } },
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// ❌ HALLUCINATION TRAP: Prisma uses its own query engine
|
|
315
|
+
// It does NOT support raw SQL joins in the standard query API
|
|
316
|
+
// Use prisma.$queryRaw for complex queries Prisma can't express
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Drizzle (TypeScript — SQL-First)
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
import { pgTable, serial, text, timestamp, integer } from "drizzle-orm/pg-core";
|
|
323
|
+
import { eq, desc, and } from "drizzle-orm";
|
|
324
|
+
|
|
325
|
+
export const users = pgTable("users", {
|
|
326
|
+
id: serial("id").primaryKey(),
|
|
327
|
+
email: text("email").notNull().unique(),
|
|
328
|
+
name: text("name").notNull(),
|
|
329
|
+
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Query (SQL-like, type-safe)
|
|
333
|
+
const result = await db
|
|
334
|
+
.select({ id: users.id, name: users.name })
|
|
335
|
+
.from(users)
|
|
336
|
+
.where(and(eq(users.role, "admin"), eq(users.isActive, true)))
|
|
337
|
+
.orderBy(desc(users.createdAt))
|
|
338
|
+
.limit(20);
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Migration Best Practices
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
Migration Rules:
|
|
347
|
+
1. Every migration must be REVERSIBLE (include down/rollback)
|
|
348
|
+
2. Never modify a migration that's been applied to production
|
|
349
|
+
3. Use explicit column types — never rely on ORM defaults
|
|
350
|
+
4. Add indexes in the SAME migration as the column
|
|
351
|
+
5. Large table migrations: add column as NULLABLE first, backfill, then add NOT NULL
|
|
352
|
+
6. Test migrations against a COPY of production data size
|
|
353
|
+
7. Never DROP a column — first remove all code references, deploy, then drop
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
```sql
|
|
357
|
+
-- Safe column addition (zero-downtime deploy)
|
|
358
|
+
-- Step 1: Add nullable column
|
|
359
|
+
ALTER TABLE users ADD COLUMN phone TEXT;
|
|
360
|
+
|
|
361
|
+
-- Step 2: Backfill (in batches to avoid locking)
|
|
362
|
+
UPDATE users SET phone = '' WHERE phone IS NULL AND id BETWEEN 1 AND 10000;
|
|
363
|
+
UPDATE users SET phone = '' WHERE phone IS NULL AND id BETWEEN 10001 AND 20000;
|
|
364
|
+
|
|
365
|
+
-- Step 3: Add constraint (after deploy confirms all code writes phone)
|
|
366
|
+
ALTER TABLE users ALTER COLUMN phone SET NOT NULL;
|
|
367
|
+
ALTER TABLE users ALTER COLUMN phone SET DEFAULT '';
|
|
368
|
+
|
|
369
|
+
-- ❌ HALLUCINATION TRAP: Adding NOT NULL without a default locks the ENTIRE table
|
|
370
|
+
-- On large tables this can cause downtime. Always add as nullable first.
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Connection Pooling
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
Application → Connection Pool → Database
|
|
379
|
+
|
|
380
|
+
Without pooling: 100 requests = 100 DB connections → DB overwhelmed
|
|
381
|
+
With pooling: 100 requests = 10-20 reused connections → DB happy
|
|
382
|
+
|
|
383
|
+
Common poolers:
|
|
384
|
+
- PgBouncer (external, most common for PostgreSQL)
|
|
385
|
+
- Prisma Accelerate (managed, for Prisma)
|
|
386
|
+
- Supabase Supavisor (managed, for Supabase)
|
|
387
|
+
- Application-level (SQLAlchemy pool, Drizzle pool)
|
|
388
|
+
|
|
389
|
+
Sizing formula:
|
|
390
|
+
max_connections = (num_cpu_cores * 2) + num_disk_spindles
|
|
391
|
+
Typical: 25-50 connections for most applications
|
|
392
|
+
|
|
393
|
+
❌ HALLUCINATION TRAP: Serverless functions need EXTERNAL pooling
|
|
394
|
+
Each Lambda/Vercel invocation opens a new connection
|
|
395
|
+
Without PgBouncer/Supavisor, you hit max_connections instantly
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## Output Format
|
|
401
|
+
|
|
402
|
+
```
|
|
403
|
+
━━━ Database Design Report ━━━━━━━━━━━━━━━━━━━━━━━
|
|
404
|
+
Skill: Database Design
|
|
405
|
+
Database: [PostgreSQL/MySQL/SQLite/etc.]
|
|
406
|
+
Scope: [N tables · N migrations]
|
|
407
|
+
─────────────────────────────────────────────────
|
|
408
|
+
✅ Passed: [checks that passed, or "All clean"]
|
|
409
|
+
⚠️ Warnings: [non-blocking issues, or "None"]
|
|
410
|
+
❌ Blocked: [blocking issues requiring fix, or "None"]
|
|
411
|
+
─────────────────────────────────────────────────
|
|
412
|
+
VBC status: PENDING → VERIFIED
|
|
413
|
+
Evidence: [migration success / schema validation]
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## 🤖 LLM-Specific Traps
|
|
419
|
+
|
|
420
|
+
1. **TIMESTAMP vs TIMESTAMPTZ:** Always use TIMESTAMPTZ (with timezone). TIMESTAMP without timezone is ambiguous.
|
|
421
|
+
2. **UUID v4 for Primary Keys:** UUID v4 is randomly ordered — destroys B-tree index performance. Use UUID v7 or BIGINT.
|
|
422
|
+
3. **Missing FK Indexes:** PostgreSQL does NOT auto-create indexes on foreign key columns. Always add them manually.
|
|
423
|
+
4. **NOT NULL on Large Tables:** Adding NOT NULL to an existing column on a large table locks the entire table. Add as nullable first.
|
|
424
|
+
5. **`SELECT *` in Application Code:** Always specify columns. Schema changes + `SELECT *` = broken application.
|
|
425
|
+
6. **Shared Mutable State Without RLS:** Multi-tenant tables without Row Level Security = data leaks between tenants.
|
|
426
|
+
7. **Hardcoded Connection Strings:** Database URLs must come from environment variables, never code.
|
|
427
|
+
8. **Direct Production Writes:** Never run unreviewed SQL against production. Use migrations and review processes.
|
|
428
|
+
9. **Ignoring Query Plans:** Design decisions without EXPLAIN ANALYZE evidence are guesses.
|
|
429
|
+
10. **Serverless Without Pooling:** Every serverless invocation opens a new connection. Always use an external connection pooler.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## 🏛️ Tribunal Integration
|
|
434
|
+
|
|
435
|
+
**Slash command: `/tribunal-database`**
|
|
436
|
+
|
|
437
|
+
### ✅ Pre-Flight Self-Audit
|
|
438
|
+
|
|
439
|
+
```
|
|
440
|
+
✅ Did I use TIMESTAMPTZ (not TIMESTAMP)?
|
|
441
|
+
✅ Did I add indexes for all foreign keys?
|
|
442
|
+
✅ Did I use BIGINT or UUID v7 for primary keys?
|
|
443
|
+
✅ Are all table/column names snake_case?
|
|
444
|
+
✅ Do all tables have created_at and updated_at?
|
|
445
|
+
✅ Is the migration reversible?
|
|
446
|
+
✅ Did I use parameterized queries (not string interpolation)?
|
|
447
|
+
✅ Is connection pooling configured for serverless?
|
|
448
|
+
✅ Is multi-tenant data isolated (RLS or schema)?
|
|
449
|
+
✅ Did I run EXPLAIN ANALYZE on critical queries?
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### 🛑 VBC Protocol
|
|
453
|
+
|
|
454
|
+
- ❌ **Forbidden:** Declaring a schema "optimized" without migration + EXPLAIN evidence.
|
|
455
|
+
- ✅ **Required:** Provide migration success logs or schema validation output.
|