@patricio0312rev/skillset 0.1.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/LICENSE +21 -0
  3. package/README.md +176 -0
  4. package/bin/cli.js +37 -0
  5. package/package.json +55 -0
  6. package/src/commands/init.js +301 -0
  7. package/src/index.js +168 -0
  8. package/src/lib/config.js +200 -0
  9. package/src/lib/generator.js +166 -0
  10. package/src/utils/display.js +95 -0
  11. package/src/utils/readme.js +196 -0
  12. package/src/utils/tool-specific.js +233 -0
  13. package/templates/ai-engineering/agent-orchestration-planner/ SKILL.md +266 -0
  14. package/templates/ai-engineering/cost-latency-optimizer/ SKILL.md +270 -0
  15. package/templates/ai-engineering/doc-to-vector-dataset-generator/ SKILL.md +239 -0
  16. package/templates/ai-engineering/evaluation-harness/ SKILL.md +219 -0
  17. package/templates/ai-engineering/guardrails-safety-filter-builder/ SKILL.md +226 -0
  18. package/templates/ai-engineering/llm-debugger/ SKILL.md +283 -0
  19. package/templates/ai-engineering/prompt-regression-tester/ SKILL.md +216 -0
  20. package/templates/ai-engineering/prompt-template-builder/ SKILL.md +393 -0
  21. package/templates/ai-engineering/rag-pipeline-builder/ SKILL.md +244 -0
  22. package/templates/ai-engineering/tool-function-schema-designer/ SKILL.md +219 -0
  23. package/templates/architecture/adr-writer/ SKILL.md +250 -0
  24. package/templates/architecture/api-versioning-deprecation-planner/ SKILL.md +331 -0
  25. package/templates/architecture/domain-model-boundaries-mapper/ SKILL.md +300 -0
  26. package/templates/architecture/migration-planner/ SKILL.md +376 -0
  27. package/templates/architecture/performance-budget-setter/ SKILL.md +318 -0
  28. package/templates/architecture/reliability-strategy-builder/ SKILL.md +286 -0
  29. package/templates/architecture/rfc-generator/ SKILL.md +362 -0
  30. package/templates/architecture/scalability-playbook/ SKILL.md +279 -0
  31. package/templates/architecture/system-design-generator/ SKILL.md +339 -0
  32. package/templates/architecture/tech-debt-prioritizer/ SKILL.md +329 -0
  33. package/templates/backend/api-contract-normalizer/ SKILL.md +487 -0
  34. package/templates/backend/api-endpoint-generator/ SKILL.md +415 -0
  35. package/templates/backend/auth-module-builder/ SKILL.md +99 -0
  36. package/templates/backend/background-jobs-designer/ SKILL.md +166 -0
  37. package/templates/backend/caching-strategist/ SKILL.md +190 -0
  38. package/templates/backend/error-handling-standardizer/ SKILL.md +174 -0
  39. package/templates/backend/rate-limiting-abuse-protection/ SKILL.md +147 -0
  40. package/templates/backend/rbac-permissions-builder/ SKILL.md +158 -0
  41. package/templates/backend/service-layer-extractor/ SKILL.md +269 -0
  42. package/templates/backend/webhook-receiver-hardener/ SKILL.md +211 -0
  43. package/templates/ci-cd/artifact-sbom-publisher/ SKILL.md +236 -0
  44. package/templates/ci-cd/caching-strategy-optimizer/ SKILL.md +195 -0
  45. package/templates/ci-cd/deployment-checklist-generator/ SKILL.md +381 -0
  46. package/templates/ci-cd/github-actions-pipeline-creator/ SKILL.md +348 -0
  47. package/templates/ci-cd/monorepo-ci-optimizer/ SKILL.md +298 -0
  48. package/templates/ci-cd/preview-environments-builder/ SKILL.md +187 -0
  49. package/templates/ci-cd/quality-gates-enforcer/ SKILL.md +342 -0
  50. package/templates/ci-cd/release-automation-builder/ SKILL.md +281 -0
  51. package/templates/ci-cd/rollback-workflow-builder/ SKILL.md +372 -0
  52. package/templates/ci-cd/secrets-env-manager/ SKILL.md +242 -0
  53. package/templates/db-management/backup-restore-runbook-generator/ SKILL.md +505 -0
  54. package/templates/db-management/data-integrity-auditor/ SKILL.md +505 -0
  55. package/templates/db-management/data-retention-archiving-planner/ SKILL.md +430 -0
  56. package/templates/db-management/data-seeding-fixtures-builder/ SKILL.md +375 -0
  57. package/templates/db-management/db-performance-watchlist/ SKILL.md +425 -0
  58. package/templates/db-management/etl-sync-job-builder/ SKILL.md +457 -0
  59. package/templates/db-management/multi-tenant-safety-checker/ SKILL.md +398 -0
  60. package/templates/db-management/prisma-migration-assistant/ SKILL.md +379 -0
  61. package/templates/db-management/schema-consistency-checker/ SKILL.md +440 -0
  62. package/templates/db-management/sql-query-optimizer/ SKILL.md +324 -0
  63. package/templates/foundation/changelog-writer/ SKILL.md +431 -0
  64. package/templates/foundation/code-formatter-installer/ SKILL.md +320 -0
  65. package/templates/foundation/codebase-summarizer/ SKILL.md +360 -0
  66. package/templates/foundation/dependency-doctor/ SKILL.md +163 -0
  67. package/templates/foundation/dev-environment-bootstrapper/ SKILL.md +259 -0
  68. package/templates/foundation/dev-onboarding-builder/ SKILL.md +556 -0
  69. package/templates/foundation/docs-starter-kit/ SKILL.md +574 -0
  70. package/templates/foundation/explaining-code/SKILL.md +13 -0
  71. package/templates/foundation/git-hygiene-enforcer/ SKILL.md +455 -0
  72. package/templates/foundation/project-scaffolder/ SKILL.md +65 -0
  73. package/templates/foundation/project-scaffolder/references/templates.md +126 -0
  74. package/templates/foundation/repo-structure-linter/ SKILL.md +0 -0
  75. package/templates/foundation/repo-structure-linter/references/conventions.md +98 -0
  76. package/templates/frontend/animation-micro-interaction-pack/ SKILL.md +41 -0
  77. package/templates/frontend/component-scaffold-generator/ SKILL.md +562 -0
  78. package/templates/frontend/design-to-component-translator/ SKILL.md +547 -0
  79. package/templates/frontend/form-wizard-builder/ SKILL.md +553 -0
  80. package/templates/frontend/frontend-refactor-planner/ SKILL.md +37 -0
  81. package/templates/frontend/i18n-frontend-implementer/ SKILL.md +44 -0
  82. package/templates/frontend/modal-drawer-system/ SKILL.md +377 -0
  83. package/templates/frontend/page-layout-builder/ SKILL.md +630 -0
  84. package/templates/frontend/state-ux-flow-builder/ SKILL.md +23 -0
  85. package/templates/frontend/table-builder/ SKILL.md +350 -0
  86. package/templates/performance/alerting-dashboard-builder/ SKILL.md +162 -0
  87. package/templates/performance/backend-latency-profiler-helper/ SKILL.md +108 -0
  88. package/templates/performance/caching-cdn-strategy-planner/ SKILL.md +150 -0
  89. package/templates/performance/capacity-planning-helper/ SKILL.md +242 -0
  90. package/templates/performance/core-web-vitals-tuner/ SKILL.md +126 -0
  91. package/templates/performance/incident-runbook-generator/ SKILL.md +162 -0
  92. package/templates/performance/load-test-scenario-builder/ SKILL.md +256 -0
  93. package/templates/performance/observability-setup/ SKILL.md +232 -0
  94. package/templates/performance/postmortem-writer/ SKILL.md +203 -0
  95. package/templates/performance/structured-logging-standardizer/ SKILL.md +122 -0
  96. package/templates/security/auth-security-reviewer/ SKILL.md +428 -0
  97. package/templates/security/dependency-vulnerability-triage/ SKILL.md +495 -0
  98. package/templates/security/input-validation-sanitization-auditor/ SKILL.md +76 -0
  99. package/templates/security/pii-redaction-logging-policy-builder/ SKILL.md +65 -0
  100. package/templates/security/rbac-policy-tester/ SKILL.md +80 -0
  101. package/templates/security/secrets-scanner/ SKILL.md +462 -0
  102. package/templates/security/secure-headers-csp-builder/ SKILL.md +404 -0
  103. package/templates/security/security-incident-playbook-generator/ SKILL.md +76 -0
  104. package/templates/security/security-pr-checklist-skill/ SKILL.md +62 -0
  105. package/templates/security/threat-model-generator/ SKILL.md +394 -0
  106. package/templates/testing/contract-testing-builder/ SKILL.md +492 -0
  107. package/templates/testing/coverage-strategist/ SKILL.md +436 -0
  108. package/templates/testing/e2e-test-builder/ SKILL.md +382 -0
  109. package/templates/testing/flaky-test-detective/ SKILL.md +416 -0
  110. package/templates/testing/integration-test-builder/ SKILL.md +525 -0
  111. package/templates/testing/mocking-assistant/ SKILL.md +383 -0
  112. package/templates/testing/snapshot-test-refactorer/ SKILL.md +375 -0
  113. package/templates/testing/test-data-factory-builder/ SKILL.md +449 -0
  114. package/templates/testing/test-reporting-triage-skill/ SKILL.md +469 -0
  115. package/templates/testing/unit-test-generator/ SKILL.md +548 -0
@@ -0,0 +1,505 @@
1
+ ---
2
+ name: data-integrity-auditor
3
+ description: Detects data integrity issues including orphaned records, broken foreign key relationships, constraint violations, and provides automated fix migrations. Use for "data integrity", "orphaned records", "broken relationships", or "data quality".
4
+ ---
5
+
6
+ # Data Integrity Auditor
7
+
8
+ Detect and fix data integrity issues automatically.
9
+
10
+ ## Integrity Check Types
11
+
12
+ ### 1. Orphaned Records
13
+
14
+ ```sql
15
+ -- Find orphaned orders (no matching user)
16
+ SELECT o.id, o.user_id
17
+ FROM orders o
18
+ LEFT JOIN users u ON u.id = o.user_id
19
+ WHERE u.id IS NULL;
20
+
21
+ -- Find orphaned order items (no matching order)
22
+ SELECT oi.id, oi.order_id
23
+ FROM order_items oi
24
+ LEFT JOIN orders o ON o.id = oi.order_id
25
+ WHERE o.id IS NULL;
26
+ ```
27
+
28
+ ### 2. Broken Foreign Keys
29
+
30
+ ```typescript
31
+ // scripts/check-foreign-keys.ts
32
+ async function checkForeignKeys() {
33
+ const issues: string[] = [];
34
+
35
+ // Orders → Users
36
+ const orphanedOrders = await prisma.$queryRaw<any[]>`
37
+ SELECT o.id, o.user_id
38
+ FROM orders o
39
+ LEFT JOIN users u ON u.id = o.user_id
40
+ WHERE u.id IS NULL
41
+ LIMIT 100
42
+ `;
43
+
44
+ if (orphanedOrders.length > 0) {
45
+ issues.push(
46
+ `❌ Found ${orphanedOrders.length} orders with invalid user_id`
47
+ );
48
+ console.log(
49
+ " Sample IDs:",
50
+ orphanedOrders.slice(0, 5).map((o) => o.id)
51
+ );
52
+ }
53
+
54
+ // Order Items → Orders
55
+ const orphanedItems = await prisma.$queryRaw<any[]>`
56
+ SELECT oi.id, oi.order_id
57
+ FROM order_items oi
58
+ LEFT JOIN orders o ON o.id = oi.order_id
59
+ WHERE o.id IS NULL
60
+ LIMIT 100
61
+ `;
62
+
63
+ if (orphanedItems.length > 0) {
64
+ issues.push(
65
+ `❌ Found ${orphanedItems.length} order items with invalid order_id`
66
+ );
67
+ }
68
+
69
+ // Products → Categories
70
+ const orphanedProducts = await prisma.$queryRaw<any[]>`
71
+ SELECT p.id, p.category_id
72
+ FROM products p
73
+ LEFT JOIN categories c ON c.id = p.category_id
74
+ WHERE p.category_id IS NOT NULL
75
+ AND c.id IS NULL
76
+ LIMIT 100
77
+ `;
78
+
79
+ if (orphanedProducts.length > 0) {
80
+ issues.push(
81
+ `❌ Found ${orphanedProducts.length} products with invalid category_id`
82
+ );
83
+ }
84
+
85
+ return issues;
86
+ }
87
+ ```
88
+
89
+ ### 3. Constraint Violations
90
+
91
+ ```typescript
92
+ async function checkConstraints() {
93
+ const issues: string[] = [];
94
+
95
+ // Check email uniqueness (should be caught by DB, but verify)
96
+ const duplicateEmails = await prisma.$queryRaw<any[]>`
97
+ SELECT email, COUNT(*) as count
98
+ FROM users
99
+ GROUP BY email
100
+ HAVING COUNT(*) > 1
101
+ `;
102
+
103
+ if (duplicateEmails.length > 0) {
104
+ issues.push(`❌ Found ${duplicateEmails.length} duplicate emails`);
105
+ }
106
+
107
+ // Check negative quantities
108
+ const negativeStock = await prisma.$queryRaw<any[]>`
109
+ SELECT id, name, stock
110
+ FROM products
111
+ WHERE stock < 0
112
+ `;
113
+
114
+ if (negativeStock.length > 0) {
115
+ issues.push(
116
+ `❌ Found ${negativeStock.length} products with negative stock`
117
+ );
118
+ }
119
+
120
+ // Check negative prices
121
+ const negativePrices = await prisma.$queryRaw<any[]>`
122
+ SELECT id, name, price
123
+ FROM products
124
+ WHERE price < 0
125
+ `;
126
+
127
+ if (negativePrices.length > 0) {
128
+ issues.push(
129
+ `❌ Found ${negativePrices.length} products with negative prices`
130
+ );
131
+ }
132
+
133
+ // Check invalid order status
134
+ const invalidStatus = await prisma.$queryRaw<any[]>`
135
+ SELECT id, status
136
+ FROM orders
137
+ WHERE status NOT IN ('pending', 'paid', 'shipped', 'delivered', 'cancelled')
138
+ `;
139
+
140
+ if (invalidStatus.length > 0) {
141
+ issues.push(`❌ Found ${invalidStatus.length} orders with invalid status`);
142
+ }
143
+
144
+ return issues;
145
+ }
146
+ ```
147
+
148
+ ### 4. Missing Required Fields
149
+
150
+ ```typescript
151
+ async function checkMissingFields() {
152
+ const issues: string[] = [];
153
+
154
+ // Users missing required fields
155
+ const usersNoEmail = await prisma.user.count({
156
+ where: { email: null },
157
+ });
158
+
159
+ if (usersNoEmail > 0) {
160
+ issues.push(`❌ Found ${usersNoEmail} users without email`);
161
+ }
162
+
163
+ // Orders with NULL totals
164
+ const ordersNoTotal = await prisma.order.count({
165
+ where: { total: null },
166
+ });
167
+
168
+ if (ordersNoTotal > 0) {
169
+ issues.push(`❌ Found ${ordersNoTotal} orders without total`);
170
+ }
171
+
172
+ return issues;
173
+ }
174
+ ```
175
+
176
+ ## Comprehensive Audit Script
177
+
178
+ ```typescript
179
+ // scripts/audit-data-integrity.ts
180
+ interface IntegrityIssue {
181
+ severity: "critical" | "warning" | "info";
182
+ category: string;
183
+ message: string;
184
+ count: number;
185
+ query?: string;
186
+ fix?: string;
187
+ }
188
+
189
+ async function auditDataIntegrity(): Promise<IntegrityIssue[]> {
190
+ const issues: IntegrityIssue[] = [];
191
+
192
+ console.log("🔍 Auditing data integrity...\n");
193
+
194
+ // 1. Check orphaned records
195
+ const orphanedOrders = await prisma.$queryRaw<any[]>`
196
+ SELECT COUNT(*) as count FROM orders o
197
+ LEFT JOIN users u ON u.id = o.user_id
198
+ WHERE u.id IS NULL
199
+ `;
200
+
201
+ if (orphanedOrders[0].count > 0) {
202
+ issues.push({
203
+ severity: "critical",
204
+ category: "orphaned-records",
205
+ message: "Orders with invalid user references",
206
+ count: orphanedOrders[0].count,
207
+ query:
208
+ "SELECT id, user_id FROM orders o LEFT JOIN users u ON u.id = o.user_id WHERE u.id IS NULL",
209
+ fix: "DELETE FROM orders WHERE id IN (...)",
210
+ });
211
+ }
212
+
213
+ // 2. Check duplicate unique constraints
214
+ const duplicateEmails = await prisma.$queryRaw<any[]>`
215
+ SELECT email, COUNT(*) as count
216
+ FROM users
217
+ GROUP BY email
218
+ HAVING COUNT(*) > 1
219
+ `;
220
+
221
+ if (duplicateEmails.length > 0) {
222
+ issues.push({
223
+ severity: "critical",
224
+ category: "constraint-violation",
225
+ message: "Duplicate email addresses",
226
+ count: duplicateEmails.length,
227
+ fix: "Keep newest record, delete duplicates",
228
+ });
229
+ }
230
+
231
+ // 3. Check data inconsistencies
232
+ const invalidPrices = await prisma.$queryRaw<any[]>`
233
+ SELECT COUNT(*) as count FROM products WHERE price < 0
234
+ `;
235
+
236
+ if (invalidPrices[0].count > 0) {
237
+ issues.push({
238
+ severity: "warning",
239
+ category: "data-quality",
240
+ message: "Products with negative prices",
241
+ count: invalidPrices[0].count,
242
+ fix: "UPDATE products SET price = ABS(price) WHERE price < 0",
243
+ });
244
+ }
245
+
246
+ // 4. Check referential integrity
247
+ const brokenOrderItems = await prisma.$queryRaw<any[]>`
248
+ SELECT COUNT(*) as count FROM order_items oi
249
+ LEFT JOIN orders o ON o.id = oi.order_id
250
+ WHERE o.id IS NULL
251
+ `;
252
+
253
+ if (brokenOrderItems[0].count > 0) {
254
+ issues.push({
255
+ severity: "critical",
256
+ category: "referential-integrity",
257
+ message: "Order items referencing non-existent orders",
258
+ count: brokenOrderItems[0].count,
259
+ fix: "DELETE FROM order_items WHERE order_id NOT IN (SELECT id FROM orders)",
260
+ });
261
+ }
262
+
263
+ return issues;
264
+ }
265
+
266
+ async function generateReport() {
267
+ const issues = await auditDataIntegrity();
268
+
269
+ console.log("\n📊 Data Integrity Report\n");
270
+ console.log(`Total issues: ${issues.length}\n`);
271
+
272
+ const grouped = issues.reduce((acc, issue) => {
273
+ if (!acc[issue.severity]) acc[issue.severity] = [];
274
+ acc[issue.severity].push(issue);
275
+ return acc;
276
+ }, {} as Record<string, IntegrityIssue[]>);
277
+
278
+ (["critical", "warning", "info"] as const).forEach((severity) => {
279
+ const items = grouped[severity] || [];
280
+ if (items.length === 0) return;
281
+
282
+ console.log(`\n${severity.toUpperCase()} (${items.length})\n`);
283
+
284
+ items.forEach((issue, i) => {
285
+ console.log(`${i + 1}. [${issue.category}] ${issue.message}`);
286
+ console.log(` Count: ${issue.count}`);
287
+ if (issue.query) {
288
+ console.log(` Query: ${issue.query.substring(0, 80)}...`);
289
+ }
290
+ if (issue.fix) {
291
+ console.log(` Fix: ${issue.fix}`);
292
+ }
293
+ console.log();
294
+ });
295
+ });
296
+
297
+ // Exit with error if critical issues
298
+ process.exit(grouped.critical?.length > 0 ? 1 : 0);
299
+ }
300
+
301
+ generateReport();
302
+ ```
303
+
304
+ ## Automated Fixes
305
+
306
+ ```typescript
307
+ // scripts/fix-integrity-issues.ts
308
+ async function fixOrphanedRecords() {
309
+ console.log("🔧 Fixing orphaned records...\n");
310
+
311
+ // Delete orphaned orders
312
+ const deletedOrders = await prisma.$executeRaw`
313
+ DELETE FROM orders
314
+ WHERE id IN (
315
+ SELECT o.id FROM orders o
316
+ LEFT JOIN users u ON u.id = o.user_id
317
+ WHERE u.id IS NULL
318
+ )
319
+ `;
320
+ console.log(`✅ Deleted ${deletedOrders} orphaned orders`);
321
+
322
+ // Delete orphaned order items
323
+ const deletedItems = await prisma.$executeRaw`
324
+ DELETE FROM order_items
325
+ WHERE id IN (
326
+ SELECT oi.id FROM order_items oi
327
+ LEFT JOIN orders o ON o.id = oi.order_id
328
+ WHERE o.id IS NULL
329
+ )
330
+ `;
331
+ console.log(`✅ Deleted ${deletedItems} orphaned order items`);
332
+ }
333
+
334
+ async function fixDuplicates() {
335
+ console.log("🔧 Fixing duplicate records...\n");
336
+
337
+ // Keep newest user, delete old duplicates
338
+ await prisma.$executeRaw`
339
+ DELETE FROM users
340
+ WHERE id IN (
341
+ SELECT id FROM (
342
+ SELECT id,
343
+ ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at DESC) as rn
344
+ FROM users
345
+ ) t
346
+ WHERE rn > 1
347
+ )
348
+ `;
349
+ console.log(`✅ Fixed duplicate emails`);
350
+ }
351
+
352
+ async function fixConstraintViolations() {
353
+ console.log("🔧 Fixing constraint violations...\n");
354
+
355
+ // Fix negative prices
356
+ const fixedPrices = await prisma.$executeRaw`
357
+ UPDATE products
358
+ SET price = ABS(price)
359
+ WHERE price < 0
360
+ `;
361
+ console.log(`✅ Fixed ${fixedPrices} negative prices`);
362
+
363
+ // Fix negative stock
364
+ const fixedStock = await prisma.$executeRaw`
365
+ UPDATE products
366
+ SET stock = 0
367
+ WHERE stock < 0
368
+ `;
369
+ console.log(`✅ Fixed ${fixedStock} negative stock values`);
370
+ }
371
+ ```
372
+
373
+ ## Prevention: Add Missing Constraints
374
+
375
+ ```sql
376
+ -- Migration to add missing constraints
377
+
378
+ -- 1. Add foreign key constraints
379
+ ALTER TABLE orders
380
+ ADD CONSTRAINT fk_orders_user_id
381
+ FOREIGN KEY (user_id) REFERENCES users(id)
382
+ ON DELETE CASCADE;
383
+
384
+ ALTER TABLE order_items
385
+ ADD CONSTRAINT fk_order_items_order_id
386
+ FOREIGN KEY (order_id) REFERENCES orders(id)
387
+ ON DELETE CASCADE;
388
+
389
+ -- 2. Add check constraints
390
+ ALTER TABLE products
391
+ ADD CONSTRAINT chk_products_price_positive
392
+ CHECK (price >= 0);
393
+
394
+ ALTER TABLE products
395
+ ADD CONSTRAINT chk_products_stock_non_negative
396
+ CHECK (stock >= 0);
397
+
398
+ -- 3. Add unique constraints
399
+ CREATE UNIQUE INDEX idx_users_email_unique
400
+ ON users(LOWER(email));
401
+
402
+ -- 4. Add NOT NULL constraints
403
+ ALTER TABLE users
404
+ ALTER COLUMN email SET NOT NULL;
405
+
406
+ ALTER TABLE orders
407
+ ALTER COLUMN total SET NOT NULL;
408
+ ```
409
+
410
+ ## Automated Testing
411
+
412
+ ```typescript
413
+ // tests/data-integrity.test.ts
414
+ describe("Data Integrity", () => {
415
+ it("should not allow orphaned orders", async () => {
416
+ // Try to create order with non-existent user
417
+ await expect(
418
+ prisma.order.create({
419
+ data: {
420
+ userId: 99999, // Non-existent
421
+ total: 100,
422
+ status: "pending",
423
+ },
424
+ })
425
+ ).rejects.toThrow("Foreign key constraint");
426
+ });
427
+
428
+ it("should not allow negative prices", async () => {
429
+ await expect(
430
+ prisma.product.create({
431
+ data: {
432
+ name: "Test",
433
+ price: -10, // Invalid
434
+ stock: 100,
435
+ },
436
+ })
437
+ ).rejects.toThrow("Check constraint");
438
+ });
439
+
440
+ it("should not allow duplicate emails", async () => {
441
+ await prisma.user.create({
442
+ data: { email: "test@example.com", name: "Test" },
443
+ });
444
+
445
+ await expect(
446
+ prisma.user.create({
447
+ data: { email: "test@example.com", name: "Test 2" },
448
+ })
449
+ ).rejects.toThrow("Unique constraint");
450
+ });
451
+ });
452
+ ```
453
+
454
+ ## Monitoring Dashboard
455
+
456
+ ```typescript
457
+ // Monitor data quality metrics
458
+ async function getDataQualityMetrics() {
459
+ return {
460
+ orphanedOrders: await prisma.$queryRaw`
461
+ SELECT COUNT(*) FROM orders o
462
+ LEFT JOIN users u ON u.id = o.user_id
463
+ WHERE u.id IS NULL
464
+ `,
465
+ duplicateEmails: await prisma.$queryRaw`
466
+ SELECT COUNT(*) FROM (
467
+ SELECT email FROM users GROUP BY email HAVING COUNT(*) > 1
468
+ ) t
469
+ `,
470
+ invalidPrices: await prisma.$queryRaw`
471
+ SELECT COUNT(*) FROM products WHERE price < 0
472
+ `,
473
+ missingData: await prisma.$queryRaw`
474
+ SELECT
475
+ SUM(CASE WHEN email IS NULL THEN 1 ELSE 0 END) as users_no_email,
476
+ SUM(CASE WHEN total IS NULL THEN 1 ELSE 0 END) as orders_no_total
477
+ FROM users
478
+ CROSS JOIN orders
479
+ `,
480
+ };
481
+ }
482
+ ```
483
+
484
+ ## Best Practices
485
+
486
+ 1. **Add constraints**: Prevent issues at database level
487
+ 2. **Regular audits**: Weekly integrity checks
488
+ 3. **Automated fixes**: Safe, reversible repairs
489
+ 4. **Monitor metrics**: Track data quality over time
490
+ 5. **Test constraints**: Ensure they work
491
+ 6. **Soft deletes**: Easier recovery
492
+ 7. **Backup before fixes**: Always
493
+
494
+ ## Output Checklist
495
+
496
+ - [ ] Orphaned record detection
497
+ - [ ] Foreign key integrity checks
498
+ - [ ] Constraint violation detection
499
+ - [ ] Missing field checks
500
+ - [ ] Automated audit script
501
+ - [ ] Fix scripts (with dry-run)
502
+ - [ ] Prevention migrations (add constraints)
503
+ - [ ] Automated tests
504
+ - [ ] Monitoring dashboard
505
+ - [ ] Regular audit schedule