@neyugn/agent-kits 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/LICENSE +21 -0
- package/README.md +514 -0
- package/README.vi.md +410 -0
- package/README.zh.md +410 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +422 -0
- package/kits/coder/ARCHITECTURE.md +289 -0
- package/kits/coder/agents/ai-engineer.md +344 -0
- package/kits/coder/agents/backend-specialist.md +270 -0
- package/kits/coder/agents/cloud-architect.md +363 -0
- package/kits/coder/agents/code-reviewer.md +284 -0
- package/kits/coder/agents/data-engineer.md +401 -0
- package/kits/coder/agents/database-specialist.md +251 -0
- package/kits/coder/agents/debugger.md +209 -0
- package/kits/coder/agents/devops-engineer.md +281 -0
- package/kits/coder/agents/documentation-writer.md +296 -0
- package/kits/coder/agents/frontend-specialist.md +298 -0
- package/kits/coder/agents/i18n-specialist.md +348 -0
- package/kits/coder/agents/integration-specialist.md +314 -0
- package/kits/coder/agents/mobile-developer.md +271 -0
- package/kits/coder/agents/multi-tenant-architect.md +281 -0
- package/kits/coder/agents/orchestrator.md +263 -0
- package/kits/coder/agents/performance-analyst.md +327 -0
- package/kits/coder/agents/project-planner.md +277 -0
- package/kits/coder/agents/queue-specialist.md +282 -0
- package/kits/coder/agents/realtime-specialist.md +267 -0
- package/kits/coder/agents/security-auditor.md +253 -0
- package/kits/coder/agents/test-engineer.md +315 -0
- package/kits/coder/agents/ux-researcher.md +388 -0
- package/kits/coder/rules/.cursorrules +287 -0
- package/kits/coder/rules/CLAUDE.md +287 -0
- package/kits/coder/rules/CODEX.md +287 -0
- package/kits/coder/rules/GEMINI.md +287 -0
- package/kits/coder/scripts/checklist.py +318 -0
- package/kits/coder/scripts/kit_status.py +292 -0
- package/kits/coder/scripts/skills_manager.py +243 -0
- package/kits/coder/scripts/verify_all.py +391 -0
- package/kits/coder/skills/accessibility-patterns/SKILL.md +372 -0
- package/kits/coder/skills/accessibility-patterns/scripts/a11y_checker.py +211 -0
- package/kits/coder/skills/ai-rag-patterns/SKILL.md +444 -0
- package/kits/coder/skills/api-patterns/SKILL.md +316 -0
- package/kits/coder/skills/api-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/api-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/api-patterns/scripts/api_validator.py +253 -0
- package/kits/coder/skills/api-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/auth-patterns/SKILL.md +267 -0
- package/kits/coder/skills/aws-patterns/SKILL.md +576 -0
- package/kits/coder/skills/brainstorming/SKILL.md +370 -0
- package/kits/coder/skills/brainstorming/assets/.gitkeep +1 -0
- package/kits/coder/skills/brainstorming/references/deep-dive.md +21 -0
- package/kits/coder/skills/brainstorming/scripts/validate.py +56 -0
- package/kits/coder/skills/clean-code/SKILL.md +240 -0
- package/kits/coder/skills/clean-code/assets/.gitkeep +1 -0
- package/kits/coder/skills/clean-code/references/deep-dive.md +21 -0
- package/kits/coder/skills/clean-code/scripts/lint_runner.py +186 -0
- package/kits/coder/skills/clean-code/scripts/validate.py +56 -0
- package/kits/coder/skills/database-design/SKILL.md +255 -0
- package/kits/coder/skills/database-design/assets/.gitkeep +1 -0
- package/kits/coder/skills/database-design/references/deep-dive.md +21 -0
- package/kits/coder/skills/database-design/scripts/schema_validator.py +272 -0
- package/kits/coder/skills/database-design/scripts/validate.py +56 -0
- package/kits/coder/skills/docker-patterns/SKILL.md +240 -0
- package/kits/coder/skills/documentation-templates/SKILL.md +441 -0
- package/kits/coder/skills/e2e-testing/SKILL.md +457 -0
- package/kits/coder/skills/flutter-patterns/SKILL.md +330 -0
- package/kits/coder/skills/frontend-design/SKILL.md +127 -0
- package/kits/coder/skills/github-actions/SKILL.md +349 -0
- package/kits/coder/skills/gitlab-ci-patterns/SKILL.md +466 -0
- package/kits/coder/skills/graphql-patterns/SKILL.md +558 -0
- package/kits/coder/skills/i18n-localization/SKILL.md +345 -0
- package/kits/coder/skills/i18n-localization/scripts/i18n_checker.py +267 -0
- package/kits/coder/skills/kubernetes-patterns/SKILL.md +357 -0
- package/kits/coder/skills/mermaid-diagrams/SKILL.md +351 -0
- package/kits/coder/skills/mobile-design/SKILL.md +305 -0
- package/kits/coder/skills/monitoring-observability/SKILL.md +458 -0
- package/kits/coder/skills/multi-tenancy/SKILL.md +317 -0
- package/kits/coder/skills/multi-tenancy/assets/.gitkeep +1 -0
- package/kits/coder/skills/multi-tenancy/references/deep-dive.md +21 -0
- package/kits/coder/skills/multi-tenancy/scripts/validate.py +56 -0
- package/kits/coder/skills/nodejs-best-practices/SKILL.md +220 -0
- package/kits/coder/skills/performance-profiling/SKILL.md +333 -0
- package/kits/coder/skills/performance-profiling/assets/.gitkeep +1 -0
- package/kits/coder/skills/performance-profiling/references/deep-dive.md +21 -0
- package/kits/coder/skills/performance-profiling/scripts/validate.py +56 -0
- package/kits/coder/skills/plan-writing/SKILL.md +360 -0
- package/kits/coder/skills/plan-writing/assets/.gitkeep +1 -0
- package/kits/coder/skills/plan-writing/references/deep-dive.md +21 -0
- package/kits/coder/skills/plan-writing/scripts/validate.py +56 -0
- package/kits/coder/skills/postgres-patterns/SKILL.md +361 -0
- package/kits/coder/skills/prompt-engineering/SKILL.md +277 -0
- package/kits/coder/skills/queue-patterns/SKILL.md +359 -0
- package/kits/coder/skills/queue-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/queue-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/queue-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/react-native-patterns/SKILL.md +393 -0
- package/kits/coder/skills/react-patterns/SKILL.md +319 -0
- package/kits/coder/skills/realtime-patterns/SKILL.md +506 -0
- package/kits/coder/skills/realtime-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/realtime-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/realtime-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/redis-patterns/SKILL.md +484 -0
- package/kits/coder/skills/security-fundamentals/SKILL.md +363 -0
- package/kits/coder/skills/security-fundamentals/assets/.gitkeep +1 -0
- package/kits/coder/skills/security-fundamentals/references/deep-dive.md +21 -0
- package/kits/coder/skills/security-fundamentals/scripts/security_scan.py +326 -0
- package/kits/coder/skills/security-fundamentals/scripts/validate.py +56 -0
- package/kits/coder/skills/seo-patterns/SKILL.md +262 -0
- package/kits/coder/skills/seo-patterns/scripts/seo_checker.py +211 -0
- package/kits/coder/skills/systematic-debugging/SKILL.md +478 -0
- package/kits/coder/skills/systematic-debugging/assets/.gitkeep +1 -0
- package/kits/coder/skills/systematic-debugging/references/deep-dive.md +21 -0
- package/kits/coder/skills/systematic-debugging/scripts/validate.py +56 -0
- package/kits/coder/skills/tailwind-patterns/SKILL.md +395 -0
- package/kits/coder/skills/terraform-patterns/SKILL.md +470 -0
- package/kits/coder/skills/testing-patterns/SKILL.md +285 -0
- package/kits/coder/skills/testing-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/testing-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/testing-patterns/scripts/test_runner.py +219 -0
- package/kits/coder/skills/testing-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/typescript-patterns/SKILL.md +417 -0
- package/kits/coder/skills/ui-ux-pro-max/SKILL.md +364 -0
- package/kits/coder/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/kits/coder/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/kits/coder/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/kits/coder/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/kits/coder/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/kits/coder/skills/ui-ux-pro-max/data/prompts.csv +24 -0
- package/kits/coder/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/kits/coder/skills/ui-ux-pro-max/data/styles.csv +59 -0
- package/kits/coder/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/kits/coder/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/kits/coder/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/kits/coder/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/core.py +257 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/design_system.py +488 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/search.py +76 -0
- package/kits/coder/workflows/.gitkeep +20 -0
- package/kits/coder/workflows/create.md +152 -0
- package/kits/coder/workflows/debug.md +223 -0
- package/kits/coder/workflows/deploy.md +283 -0
- package/kits/coder/workflows/orchestrate.md +243 -0
- package/kits/coder/workflows/plan.md +134 -0
- package/kits/coder/workflows/test.md +237 -0
- package/kits/coder/workflows/ui-ux-pro-max.md +109 -0
- package/package.json +49 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Schema Validator - Database schema validation for AGT-Kit
|
|
4
|
+
==========================================================
|
|
5
|
+
|
|
6
|
+
Validates Prisma, Drizzle, TypeORM schemas and checks for common issues.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python3 .agent/skills/database-design/scripts/schema_validator.py <project_path>
|
|
10
|
+
|
|
11
|
+
Checks:
|
|
12
|
+
- Prisma schema syntax and conventions
|
|
13
|
+
- Missing relations and indexes
|
|
14
|
+
- Naming conventions (PascalCase models, camelCase fields)
|
|
15
|
+
- Required fields (id, createdAt, updatedAt)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
import json
|
|
20
|
+
import re
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
from typing import List, Dict, Any
|
|
24
|
+
|
|
25
|
+
# Fix console encoding
|
|
26
|
+
try:
|
|
27
|
+
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
28
|
+
except:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def find_schema_files(project_path: Path) -> List[tuple]:
|
|
33
|
+
"""Find database schema files."""
|
|
34
|
+
schemas = []
|
|
35
|
+
|
|
36
|
+
# Prisma
|
|
37
|
+
for f in project_path.glob('**/prisma/schema.prisma'):
|
|
38
|
+
if 'node_modules' not in str(f):
|
|
39
|
+
schemas.append(('prisma', f))
|
|
40
|
+
|
|
41
|
+
# Drizzle
|
|
42
|
+
for pattern in ['**/drizzle/*.ts', '**/db/schema*.ts', '**/schema/*.ts']:
|
|
43
|
+
for f in project_path.glob(pattern):
|
|
44
|
+
if 'node_modules' not in str(f) and ('schema' in f.name.lower() or 'table' in f.name.lower()):
|
|
45
|
+
schemas.append(('drizzle', f))
|
|
46
|
+
|
|
47
|
+
# TypeORM entities
|
|
48
|
+
for f in project_path.glob('**/entities/*.ts'):
|
|
49
|
+
if 'node_modules' not in str(f):
|
|
50
|
+
schemas.append(('typeorm', f))
|
|
51
|
+
|
|
52
|
+
return schemas[:15] # Limit
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def validate_prisma_schema(file_path: Path) -> Dict[str, Any]:
|
|
56
|
+
"""Validate Prisma schema file."""
|
|
57
|
+
issues = []
|
|
58
|
+
passed = []
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
content = file_path.read_text(encoding='utf-8', errors='ignore')
|
|
62
|
+
|
|
63
|
+
# Find all models
|
|
64
|
+
models = re.findall(r'model\s+(\w+)\s*{([^}]+)}', content, re.DOTALL)
|
|
65
|
+
|
|
66
|
+
if models:
|
|
67
|
+
passed.append(f"Found {len(models)} models")
|
|
68
|
+
else:
|
|
69
|
+
issues.append("No models found in schema")
|
|
70
|
+
return {"passed": passed, "issues": issues}
|
|
71
|
+
|
|
72
|
+
for model_name, model_body in models:
|
|
73
|
+
# Check PascalCase naming
|
|
74
|
+
if not model_name[0].isupper():
|
|
75
|
+
issues.append(f"Model '{model_name}' should be PascalCase")
|
|
76
|
+
|
|
77
|
+
# Check for id field
|
|
78
|
+
if '@id' not in model_body:
|
|
79
|
+
issues.append(f"Model '{model_name}' missing @id field")
|
|
80
|
+
|
|
81
|
+
# Check for timestamps
|
|
82
|
+
has_created = 'createdAt' in model_body or 'created_at' in model_body
|
|
83
|
+
has_updated = 'updatedAt' in model_body or 'updated_at' in model_body
|
|
84
|
+
|
|
85
|
+
if not has_created:
|
|
86
|
+
issues.append(f"Model '{model_name}' missing createdAt (recommended)")
|
|
87
|
+
if not has_updated:
|
|
88
|
+
issues.append(f"Model '{model_name}' missing updatedAt (recommended)")
|
|
89
|
+
|
|
90
|
+
# Check for index on foreign keys
|
|
91
|
+
fk_fields = re.findall(r'(\w+Id)\s+\w+', model_body)
|
|
92
|
+
for fk in fk_fields:
|
|
93
|
+
if f'@@index([{fk}])' not in content and f'@@index(["{fk}"])' not in content:
|
|
94
|
+
issues.append(f"Consider @@index([{fk}]) in {model_name}")
|
|
95
|
+
|
|
96
|
+
# Check for enums
|
|
97
|
+
enums = re.findall(r'enum\s+(\w+)\s*{', content)
|
|
98
|
+
if enums:
|
|
99
|
+
passed.append(f"Found {len(enums)} enums")
|
|
100
|
+
for enum_name in enums:
|
|
101
|
+
if not enum_name[0].isupper():
|
|
102
|
+
issues.append(f"Enum '{enum_name}' should be PascalCase")
|
|
103
|
+
|
|
104
|
+
# Check for datasource
|
|
105
|
+
if 'datasource' in content:
|
|
106
|
+
passed.append("Datasource configured")
|
|
107
|
+
else:
|
|
108
|
+
issues.append("Missing datasource configuration")
|
|
109
|
+
|
|
110
|
+
# Check for generator
|
|
111
|
+
if 'generator' in content:
|
|
112
|
+
passed.append("Generator configured")
|
|
113
|
+
|
|
114
|
+
except Exception as e:
|
|
115
|
+
issues.append(f"Parse error: {str(e)[:50]}")
|
|
116
|
+
|
|
117
|
+
return {"passed": passed, "issues": issues}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def validate_drizzle_schema(file_path: Path) -> Dict[str, Any]:
|
|
121
|
+
"""Validate Drizzle schema file."""
|
|
122
|
+
issues = []
|
|
123
|
+
passed = []
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
content = file_path.read_text(encoding='utf-8', errors='ignore')
|
|
127
|
+
|
|
128
|
+
# Check for table definitions
|
|
129
|
+
tables = re.findall(r'(?:export\s+const|const)\s+(\w+)\s*=\s*(?:pgTable|mysqlTable|sqliteTable)', content)
|
|
130
|
+
|
|
131
|
+
if tables:
|
|
132
|
+
passed.append(f"Found {len(tables)} tables")
|
|
133
|
+
else:
|
|
134
|
+
issues.append("No table definitions found")
|
|
135
|
+
|
|
136
|
+
# Check for id columns
|
|
137
|
+
if 'primaryKey' in content or '.primaryKey()' in content:
|
|
138
|
+
passed.append("Primary keys defined")
|
|
139
|
+
else:
|
|
140
|
+
issues.append("Missing primary key definitions")
|
|
141
|
+
|
|
142
|
+
# Check for timestamps
|
|
143
|
+
if 'timestamp' in content.lower() or 'createdAt' in content:
|
|
144
|
+
passed.append("Timestamp fields found")
|
|
145
|
+
|
|
146
|
+
# Check for relations
|
|
147
|
+
if 'relations' in content:
|
|
148
|
+
passed.append("Relations defined")
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
issues.append(f"Parse error: {str(e)[:50]}")
|
|
152
|
+
|
|
153
|
+
return {"passed": passed, "issues": issues}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def validate_typeorm_entity(file_path: Path) -> Dict[str, Any]:
|
|
157
|
+
"""Validate TypeORM entity file."""
|
|
158
|
+
issues = []
|
|
159
|
+
passed = []
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
content = file_path.read_text(encoding='utf-8', errors='ignore')
|
|
163
|
+
|
|
164
|
+
# Check for @Entity decorator
|
|
165
|
+
if '@Entity' in content:
|
|
166
|
+
passed.append("@Entity decorator found")
|
|
167
|
+
else:
|
|
168
|
+
issues.append("Missing @Entity decorator")
|
|
169
|
+
|
|
170
|
+
# Check for @PrimaryGeneratedColumn or @PrimaryColumn
|
|
171
|
+
if '@PrimaryGeneratedColumn' in content or '@PrimaryColumn' in content:
|
|
172
|
+
passed.append("Primary key defined")
|
|
173
|
+
else:
|
|
174
|
+
issues.append("Missing primary key column")
|
|
175
|
+
|
|
176
|
+
# Check for @CreateDateColumn
|
|
177
|
+
if '@CreateDateColumn' in content:
|
|
178
|
+
passed.append("CreateDateColumn found")
|
|
179
|
+
else:
|
|
180
|
+
issues.append("Consider adding @CreateDateColumn")
|
|
181
|
+
|
|
182
|
+
except Exception as e:
|
|
183
|
+
issues.append(f"Parse error: {str(e)[:50]}")
|
|
184
|
+
|
|
185
|
+
return {"passed": passed, "issues": issues}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def main():
|
|
189
|
+
project_path = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
|
190
|
+
|
|
191
|
+
print(f"\n{'='*60}")
|
|
192
|
+
print(f"[AGT-KIT SCHEMA VALIDATOR] Database Schema Check")
|
|
193
|
+
print(f"{'='*60}")
|
|
194
|
+
print(f"Project: {project_path}")
|
|
195
|
+
print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
196
|
+
print("-"*60)
|
|
197
|
+
|
|
198
|
+
schemas = find_schema_files(project_path)
|
|
199
|
+
print(f"Found {len(schemas)} schema files")
|
|
200
|
+
|
|
201
|
+
if not schemas:
|
|
202
|
+
output = {
|
|
203
|
+
"script": "schema_validator",
|
|
204
|
+
"skill": "database-design",
|
|
205
|
+
"project": str(project_path),
|
|
206
|
+
"schemas_checked": 0,
|
|
207
|
+
"passed": True,
|
|
208
|
+
"message": "No schema files found"
|
|
209
|
+
}
|
|
210
|
+
print(json.dumps(output, indent=2))
|
|
211
|
+
sys.exit(0)
|
|
212
|
+
|
|
213
|
+
all_results = []
|
|
214
|
+
total_issues = 0
|
|
215
|
+
|
|
216
|
+
for schema_type, file_path in schemas:
|
|
217
|
+
print(f"\n📄 {file_path.name} ({schema_type})")
|
|
218
|
+
|
|
219
|
+
if schema_type == 'prisma':
|
|
220
|
+
result = validate_prisma_schema(file_path)
|
|
221
|
+
elif schema_type == 'drizzle':
|
|
222
|
+
result = validate_drizzle_schema(file_path)
|
|
223
|
+
elif schema_type == 'typeorm':
|
|
224
|
+
result = validate_typeorm_entity(file_path)
|
|
225
|
+
else:
|
|
226
|
+
result = {"passed": [], "issues": []}
|
|
227
|
+
|
|
228
|
+
# Print results
|
|
229
|
+
for item in result["passed"]:
|
|
230
|
+
print(f" ✅ {item}")
|
|
231
|
+
for item in result["issues"][:5]:
|
|
232
|
+
print(f" ⚠️ {item}")
|
|
233
|
+
|
|
234
|
+
if len(result["issues"]) > 5:
|
|
235
|
+
print(f" ... and {len(result['issues']) - 5} more issues")
|
|
236
|
+
|
|
237
|
+
all_results.append({
|
|
238
|
+
"file": str(file_path.name),
|
|
239
|
+
"type": schema_type,
|
|
240
|
+
**result
|
|
241
|
+
})
|
|
242
|
+
total_issues += len(result["issues"])
|
|
243
|
+
|
|
244
|
+
# Summary
|
|
245
|
+
print("\n" + "="*60)
|
|
246
|
+
print("SUMMARY")
|
|
247
|
+
print("="*60)
|
|
248
|
+
|
|
249
|
+
# Schema issues are warnings, not failures
|
|
250
|
+
passed = total_issues < 10
|
|
251
|
+
|
|
252
|
+
if passed:
|
|
253
|
+
print(f"✅ Schema validation passed ({total_issues} minor issues)")
|
|
254
|
+
else:
|
|
255
|
+
print(f"⚠️ Schema needs review ({total_issues} issues)")
|
|
256
|
+
|
|
257
|
+
output = {
|
|
258
|
+
"script": "schema_validator",
|
|
259
|
+
"skill": "database-design",
|
|
260
|
+
"project": str(project_path),
|
|
261
|
+
"schemas_checked": len(schemas),
|
|
262
|
+
"total_issues": total_issues,
|
|
263
|
+
"passed": passed,
|
|
264
|
+
"results": all_results
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
print("\n" + json.dumps(output, indent=2))
|
|
268
|
+
sys.exit(0)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
if __name__ == "__main__":
|
|
272
|
+
main()
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example validator for database-design
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python validate.py <project_path>
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validate(project_path: str) -> dict:
|
|
14
|
+
"""Main validation logic"""
|
|
15
|
+
results = {
|
|
16
|
+
'errors': [],
|
|
17
|
+
'warnings': [],
|
|
18
|
+
'passed': []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# TODO: Add validation logic
|
|
22
|
+
results['passed'].append('Placeholder validation passed')
|
|
23
|
+
|
|
24
|
+
return results
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def print_results(results: dict):
|
|
28
|
+
"""Pretty print results"""
|
|
29
|
+
print("\n🔍 Validation Results\n")
|
|
30
|
+
|
|
31
|
+
if results['errors']:
|
|
32
|
+
print(f"❌ Errors ({len(results['errors'])})")
|
|
33
|
+
for error in results['errors']:
|
|
34
|
+
print(f" - {error}")
|
|
35
|
+
|
|
36
|
+
if results['warnings']:
|
|
37
|
+
print(f"\n⚠️ Warnings ({len(results['warnings'])})")
|
|
38
|
+
for warning in results['warnings']:
|
|
39
|
+
print(f" - {warning}")
|
|
40
|
+
|
|
41
|
+
if results['passed']:
|
|
42
|
+
print(f"\n✅ Passed ({len(results['passed'])})")
|
|
43
|
+
for passed in results['passed']:
|
|
44
|
+
print(f" - {passed}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
if len(sys.argv) < 2:
|
|
49
|
+
print("Usage: python validate.py <project_path>")
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
project_path = sys.argv[1]
|
|
53
|
+
results = validate(project_path)
|
|
54
|
+
print_results(results)
|
|
55
|
+
|
|
56
|
+
sys.exit(1 if results['errors'] else 0)
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docker-patterns
|
|
3
|
+
description: Docker containerization principles and decision-making. Use when writing Dockerfiles, optimizing image size, configuring Docker Compose, securing containers, or troubleshooting container issues. Covers multi-stage builds, security hardening, orchestration patterns.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash
|
|
5
|
+
version: 1.0
|
|
6
|
+
priority: HIGH
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Docker Patterns - Container Excellence
|
|
10
|
+
|
|
11
|
+
> **Philosophy:** Containers should be **small, secure, and consistent** across all environments. Optimize for production from day one.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Core Principles
|
|
16
|
+
|
|
17
|
+
| Principle | Rule |
|
|
18
|
+
| ---------------- | ----------------------------------------------------- |
|
|
19
|
+
| **Immutable** | Build once, run anywhere - no runtime modifications |
|
|
20
|
+
| **Minimal** | Only include what's needed - smaller = faster + safer |
|
|
21
|
+
| **Secure** | Non-root by default, no secrets in layers |
|
|
22
|
+
| **Reproducible** | Pin versions, multi-stage for consistent builds |
|
|
23
|
+
| **Observable** | Health checks, structured logs, metrics endpoints |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Image Base Selection
|
|
28
|
+
|
|
29
|
+
| Use Case | Recommended Base | Size |
|
|
30
|
+
| ------------------------- | ------------------------- | ------ |
|
|
31
|
+
| **Node.js production** | `node:20-alpine` | ~50MB |
|
|
32
|
+
| **Minimal static binary** | `scratch` or `distroless` | <10MB |
|
|
33
|
+
| **Python production** | `python:3.12-slim` | ~45MB |
|
|
34
|
+
| **General purpose** | `alpine:3.19` | ~5MB |
|
|
35
|
+
| **Debugging needed** | `*-slim` variants | ~100MB |
|
|
36
|
+
|
|
37
|
+
> 🔴 **Avoid:** Full `node:20`, `python:3.12`, `ubuntu:latest` in production.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Multi-Stage Build Pattern
|
|
42
|
+
|
|
43
|
+
```dockerfile
|
|
44
|
+
# Stage 1: Dependencies (cached aggressively)
|
|
45
|
+
FROM node:20-alpine AS deps
|
|
46
|
+
WORKDIR /app
|
|
47
|
+
COPY package*.json ./
|
|
48
|
+
RUN npm ci --only=production && npm cache clean --force
|
|
49
|
+
|
|
50
|
+
# Stage 2: Build (includes dev dependencies)
|
|
51
|
+
FROM node:20-alpine AS build
|
|
52
|
+
WORKDIR /app
|
|
53
|
+
COPY package*.json ./
|
|
54
|
+
RUN npm ci
|
|
55
|
+
COPY . .
|
|
56
|
+
RUN npm run build && npm prune --production
|
|
57
|
+
|
|
58
|
+
# Stage 3: Runtime (minimal)
|
|
59
|
+
FROM node:20-alpine AS runtime
|
|
60
|
+
RUN addgroup -g 1001 -S app && adduser -S app -u 1001
|
|
61
|
+
WORKDIR /app
|
|
62
|
+
COPY --from=deps --chown=app:app /app/node_modules ./node_modules
|
|
63
|
+
COPY --from=build --chown=app:app /app/dist ./dist
|
|
64
|
+
USER app
|
|
65
|
+
EXPOSE 3000
|
|
66
|
+
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
|
|
67
|
+
CMD curl -f http://localhost:3000/health || exit 1
|
|
68
|
+
CMD ["node", "dist/index.js"]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Layer Optimization Rules
|
|
74
|
+
|
|
75
|
+
| Rule | Why |
|
|
76
|
+
| ----------------------------- | ---------------------------------------- |
|
|
77
|
+
| **COPY package.json first** | Deps layer cached until deps change |
|
|
78
|
+
| **Combine RUN commands** | Fewer layers = smaller image |
|
|
79
|
+
| **Clean in same RUN** | `npm ci && npm cache clean` not separate |
|
|
80
|
+
| **Order by change frequency** | Least changing → Most changing |
|
|
81
|
+
| **.dockerignore complete** | Exclude node_modules, .git, logs |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Security Hardening Checklist
|
|
86
|
+
|
|
87
|
+
| Security Rule | Implementation |
|
|
88
|
+
| ---------------------------- | ----------------------------------- |
|
|
89
|
+
| **Non-root user** | `adduser` + `USER 1001` |
|
|
90
|
+
| **Pin base image versions** | `node:20.10.0-alpine`, not `latest` |
|
|
91
|
+
| **No secrets in Dockerfile** | Use build secrets or runtime env |
|
|
92
|
+
| **Minimal packages** | No vim, curl unless needed |
|
|
93
|
+
| **Read-only filesystem** | `--read-only` runtime flag |
|
|
94
|
+
| **Scan for vulnerabilities** | `docker scout`, `trivy` |
|
|
95
|
+
|
|
96
|
+
### Build Secrets Pattern (BuildKit)
|
|
97
|
+
|
|
98
|
+
```dockerfile
|
|
99
|
+
# syntax=docker/dockerfile:1
|
|
100
|
+
FROM alpine
|
|
101
|
+
RUN --mount=type=secret,id=api_key \
|
|
102
|
+
API_KEY=$(cat /run/secrets/api_key) && \
|
|
103
|
+
# Use API_KEY - it won't be in final layer
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Docker Compose Patterns
|
|
109
|
+
|
|
110
|
+
### Production-Ready Service
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
services:
|
|
114
|
+
app:
|
|
115
|
+
build:
|
|
116
|
+
context: .
|
|
117
|
+
target: runtime
|
|
118
|
+
depends_on:
|
|
119
|
+
db:
|
|
120
|
+
condition: service_healthy
|
|
121
|
+
deploy:
|
|
122
|
+
resources:
|
|
123
|
+
limits:
|
|
124
|
+
cpus: "1.0"
|
|
125
|
+
memory: 512M
|
|
126
|
+
healthcheck:
|
|
127
|
+
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
|
128
|
+
interval: 30s
|
|
129
|
+
timeout: 10s
|
|
130
|
+
retries: 3
|
|
131
|
+
networks:
|
|
132
|
+
- backend
|
|
133
|
+
restart: unless-stopped
|
|
134
|
+
|
|
135
|
+
db:
|
|
136
|
+
image: postgres:16-alpine
|
|
137
|
+
environment:
|
|
138
|
+
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
|
|
139
|
+
secrets:
|
|
140
|
+
- db_password
|
|
141
|
+
volumes:
|
|
142
|
+
- postgres_data:/var/lib/postgresql/data
|
|
143
|
+
healthcheck:
|
|
144
|
+
test: ["CMD", "pg_isready"]
|
|
145
|
+
interval: 10s
|
|
146
|
+
|
|
147
|
+
networks:
|
|
148
|
+
backend:
|
|
149
|
+
driver: bridge
|
|
150
|
+
|
|
151
|
+
volumes:
|
|
152
|
+
postgres_data:
|
|
153
|
+
|
|
154
|
+
secrets:
|
|
155
|
+
db_password:
|
|
156
|
+
file: ./secrets/db_password.txt
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Decision Trees
|
|
162
|
+
|
|
163
|
+
### When to Use Multi-Stage?
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Is build output smaller than source?
|
|
167
|
+
├── Yes → Use multi-stage (most apps)
|
|
168
|
+
└── No → Single stage might be OK
|
|
169
|
+
└── Still need build tools at runtime?
|
|
170
|
+
├── Yes → Single stage
|
|
171
|
+
└── No → Multi-stage anyway for security
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Which Base Image?
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
Need shell for debugging?
|
|
178
|
+
├── Yes → alpine or slim variants
|
|
179
|
+
└── No → Do you need libc?
|
|
180
|
+
├── Yes → distroless
|
|
181
|
+
└── No → scratch (Go, Rust static binaries)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Anti-Patterns (DON'T)
|
|
187
|
+
|
|
188
|
+
| ❌ Anti-Pattern | ✅ Correct Approach |
|
|
189
|
+
| ------------------------------ | ----------------------------------------- |
|
|
190
|
+
| `FROM node:latest` | `FROM node:20.10.0-alpine` |
|
|
191
|
+
| `RUN npm install` (not ci) | `RUN npm ci --only=production` |
|
|
192
|
+
| Running as root | Create user, `USER 1001` |
|
|
193
|
+
| Secrets in ENV | Build secrets or external secrets manager |
|
|
194
|
+
| `COPY . .` before package.json | Copy package.json first for caching |
|
|
195
|
+
| Separate RUN for cleanup | Clean in same RUN command |
|
|
196
|
+
| No .dockerignore | Comprehensive .dockerignore |
|
|
197
|
+
| No health checks | HEALTHCHECK instruction |
|
|
198
|
+
| 1GB+ images | Multi-stage + alpine base |
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Common Issues & Fixes
|
|
203
|
+
|
|
204
|
+
| Issue | Cause | Fix |
|
|
205
|
+
| -------------------------- | ------------------------ | --------------------------------------- |
|
|
206
|
+
| **Slow builds** | Cache invalidation | COPY package.json before source |
|
|
207
|
+
| **Large images** | Build tools in prod | Multi-stage, distroless |
|
|
208
|
+
| **Permission errors** | Root ownership | `--chown` in COPY, proper USER |
|
|
209
|
+
| **Container won't start** | CMD syntax error | Use exec form `["node", "app.js"]` |
|
|
210
|
+
| **Can't connect services** | Network misconfiguration | Custom networks, service names as hosts |
|
|
211
|
+
| **Data lost on restart** | No volume | Named volumes for persistence |
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 🔴 Self-Check Before Completing
|
|
216
|
+
|
|
217
|
+
| Check | Question |
|
|
218
|
+
| ----------------------- | ------------------------------------------ |
|
|
219
|
+
| ✅ **Multi-stage?** | Is build separated from runtime? |
|
|
220
|
+
| ✅ **Non-root?** | Container runs as non-root user? |
|
|
221
|
+
| ✅ **Pinned versions?** | Base image and deps have explicit version? |
|
|
222
|
+
| ✅ **Health check?** | HEALTHCHECK or compose healthcheck? |
|
|
223
|
+
| ✅ **Secrets safe?** | No secrets in layers or ENV? |
|
|
224
|
+
| ✅ **Image size?** | Under 500MB for typical apps? |
|
|
225
|
+
| ✅ **.dockerignore?** | Excludes node_modules, .git, logs? |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Related Skills
|
|
230
|
+
|
|
231
|
+
| Need | Skill |
|
|
232
|
+
| --------------------- | ------------------------- |
|
|
233
|
+
| CI/CD pipelines | `github-actions` (future) |
|
|
234
|
+
| Kubernetes deployment | `kubernetes-patterns` |
|
|
235
|
+
| Server management | `server-management` |
|
|
236
|
+
| Deployment workflows | `deployment-procedures` |
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
> **Remember:** A well-built container is invisible infrastructure. If you're debugging container issues in production, something went wrong at build time.
|