@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.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/bin/cli.js +37 -0
- package/package.json +55 -0
- package/src/commands/init.js +301 -0
- package/src/index.js +168 -0
- package/src/lib/config.js +200 -0
- package/src/lib/generator.js +166 -0
- package/src/utils/display.js +95 -0
- package/src/utils/readme.js +196 -0
- package/src/utils/tool-specific.js +233 -0
- package/templates/ai-engineering/agent-orchestration-planner/ SKILL.md +266 -0
- package/templates/ai-engineering/cost-latency-optimizer/ SKILL.md +270 -0
- package/templates/ai-engineering/doc-to-vector-dataset-generator/ SKILL.md +239 -0
- package/templates/ai-engineering/evaluation-harness/ SKILL.md +219 -0
- package/templates/ai-engineering/guardrails-safety-filter-builder/ SKILL.md +226 -0
- package/templates/ai-engineering/llm-debugger/ SKILL.md +283 -0
- package/templates/ai-engineering/prompt-regression-tester/ SKILL.md +216 -0
- package/templates/ai-engineering/prompt-template-builder/ SKILL.md +393 -0
- package/templates/ai-engineering/rag-pipeline-builder/ SKILL.md +244 -0
- package/templates/ai-engineering/tool-function-schema-designer/ SKILL.md +219 -0
- package/templates/architecture/adr-writer/ SKILL.md +250 -0
- package/templates/architecture/api-versioning-deprecation-planner/ SKILL.md +331 -0
- package/templates/architecture/domain-model-boundaries-mapper/ SKILL.md +300 -0
- package/templates/architecture/migration-planner/ SKILL.md +376 -0
- package/templates/architecture/performance-budget-setter/ SKILL.md +318 -0
- package/templates/architecture/reliability-strategy-builder/ SKILL.md +286 -0
- package/templates/architecture/rfc-generator/ SKILL.md +362 -0
- package/templates/architecture/scalability-playbook/ SKILL.md +279 -0
- package/templates/architecture/system-design-generator/ SKILL.md +339 -0
- package/templates/architecture/tech-debt-prioritizer/ SKILL.md +329 -0
- package/templates/backend/api-contract-normalizer/ SKILL.md +487 -0
- package/templates/backend/api-endpoint-generator/ SKILL.md +415 -0
- package/templates/backend/auth-module-builder/ SKILL.md +99 -0
- package/templates/backend/background-jobs-designer/ SKILL.md +166 -0
- package/templates/backend/caching-strategist/ SKILL.md +190 -0
- package/templates/backend/error-handling-standardizer/ SKILL.md +174 -0
- package/templates/backend/rate-limiting-abuse-protection/ SKILL.md +147 -0
- package/templates/backend/rbac-permissions-builder/ SKILL.md +158 -0
- package/templates/backend/service-layer-extractor/ SKILL.md +269 -0
- package/templates/backend/webhook-receiver-hardener/ SKILL.md +211 -0
- package/templates/ci-cd/artifact-sbom-publisher/ SKILL.md +236 -0
- package/templates/ci-cd/caching-strategy-optimizer/ SKILL.md +195 -0
- package/templates/ci-cd/deployment-checklist-generator/ SKILL.md +381 -0
- package/templates/ci-cd/github-actions-pipeline-creator/ SKILL.md +348 -0
- package/templates/ci-cd/monorepo-ci-optimizer/ SKILL.md +298 -0
- package/templates/ci-cd/preview-environments-builder/ SKILL.md +187 -0
- package/templates/ci-cd/quality-gates-enforcer/ SKILL.md +342 -0
- package/templates/ci-cd/release-automation-builder/ SKILL.md +281 -0
- package/templates/ci-cd/rollback-workflow-builder/ SKILL.md +372 -0
- package/templates/ci-cd/secrets-env-manager/ SKILL.md +242 -0
- package/templates/db-management/backup-restore-runbook-generator/ SKILL.md +505 -0
- package/templates/db-management/data-integrity-auditor/ SKILL.md +505 -0
- package/templates/db-management/data-retention-archiving-planner/ SKILL.md +430 -0
- package/templates/db-management/data-seeding-fixtures-builder/ SKILL.md +375 -0
- package/templates/db-management/db-performance-watchlist/ SKILL.md +425 -0
- package/templates/db-management/etl-sync-job-builder/ SKILL.md +457 -0
- package/templates/db-management/multi-tenant-safety-checker/ SKILL.md +398 -0
- package/templates/db-management/prisma-migration-assistant/ SKILL.md +379 -0
- package/templates/db-management/schema-consistency-checker/ SKILL.md +440 -0
- package/templates/db-management/sql-query-optimizer/ SKILL.md +324 -0
- package/templates/foundation/changelog-writer/ SKILL.md +431 -0
- package/templates/foundation/code-formatter-installer/ SKILL.md +320 -0
- package/templates/foundation/codebase-summarizer/ SKILL.md +360 -0
- package/templates/foundation/dependency-doctor/ SKILL.md +163 -0
- package/templates/foundation/dev-environment-bootstrapper/ SKILL.md +259 -0
- package/templates/foundation/dev-onboarding-builder/ SKILL.md +556 -0
- package/templates/foundation/docs-starter-kit/ SKILL.md +574 -0
- package/templates/foundation/explaining-code/SKILL.md +13 -0
- package/templates/foundation/git-hygiene-enforcer/ SKILL.md +455 -0
- package/templates/foundation/project-scaffolder/ SKILL.md +65 -0
- package/templates/foundation/project-scaffolder/references/templates.md +126 -0
- package/templates/foundation/repo-structure-linter/ SKILL.md +0 -0
- package/templates/foundation/repo-structure-linter/references/conventions.md +98 -0
- package/templates/frontend/animation-micro-interaction-pack/ SKILL.md +41 -0
- package/templates/frontend/component-scaffold-generator/ SKILL.md +562 -0
- package/templates/frontend/design-to-component-translator/ SKILL.md +547 -0
- package/templates/frontend/form-wizard-builder/ SKILL.md +553 -0
- package/templates/frontend/frontend-refactor-planner/ SKILL.md +37 -0
- package/templates/frontend/i18n-frontend-implementer/ SKILL.md +44 -0
- package/templates/frontend/modal-drawer-system/ SKILL.md +377 -0
- package/templates/frontend/page-layout-builder/ SKILL.md +630 -0
- package/templates/frontend/state-ux-flow-builder/ SKILL.md +23 -0
- package/templates/frontend/table-builder/ SKILL.md +350 -0
- package/templates/performance/alerting-dashboard-builder/ SKILL.md +162 -0
- package/templates/performance/backend-latency-profiler-helper/ SKILL.md +108 -0
- package/templates/performance/caching-cdn-strategy-planner/ SKILL.md +150 -0
- package/templates/performance/capacity-planning-helper/ SKILL.md +242 -0
- package/templates/performance/core-web-vitals-tuner/ SKILL.md +126 -0
- package/templates/performance/incident-runbook-generator/ SKILL.md +162 -0
- package/templates/performance/load-test-scenario-builder/ SKILL.md +256 -0
- package/templates/performance/observability-setup/ SKILL.md +232 -0
- package/templates/performance/postmortem-writer/ SKILL.md +203 -0
- package/templates/performance/structured-logging-standardizer/ SKILL.md +122 -0
- package/templates/security/auth-security-reviewer/ SKILL.md +428 -0
- package/templates/security/dependency-vulnerability-triage/ SKILL.md +495 -0
- package/templates/security/input-validation-sanitization-auditor/ SKILL.md +76 -0
- package/templates/security/pii-redaction-logging-policy-builder/ SKILL.md +65 -0
- package/templates/security/rbac-policy-tester/ SKILL.md +80 -0
- package/templates/security/secrets-scanner/ SKILL.md +462 -0
- package/templates/security/secure-headers-csp-builder/ SKILL.md +404 -0
- package/templates/security/security-incident-playbook-generator/ SKILL.md +76 -0
- package/templates/security/security-pr-checklist-skill/ SKILL.md +62 -0
- package/templates/security/threat-model-generator/ SKILL.md +394 -0
- package/templates/testing/contract-testing-builder/ SKILL.md +492 -0
- package/templates/testing/coverage-strategist/ SKILL.md +436 -0
- package/templates/testing/e2e-test-builder/ SKILL.md +382 -0
- package/templates/testing/flaky-test-detective/ SKILL.md +416 -0
- package/templates/testing/integration-test-builder/ SKILL.md +525 -0
- package/templates/testing/mocking-assistant/ SKILL.md +383 -0
- package/templates/testing/snapshot-test-refactorer/ SKILL.md +375 -0
- package/templates/testing/test-data-factory-builder/ SKILL.md +449 -0
- package/templates/testing/test-reporting-triage-skill/ SKILL.md +469 -0
- package/templates/testing/unit-test-generator/ SKILL.md +548 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: schema-consistency-checker
|
|
3
|
+
description: Audits database schemas for naming conventions, type consistency, nullability patterns, and missing constraints. Provides violations report with recommended fixes. Use for "schema validation", "database linting", "schema standards", or "consistency checks".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Schema Consistency Checker
|
|
7
|
+
|
|
8
|
+
Enforce schema consistency and best practices across your database.
|
|
9
|
+
|
|
10
|
+
## Consistency Rules
|
|
11
|
+
|
|
12
|
+
### 1. Naming Conventions
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// naming-rules.ts
|
|
16
|
+
export const NAMING_RULES = {
|
|
17
|
+
tables: {
|
|
18
|
+
pattern: /^[A-Z][a-zA-Z0-9]*$/, // PascalCase
|
|
19
|
+
examples: ["User", "OrderItem", "ProductCategory"],
|
|
20
|
+
},
|
|
21
|
+
columns: {
|
|
22
|
+
pattern: /^[a-z][a-zA-Z0-9]*$/, // camelCase
|
|
23
|
+
examples: ["id", "firstName", "createdAt"],
|
|
24
|
+
},
|
|
25
|
+
indexes: {
|
|
26
|
+
pattern: /^idx_[a-z_]+$/, // idx_table_column
|
|
27
|
+
examples: ["idx_users_email", "idx_orders_user_id"],
|
|
28
|
+
},
|
|
29
|
+
foreignKeys: {
|
|
30
|
+
pattern: /^fk_[a-z_]+$/, // fk_table_column
|
|
31
|
+
examples: ["fk_orders_user_id", "fk_products_category_id"],
|
|
32
|
+
},
|
|
33
|
+
constraints: {
|
|
34
|
+
pattern: /^(chk|unq)_[a-z_]+$/, // chk_ or unq_prefix
|
|
35
|
+
examples: ["chk_age_positive", "unq_users_email"],
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Type Consistency
|
|
41
|
+
|
|
42
|
+
```sql
|
|
43
|
+
-- ❌ Bad: Inconsistent types for IDs
|
|
44
|
+
CREATE TABLE users (
|
|
45
|
+
id INTEGER PRIMARY KEY,
|
|
46
|
+
email TEXT
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE TABLE orders (
|
|
50
|
+
id BIGINT PRIMARY KEY, -- ❌ Different ID type
|
|
51
|
+
user_id TEXT -- ❌ Wrong type for FK
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
-- ✅ Good: Consistent types
|
|
55
|
+
CREATE TABLE users (
|
|
56
|
+
id BIGINT PRIMARY KEY,
|
|
57
|
+
email TEXT
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE TABLE orders (
|
|
61
|
+
id BIGINT PRIMARY KEY,
|
|
62
|
+
user_id BIGINT REFERENCES users(id)
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. Nullability Patterns
|
|
67
|
+
|
|
68
|
+
```sql
|
|
69
|
+
-- ❌ Bad: Inconsistent NULL handling
|
|
70
|
+
CREATE TABLE users (
|
|
71
|
+
id BIGINT PRIMARY KEY,
|
|
72
|
+
email TEXT, -- ❌ No NOT NULL on critical field
|
|
73
|
+
name TEXT, -- ❌ Should be NOT NULL
|
|
74
|
+
phone TEXT NULL, -- ⚠️ Explicit NULL unnecessary
|
|
75
|
+
created_at TIMESTAMP -- ❌ Missing NOT NULL
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
-- ✅ Good: Clear nullability
|
|
79
|
+
CREATE TABLE users (
|
|
80
|
+
id BIGINT PRIMARY KEY,
|
|
81
|
+
email TEXT NOT NULL UNIQUE,
|
|
82
|
+
name TEXT NOT NULL,
|
|
83
|
+
phone TEXT, -- Optional field
|
|
84
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 4. Missing Constraints
|
|
89
|
+
|
|
90
|
+
```sql
|
|
91
|
+
-- ❌ Bad: Missing constraints
|
|
92
|
+
CREATE TABLE orders (
|
|
93
|
+
id BIGINT PRIMARY KEY,
|
|
94
|
+
user_id BIGINT, -- ❌ Missing FK
|
|
95
|
+
status TEXT, -- ❌ No CHECK constraint
|
|
96
|
+
total DECIMAL(10,2), -- ❌ No CHECK for positive
|
|
97
|
+
created_at TIMESTAMP
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
-- ✅ Good: Proper constraints
|
|
101
|
+
CREATE TABLE orders (
|
|
102
|
+
id BIGINT PRIMARY KEY,
|
|
103
|
+
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
104
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'paid', 'shipped', 'delivered')),
|
|
105
|
+
total DECIMAL(10,2) NOT NULL CHECK (total >= 0),
|
|
106
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
107
|
+
);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Audit Script
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// scripts/audit-schema.ts
|
|
114
|
+
import { PrismaClient } from "@prisma/client";
|
|
115
|
+
|
|
116
|
+
const prisma = new PrismaClient();
|
|
117
|
+
|
|
118
|
+
interface Violation {
|
|
119
|
+
severity: "error" | "warning" | "info";
|
|
120
|
+
category: string;
|
|
121
|
+
table: string;
|
|
122
|
+
column?: string;
|
|
123
|
+
message: string;
|
|
124
|
+
recommendation: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function auditSchema(): Promise<Violation[]> {
|
|
128
|
+
const violations: Violation[] = [];
|
|
129
|
+
|
|
130
|
+
// Get schema metadata
|
|
131
|
+
const tables = await prisma.$queryRaw<any[]>`
|
|
132
|
+
SELECT
|
|
133
|
+
table_name,
|
|
134
|
+
column_name,
|
|
135
|
+
data_type,
|
|
136
|
+
is_nullable,
|
|
137
|
+
column_default
|
|
138
|
+
FROM information_schema.columns
|
|
139
|
+
WHERE table_schema = 'public'
|
|
140
|
+
ORDER BY table_name, ordinal_position
|
|
141
|
+
`;
|
|
142
|
+
|
|
143
|
+
// Check 1: Naming conventions
|
|
144
|
+
tables.forEach((col) => {
|
|
145
|
+
// Table naming
|
|
146
|
+
if (!/^[A-Z][a-zA-Z0-9]*$/.test(col.table_name)) {
|
|
147
|
+
violations.push({
|
|
148
|
+
severity: "warning",
|
|
149
|
+
category: "naming",
|
|
150
|
+
table: col.table_name,
|
|
151
|
+
message: `Table name '${col.table_name}' doesn't follow PascalCase convention`,
|
|
152
|
+
recommendation: `Rename to PascalCase (e.g., 'UserProfile', 'OrderItem')`,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Column naming
|
|
157
|
+
if (!/^[a-z][a-zA-Z0-9]*$/.test(col.column_name)) {
|
|
158
|
+
violations.push({
|
|
159
|
+
severity: "warning",
|
|
160
|
+
category: "naming",
|
|
161
|
+
table: col.table_name,
|
|
162
|
+
column: col.column_name,
|
|
163
|
+
message: `Column '${col.column_name}' doesn't follow camelCase convention`,
|
|
164
|
+
recommendation: `Rename to camelCase (e.g., 'firstName', 'createdAt')`,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Check 2: Missing NOT NULL on critical fields
|
|
170
|
+
const criticalFields = [
|
|
171
|
+
"email",
|
|
172
|
+
"name",
|
|
173
|
+
"user_id",
|
|
174
|
+
"created_at",
|
|
175
|
+
"updated_at",
|
|
176
|
+
];
|
|
177
|
+
tables.forEach((col) => {
|
|
178
|
+
if (
|
|
179
|
+
criticalFields.some((f) => col.column_name.includes(f)) &&
|
|
180
|
+
col.is_nullable === "YES"
|
|
181
|
+
) {
|
|
182
|
+
violations.push({
|
|
183
|
+
severity: "error",
|
|
184
|
+
category: "nullability",
|
|
185
|
+
table: col.table_name,
|
|
186
|
+
column: col.column_name,
|
|
187
|
+
message: `Critical field '${col.column_name}' allows NULL`,
|
|
188
|
+
recommendation: `Add NOT NULL constraint`,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Check 3: Type consistency for IDs
|
|
194
|
+
const idTypes = new Map<string, string>();
|
|
195
|
+
tables.forEach((col) => {
|
|
196
|
+
if (col.column_name === "id") {
|
|
197
|
+
idTypes.set(col.table_name, col.data_type);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const primaryIdType = Array.from(idTypes.values())[0];
|
|
202
|
+
idTypes.forEach((type, table) => {
|
|
203
|
+
if (type !== primaryIdType) {
|
|
204
|
+
violations.push({
|
|
205
|
+
severity: "error",
|
|
206
|
+
category: "type-consistency",
|
|
207
|
+
table,
|
|
208
|
+
column: "id",
|
|
209
|
+
message: `ID type '${type}' inconsistent with primary type '${primaryIdType}'`,
|
|
210
|
+
recommendation: `Standardize all IDs to ${primaryIdType}`,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Check 4: Missing indexes on foreign keys
|
|
216
|
+
const foreignKeys = await prisma.$queryRaw<any[]>`
|
|
217
|
+
SELECT
|
|
218
|
+
tc.table_name,
|
|
219
|
+
kcu.column_name
|
|
220
|
+
FROM information_schema.table_constraints tc
|
|
221
|
+
JOIN information_schema.key_column_usage kcu
|
|
222
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
223
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
224
|
+
`;
|
|
225
|
+
|
|
226
|
+
const indexes = await prisma.$queryRaw<any[]>`
|
|
227
|
+
SELECT
|
|
228
|
+
tablename,
|
|
229
|
+
indexname,
|
|
230
|
+
indexdef
|
|
231
|
+
FROM pg_indexes
|
|
232
|
+
WHERE schemaname = 'public'
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
foreignKeys.forEach((fk) => {
|
|
236
|
+
const hasIndex = indexes.some(
|
|
237
|
+
(idx) =>
|
|
238
|
+
idx.tablename === fk.table_name && idx.indexdef.includes(fk.column_name)
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
if (!hasIndex) {
|
|
242
|
+
violations.push({
|
|
243
|
+
severity: "warning",
|
|
244
|
+
category: "performance",
|
|
245
|
+
table: fk.table_name,
|
|
246
|
+
column: fk.column_name,
|
|
247
|
+
message: `Foreign key '${fk.column_name}' has no index`,
|
|
248
|
+
recommendation: `CREATE INDEX idx_${fk.table_name}_${fk.column_name} ON "${fk.table_name}"("${fk.column_name}")`,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Check 5: Missing timestamps
|
|
254
|
+
const tablesGrouped = tables.reduce((acc, col) => {
|
|
255
|
+
if (!acc[col.table_name]) acc[col.table_name] = [];
|
|
256
|
+
acc[col.table_name].push(col.column_name);
|
|
257
|
+
return acc;
|
|
258
|
+
}, {} as Record<string, string[]>);
|
|
259
|
+
|
|
260
|
+
Object.entries(tablesGrouped).forEach(([table, columns]) => {
|
|
261
|
+
if (!columns.includes("created_at")) {
|
|
262
|
+
violations.push({
|
|
263
|
+
severity: "info",
|
|
264
|
+
category: "audit",
|
|
265
|
+
table,
|
|
266
|
+
message: `Table missing 'created_at' timestamp`,
|
|
267
|
+
recommendation: `Add: created_at TIMESTAMP NOT NULL DEFAULT NOW()`,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
if (!columns.includes("updated_at") && !columns.includes("updatedAt")) {
|
|
271
|
+
violations.push({
|
|
272
|
+
severity: "info",
|
|
273
|
+
category: "audit",
|
|
274
|
+
table,
|
|
275
|
+
message: `Table missing 'updated_at' timestamp`,
|
|
276
|
+
recommendation: `Add: updated_at TIMESTAMP NOT NULL DEFAULT NOW()`,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return violations;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Generate report
|
|
285
|
+
async function generateReport() {
|
|
286
|
+
const violations = await auditSchema();
|
|
287
|
+
|
|
288
|
+
console.log("📊 Schema Audit Report\n");
|
|
289
|
+
console.log(`Total violations: ${violations.length}\n`);
|
|
290
|
+
|
|
291
|
+
// Group by severity
|
|
292
|
+
const grouped = violations.reduce((acc, v) => {
|
|
293
|
+
if (!acc[v.severity]) acc[v.severity] = [];
|
|
294
|
+
acc[v.severity].push(v);
|
|
295
|
+
return acc;
|
|
296
|
+
}, {} as Record<string, Violation[]>);
|
|
297
|
+
|
|
298
|
+
// Print by severity
|
|
299
|
+
(["error", "warning", "info"] as const).forEach((severity) => {
|
|
300
|
+
const items = grouped[severity] || [];
|
|
301
|
+
if (items.length === 0) return;
|
|
302
|
+
|
|
303
|
+
console.log(
|
|
304
|
+
`\n${
|
|
305
|
+
{ error: "❌ Errors", warning: "⚠️ Warnings", info: "ℹ️ Info" }[
|
|
306
|
+
severity
|
|
307
|
+
]
|
|
308
|
+
} (${items.length})\n`
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
items.forEach((v, i) => {
|
|
312
|
+
console.log(
|
|
313
|
+
`${i + 1}. [${v.category}] ${v.table}${v.column ? `.${v.column}` : ""}`
|
|
314
|
+
);
|
|
315
|
+
console.log(` Message: ${v.message}`);
|
|
316
|
+
console.log(` Fix: ${v.recommendation}\n`);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Exit code based on errors
|
|
321
|
+
process.exit(grouped.error?.length > 0 ? 1 : 0);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
generateReport();
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Recommended Schema Standards
|
|
328
|
+
|
|
329
|
+
```prisma
|
|
330
|
+
// schema.prisma with best practices
|
|
331
|
+
|
|
332
|
+
model User {
|
|
333
|
+
// 1. ID: Consistent type (Int or String/cuid)
|
|
334
|
+
id Int @id @default(autoincrement())
|
|
335
|
+
|
|
336
|
+
// 2. Critical fields: NOT NULL
|
|
337
|
+
email String @unique
|
|
338
|
+
name String
|
|
339
|
+
|
|
340
|
+
// 3. Optional fields: Clearly nullable
|
|
341
|
+
phone String?
|
|
342
|
+
bio String?
|
|
343
|
+
|
|
344
|
+
// 4. Audit timestamps: Always include
|
|
345
|
+
createdAt DateTime @default(now())
|
|
346
|
+
updatedAt DateTime @updatedAt
|
|
347
|
+
|
|
348
|
+
// 5. Relations: Proper foreign keys
|
|
349
|
+
orders Order[]
|
|
350
|
+
|
|
351
|
+
// 6. Indexes: On frequently queried fields
|
|
352
|
+
@@index([email])
|
|
353
|
+
@@index([createdAt])
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
model Order {
|
|
357
|
+
id Int @id @default(autoincrement())
|
|
358
|
+
|
|
359
|
+
// Foreign key with clear naming
|
|
360
|
+
userId Int
|
|
361
|
+
user User @relation(fields: [userId], references: [id])
|
|
362
|
+
|
|
363
|
+
// Enum for status (type safety)
|
|
364
|
+
status OrderStatus @default(PENDING)
|
|
365
|
+
|
|
366
|
+
// Decimal for money
|
|
367
|
+
total Decimal @db.Decimal(10, 2)
|
|
368
|
+
|
|
369
|
+
// Timestamps
|
|
370
|
+
createdAt DateTime @default(now())
|
|
371
|
+
updatedAt DateTime @updatedAt
|
|
372
|
+
|
|
373
|
+
// Indexes on foreign keys
|
|
374
|
+
@@index([userId])
|
|
375
|
+
@@index([status])
|
|
376
|
+
@@index([createdAt])
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
enum OrderStatus {
|
|
380
|
+
PENDING
|
|
381
|
+
PAID
|
|
382
|
+
SHIPPED
|
|
383
|
+
DELIVERED
|
|
384
|
+
CANCELLED
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Auto-fix Migrations
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
// scripts/fix-schema.ts
|
|
392
|
+
async function generateFixMigrations(violations: Violation[]) {
|
|
393
|
+
const migrations: string[] = [];
|
|
394
|
+
|
|
395
|
+
violations.forEach((v) => {
|
|
396
|
+
if (v.category === "nullability" && v.column) {
|
|
397
|
+
migrations.push(
|
|
398
|
+
`ALTER TABLE "${v.table}" ALTER COLUMN "${v.column}" SET NOT NULL;`
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (
|
|
403
|
+
v.category === "performance" &&
|
|
404
|
+
v.recommendation.startsWith("CREATE INDEX")
|
|
405
|
+
) {
|
|
406
|
+
migrations.push(v.recommendation + ";");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (v.category === "audit" && v.message.includes("created_at")) {
|
|
410
|
+
migrations.push(
|
|
411
|
+
`ALTER TABLE "${v.table}" ADD COLUMN "created_at" TIMESTAMP NOT NULL DEFAULT NOW();`
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
console.log("-- Auto-generated fixes\n");
|
|
417
|
+
migrations.forEach((m) => console.log(m));
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Best Practices
|
|
422
|
+
|
|
423
|
+
1. **Run regularly**: Weekly schema audits
|
|
424
|
+
2. **Enforce in CI**: Fail builds on errors
|
|
425
|
+
3. **Document standards**: Team agreement on conventions
|
|
426
|
+
4. **Gradual adoption**: Fix incrementally
|
|
427
|
+
5. **Use enums**: For status fields
|
|
428
|
+
6. **Always timestamp**: created_at and updated_at
|
|
429
|
+
7. **Index foreign keys**: Performance best practice
|
|
430
|
+
|
|
431
|
+
## Output Checklist
|
|
432
|
+
|
|
433
|
+
- [ ] Naming violations report
|
|
434
|
+
- [ ] Type consistency checks
|
|
435
|
+
- [ ] Nullability issues identified
|
|
436
|
+
- [ ] Missing constraints flagged
|
|
437
|
+
- [ ] Performance issues (missing indexes)
|
|
438
|
+
- [ ] Recommended fixes generated
|
|
439
|
+
- [ ] Auto-fix migrations provided
|
|
440
|
+
- [ ] Schema standards documented
|