swe-workflow-skills 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 +144 -0
- package/VERSION +1 -0
- package/bin/cli.mjs +44 -0
- package/catalog.json +225 -0
- package/commands/role.md +34 -0
- package/hooks/session-start.mjs +118 -0
- package/install.mjs +318 -0
- package/package.json +47 -0
- package/roles.json +194 -0
- package/scripts/resolve.mjs +296 -0
- package/skills/accessibility-design/SKILL.md +128 -0
- package/skills/accessibility-design/evals/evals.json +51 -0
- package/skills/accessibility-design/references/accessibility-patterns.md +321 -0
- package/skills/api-design/SKILL.md +144 -0
- package/skills/api-design/evals/evals.json +48 -0
- package/skills/api-design/references/rest-conventions.md +147 -0
- package/skills/api-design/templates/api-spec.md +156 -0
- package/skills/architecture-design/SKILL.md +86 -0
- package/skills/architecture-design/evals/evals.json +44 -0
- package/skills/architecture-design/references/clean-architecture.md +147 -0
- package/skills/architecture-design/references/component-principles.md +129 -0
- package/skills/architecture-design/references/principles.md +81 -0
- package/skills/architecture-design/references/solid-principles.md +106 -0
- package/skills/architecture-design/templates/adr.md +63 -0
- package/skills/architecture-documentation/SKILL.md +126 -0
- package/skills/architecture-documentation/evals/evals.json +44 -0
- package/skills/architecture-documentation/references/abstraction-levels.md +91 -0
- package/skills/architecture-documentation/references/diagram-tooling.md +141 -0
- package/skills/architecture-documentation/templates/architecture-doc.md +171 -0
- package/skills/bug-investigating/SKILL.md +133 -0
- package/skills/bug-investigating/evals/evals.json +56 -0
- package/skills/bug-investigating/references/common-bugs.md +62 -0
- package/skills/bug-investigating/references/debugging-patterns.md +94 -0
- package/skills/cicd-pipeline/SKILL.md +87 -0
- package/skills/cicd-pipeline/evals/evals.json +34 -0
- package/skills/cicd-pipeline/references/pipeline-patterns.md +206 -0
- package/skills/cicd-pipeline/templates/github-actions.md +206 -0
- package/skills/code-reviewing/SKILL.md +92 -0
- package/skills/code-reviewing/evals/evals.json +62 -0
- package/skills/code-reviewing/references/error-handling.md +108 -0
- package/skills/code-reviewing/references/review-checklist.md +144 -0
- package/skills/configuration-strategy/SKILL.md +109 -0
- package/skills/configuration-strategy/evals/evals.json +41 -0
- package/skills/configuration-strategy/references/config-patterns.md +161 -0
- package/skills/containerization/SKILL.md +90 -0
- package/skills/containerization/evals/evals.json +36 -0
- package/skills/containerization/references/dockerfile-patterns.md +168 -0
- package/skills/containerization/templates/dockerfile.md +154 -0
- package/skills/data-modeling/SKILL.md +83 -0
- package/skills/data-modeling/evals/evals.json +43 -0
- package/skills/data-modeling/references/conventions.md +57 -0
- package/skills/data-modeling/templates/schema.md +120 -0
- package/skills/dependency-impact-analysis/SKILL.md +113 -0
- package/skills/dependency-impact-analysis/evals/evals.json +41 -0
- package/skills/dependency-impact-analysis/references/impact-patterns.md +150 -0
- package/skills/dependency-management/SKILL.md +161 -0
- package/skills/dependency-management/evals/evals.json +48 -0
- package/skills/dependency-management/references/evaluation-checklist.md +127 -0
- package/skills/deployment-checklist/SKILL.md +132 -0
- package/skills/deployment-checklist/evals/evals.json +58 -0
- package/skills/deployment-checklist/references/pre-deploy-gates.md +91 -0
- package/skills/deployment-repo/SKILL.md +190 -0
- package/skills/deployment-repo/evals/evals.json +44 -0
- package/skills/deployment-repo/references/deployment-repo-patterns.md +258 -0
- package/skills/deployment-repo/references/version-compatibility.md +227 -0
- package/skills/deployment-repo/templates/deployment-repo-structure.md +226 -0
- package/skills/effort-estimation/SKILL.md +95 -0
- package/skills/effort-estimation/evals/evals.json +32 -0
- package/skills/effort-estimation/references/estimation-methods.md +154 -0
- package/skills/feature-planning/SKILL.md +84 -0
- package/skills/feature-planning/evals/evals.json +44 -0
- package/skills/feature-planning/templates/plan.md +55 -0
- package/skills/feature-planning/templates/task.md +26 -0
- package/skills/frontend-architecture/SKILL.md +154 -0
- package/skills/frontend-architecture/evals/evals.json +34 -0
- package/skills/frontend-architecture/references/component-patterns.md +264 -0
- package/skills/frontend-architecture/templates/folder-structure.md +203 -0
- package/skills/git-workflow/SKILL.md +127 -0
- package/skills/git-workflow/evals/evals.json +44 -0
- package/skills/git-workflow/references/conventions.md +142 -0
- package/skills/git-workflow/templates/pull-request.md +57 -0
- package/skills/gitops-delivery/SKILL.md +319 -0
- package/skills/gitops-delivery/evals/evals.json +44 -0
- package/skills/gitops-delivery/references/gitops-patterns.md +478 -0
- package/skills/gitops-delivery/templates/gitops-config.md +196 -0
- package/skills/incident-response/SKILL.md +130 -0
- package/skills/incident-response/evals/evals.json +55 -0
- package/skills/incident-response/references/communication-templates.md +134 -0
- package/skills/incident-response/references/severity-levels.md +77 -0
- package/skills/incident-response/templates/incident-timeline.md +57 -0
- package/skills/infrastructure-as-code/SKILL.md +86 -0
- package/skills/infrastructure-as-code/evals/evals.json +33 -0
- package/skills/infrastructure-as-code/references/iac-patterns.md +179 -0
- package/skills/infrastructure-as-code/templates/terraform-module.md +158 -0
- package/skills/metrics-and-okrs/SKILL.md +113 -0
- package/skills/metrics-and-okrs/evals/evals.json +33 -0
- package/skills/metrics-and-okrs/references/metric-catalog.md +90 -0
- package/skills/metrics-and-okrs/templates/okr-document.md +61 -0
- package/skills/ml-experiment-tracking/SKILL.md +96 -0
- package/skills/ml-experiment-tracking/evals/evals.json +32 -0
- package/skills/ml-experiment-tracking/references/tracking-tools.md +127 -0
- package/skills/ml-model-deployment/SKILL.md +106 -0
- package/skills/ml-model-deployment/evals/evals.json +34 -0
- package/skills/ml-model-deployment/references/serving-patterns.md +162 -0
- package/skills/ml-pipeline-design/SKILL.md +162 -0
- package/skills/ml-pipeline-design/evals/evals.json +34 -0
- package/skills/ml-pipeline-design/references/pipeline-components.md +174 -0
- package/skills/observability-design/SKILL.md +162 -0
- package/skills/observability-design/evals/evals.json +52 -0
- package/skills/observability-design/references/logging-patterns.md +229 -0
- package/skills/observability-design/references/slo-framework.md +151 -0
- package/skills/observability-design/templates/slo-document.md +80 -0
- package/skills/performance-optimization/SKILL.md +83 -0
- package/skills/performance-optimization/evals/evals.json +47 -0
- package/skills/performance-optimization/references/bottleneck-patterns.md +256 -0
- package/skills/performance-optimization/references/concurrency.md +101 -0
- package/skills/prd-writing/SKILL.md +109 -0
- package/skills/prd-writing/evals/evals.json +33 -0
- package/skills/prd-writing/references/prd-examples.md +132 -0
- package/skills/prd-writing/templates/prd.md +71 -0
- package/skills/prd-writing/templates/rfc.md +79 -0
- package/skills/project-documentation/SKILL.md +104 -0
- package/skills/project-documentation/evals/evals.json +48 -0
- package/skills/project-documentation/references/contributing-guide.md +100 -0
- package/skills/project-documentation/templates/changelog.md +59 -0
- package/skills/project-documentation/templates/readme.md +121 -0
- package/skills/project-proposal/SKILL.md +90 -0
- package/skills/project-proposal/evals/evals.json +31 -0
- package/skills/project-proposal/references/proposal-examples.md +140 -0
- package/skills/project-proposal/templates/proposal.md +76 -0
- package/skills/project-review/SKILL.md +111 -0
- package/skills/project-review/evals/evals.json +42 -0
- package/skills/refactoring/SKILL.md +90 -0
- package/skills/refactoring/evals/evals.json +44 -0
- package/skills/refactoring/references/transformations.md +132 -0
- package/skills/retrospective/SKILL.md +157 -0
- package/skills/retrospective/evals/evals.json +34 -0
- package/skills/retrospective/references/facilitation-guide.md +130 -0
- package/skills/retrospective/templates/post-mortem.md +121 -0
- package/skills/rollback-strategy/SKILL.md +116 -0
- package/skills/rollback-strategy/evals/evals.json +55 -0
- package/skills/rollback-strategy/references/rollback-patterns.md +125 -0
- package/skills/rollback-strategy/templates/rollback-plan.md +69 -0
- package/skills/security-audit/SKILL.md +146 -0
- package/skills/security-audit/evals/evals.json +66 -0
- package/skills/security-audit/references/owasp-top-10.md +167 -0
- package/skills/security-audit/templates/security-report.md +79 -0
- package/skills/skill-router/SKILL.md +171 -0
- package/skills/skill-router/evals/evals.json +39 -0
- package/skills/strategic-review/SKILL.md +106 -0
- package/skills/strategic-review/evals/evals.json +42 -0
- package/skills/strategic-review/templates/full-review-prompt.md +84 -0
- package/skills/tdd-workflow/SKILL.md +147 -0
- package/skills/tdd-workflow/evals/evals.json +58 -0
- package/skills/tdd-workflow/references/test-quality.md +71 -0
- package/skills/technical-debt-review/SKILL.md +113 -0
- package/skills/technical-debt-review/evals/evals.json +41 -0
- package/skills/technical-debt-review/references/debt-taxonomy.md +124 -0
- package/skills/technical-debt-review/templates/debt-audit.md +85 -0
- package/skills/test-data-strategy/SKILL.md +129 -0
- package/skills/test-data-strategy/evals/evals.json +49 -0
- package/skills/test-data-strategy/references/data-generation-patterns.md +341 -0
- package/skills/test-suite-design/SKILL.md +137 -0
- package/skills/test-suite-design/evals/evals.json +69 -0
- package/skills/test-suite-design/references/test-infrastructure.md +175 -0
- package/skills/test-suite-design/references/testing-pyramid.md +140 -0
- package/skills/ui-ux-design/SKILL.md +117 -0
- package/skills/ui-ux-design/evals/evals.json +35 -0
- package/skills/ui-ux-design/references/interaction-patterns.md +145 -0
- package/skills/ui-ux-design/templates/screen-spec.md +97 -0
- package/skills/verification-before-completion/SKILL.md +85 -0
- package/skills/verification-before-completion/evals/evals.json +53 -0
- package/skills/writing-skills/SKILL.md +87 -0
- package/skills/writing-skills/evals/evals.json +41 -0
- package/skills/writing-skills/references/pressure-testing.md +69 -0
- package/uninstall.mjs +182 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Dockerfile Patterns
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- Node.js patterns
|
|
5
|
+
- Python patterns
|
|
6
|
+
- Go patterns
|
|
7
|
+
- Docker Compose patterns
|
|
8
|
+
- Common anti-patterns
|
|
9
|
+
|
|
10
|
+
## Node.js Multi-Stage Build
|
|
11
|
+
|
|
12
|
+
```dockerfile
|
|
13
|
+
# Stage 1: Build
|
|
14
|
+
FROM node:20.11-alpine AS builder
|
|
15
|
+
WORKDIR /app
|
|
16
|
+
COPY package.json package-lock.json ./
|
|
17
|
+
RUN npm ci --ignore-scripts
|
|
18
|
+
COPY . .
|
|
19
|
+
RUN npm run build
|
|
20
|
+
|
|
21
|
+
# Stage 2: Production
|
|
22
|
+
FROM node:20.11-alpine AS production
|
|
23
|
+
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
|
|
24
|
+
WORKDIR /app
|
|
25
|
+
COPY --from=builder /app/dist ./dist
|
|
26
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
27
|
+
COPY --from=builder /app/package.json ./
|
|
28
|
+
USER appuser
|
|
29
|
+
EXPOSE 3000
|
|
30
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
|
|
31
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
|
|
32
|
+
CMD ["node", "dist/main.js"]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Python Multi-Stage Build
|
|
36
|
+
|
|
37
|
+
```dockerfile
|
|
38
|
+
# Stage 1: Build
|
|
39
|
+
FROM python:3.12-slim AS builder
|
|
40
|
+
WORKDIR /app
|
|
41
|
+
RUN pip install --no-cache-dir poetry
|
|
42
|
+
COPY pyproject.toml poetry.lock ./
|
|
43
|
+
RUN poetry export -f requirements.txt -o requirements.txt --without-hashes
|
|
44
|
+
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
|
|
45
|
+
COPY . .
|
|
46
|
+
|
|
47
|
+
# Stage 2: Production
|
|
48
|
+
FROM python:3.12-slim AS production
|
|
49
|
+
RUN groupadd -r appgroup && useradd -r -g appgroup -d /app appuser
|
|
50
|
+
WORKDIR /app
|
|
51
|
+
COPY --from=builder /install /usr/local
|
|
52
|
+
COPY --from=builder /app .
|
|
53
|
+
USER appuser
|
|
54
|
+
EXPOSE 8000
|
|
55
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=15s \
|
|
56
|
+
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
|
|
57
|
+
CMD ["gunicorn", "app:create_app()", "--bind", "0.0.0.0:8000", "--workers", "4"]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Go (Distroless)
|
|
61
|
+
|
|
62
|
+
```dockerfile
|
|
63
|
+
FROM golang:1.22-alpine AS builder
|
|
64
|
+
WORKDIR /app
|
|
65
|
+
COPY go.mod go.sum ./
|
|
66
|
+
RUN go mod download
|
|
67
|
+
COPY . .
|
|
68
|
+
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /server ./cmd/server
|
|
69
|
+
|
|
70
|
+
FROM gcr.io/distroless/static-debian12
|
|
71
|
+
COPY --from=builder /server /server
|
|
72
|
+
USER nonroot:nonroot
|
|
73
|
+
EXPOSE 8080
|
|
74
|
+
ENTRYPOINT ["/server"]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Go produces a static binary — the final image can be distroless (no shell, no package manager) for a minimal attack surface. Image size: ~10-20 MB.
|
|
78
|
+
|
|
79
|
+
## Docker Compose for Local Development
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
services:
|
|
83
|
+
app:
|
|
84
|
+
build:
|
|
85
|
+
context: .
|
|
86
|
+
target: builder # Use the build stage for development
|
|
87
|
+
volumes:
|
|
88
|
+
- .:/app
|
|
89
|
+
- /app/node_modules # Prevent overwriting container's node_modules
|
|
90
|
+
ports:
|
|
91
|
+
- "3000:3000"
|
|
92
|
+
environment:
|
|
93
|
+
- NODE_ENV=development
|
|
94
|
+
- DATABASE_URL=postgresql://postgres:postgres@db:5432/appdb
|
|
95
|
+
- REDIS_URL=redis://redis:6379
|
|
96
|
+
depends_on:
|
|
97
|
+
db:
|
|
98
|
+
condition: service_healthy
|
|
99
|
+
redis:
|
|
100
|
+
condition: service_healthy
|
|
101
|
+
command: npm run dev # Override CMD for hot-reload
|
|
102
|
+
|
|
103
|
+
db:
|
|
104
|
+
image: postgres:16-alpine
|
|
105
|
+
environment:
|
|
106
|
+
POSTGRES_USER: postgres
|
|
107
|
+
POSTGRES_PASSWORD: postgres
|
|
108
|
+
POSTGRES_DB: appdb
|
|
109
|
+
volumes:
|
|
110
|
+
- pgdata:/var/lib/postgresql/data
|
|
111
|
+
ports:
|
|
112
|
+
- "5432:5432"
|
|
113
|
+
healthcheck:
|
|
114
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
115
|
+
interval: 5s
|
|
116
|
+
timeout: 3s
|
|
117
|
+
retries: 5
|
|
118
|
+
|
|
119
|
+
redis:
|
|
120
|
+
image: redis:7-alpine
|
|
121
|
+
ports:
|
|
122
|
+
- "6379:6379"
|
|
123
|
+
healthcheck:
|
|
124
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
125
|
+
interval: 5s
|
|
126
|
+
timeout: 3s
|
|
127
|
+
retries: 5
|
|
128
|
+
|
|
129
|
+
volumes:
|
|
130
|
+
pgdata:
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## .dockerignore Template
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
.git
|
|
137
|
+
.github
|
|
138
|
+
node_modules
|
|
139
|
+
dist
|
|
140
|
+
*.log
|
|
141
|
+
.env
|
|
142
|
+
.env.*
|
|
143
|
+
!.env.example
|
|
144
|
+
docker-compose*.yml
|
|
145
|
+
Dockerfile*
|
|
146
|
+
.dockerignore
|
|
147
|
+
README.md
|
|
148
|
+
docs/
|
|
149
|
+
tests/
|
|
150
|
+
__pycache__
|
|
151
|
+
*.pyc
|
|
152
|
+
.pytest_cache
|
|
153
|
+
.coverage
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Common Anti-patterns
|
|
157
|
+
|
|
158
|
+
**Running as root**: Every container should run as a non-root user. If the base image runs as root by default, create a user.
|
|
159
|
+
|
|
160
|
+
**Using `latest` tag**: Tags can be overwritten. Pin to a specific version or SHA digest for reproducibility.
|
|
161
|
+
|
|
162
|
+
**Installing dev dependencies in production**: Use multi-stage builds. Keep test frameworks, linters, and build tools out of the final image.
|
|
163
|
+
|
|
164
|
+
**Copying everything before installing deps**: This busts the Docker layer cache on every code change. Copy dependency manifests first, install, then copy application code.
|
|
165
|
+
|
|
166
|
+
**Large images**: A Node.js app shouldn't be 1.5 GB. Use Alpine bases, multi-stage builds, and .dockerignore. Target: <200 MB for most apps.
|
|
167
|
+
|
|
168
|
+
**Secrets in build args**: Build args are visible in `docker history`. Use runtime env vars or mounted secrets for sensitive data. Never `ARG DB_PASSWORD`.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Dockerfile Templates
|
|
2
|
+
|
|
3
|
+
Copy the appropriate template, then replace placeholder values (`APP_NAME`, port numbers, etc.).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Node.js — Multi-Stage
|
|
8
|
+
|
|
9
|
+
```dockerfile
|
|
10
|
+
# syntax=docker/dockerfile:1
|
|
11
|
+
FROM node:20.11-alpine3.19 AS deps
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY package.json package-lock.json ./
|
|
14
|
+
RUN npm ci --omit=dev
|
|
15
|
+
|
|
16
|
+
FROM node:20.11-alpine3.19 AS build
|
|
17
|
+
WORKDIR /app
|
|
18
|
+
COPY package.json package-lock.json ./
|
|
19
|
+
RUN npm ci
|
|
20
|
+
COPY . .
|
|
21
|
+
RUN npm run build
|
|
22
|
+
|
|
23
|
+
FROM node:20.11-alpine3.19 AS production
|
|
24
|
+
WORKDIR /app
|
|
25
|
+
ENV NODE_ENV=production
|
|
26
|
+
# Non-root user
|
|
27
|
+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
28
|
+
COPY --from=deps --chown=appuser:appgroup /app/node_modules ./node_modules
|
|
29
|
+
COPY --from=build --chown=appuser:appgroup /app/dist ./dist
|
|
30
|
+
USER appuser
|
|
31
|
+
EXPOSE 3000
|
|
32
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
33
|
+
CMD wget -qO- http://localhost:3000/health || exit 1
|
|
34
|
+
CMD ["node", "dist/index.js"]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Python — Multi-Stage
|
|
40
|
+
|
|
41
|
+
```dockerfile
|
|
42
|
+
# syntax=docker/dockerfile:1
|
|
43
|
+
FROM python:3.12-slim AS build
|
|
44
|
+
WORKDIR /app
|
|
45
|
+
COPY requirements.txt .
|
|
46
|
+
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
|
|
47
|
+
|
|
48
|
+
FROM python:3.12-slim AS production
|
|
49
|
+
WORKDIR /app
|
|
50
|
+
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
|
|
51
|
+
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
|
|
52
|
+
COPY --from=build --chown=appuser:appgroup /install /usr/local
|
|
53
|
+
COPY --chown=appuser:appgroup . .
|
|
54
|
+
USER appuser
|
|
55
|
+
EXPOSE 8000
|
|
56
|
+
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
57
|
+
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"
|
|
58
|
+
CMD ["python", "-m", "gunicorn", "app.main:app", "--bind", "0.0.0.0:8000"]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Go — Binary (Minimal Runtime)
|
|
64
|
+
|
|
65
|
+
```dockerfile
|
|
66
|
+
# syntax=docker/dockerfile:1
|
|
67
|
+
FROM golang:1.22-alpine AS build
|
|
68
|
+
WORKDIR /app
|
|
69
|
+
COPY go.mod go.sum ./
|
|
70
|
+
RUN go mod download
|
|
71
|
+
COPY . .
|
|
72
|
+
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server ./cmd/server
|
|
73
|
+
|
|
74
|
+
FROM gcr.io/distroless/static-debian12 AS production
|
|
75
|
+
WORKDIR /app
|
|
76
|
+
# distroless runs as nonroot (uid 65532) by default
|
|
77
|
+
COPY --from=build /app/server .
|
|
78
|
+
EXPOSE 8080
|
|
79
|
+
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
80
|
+
CMD ["/app/server", "healthcheck"]
|
|
81
|
+
ENTRYPOINT ["/app/server"]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## .dockerignore
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
.git
|
|
90
|
+
.gitignore
|
|
91
|
+
*.md
|
|
92
|
+
.env*
|
|
93
|
+
node_modules/
|
|
94
|
+
dist/
|
|
95
|
+
build/
|
|
96
|
+
coverage/
|
|
97
|
+
**/*.test.*
|
|
98
|
+
**/*.spec.*
|
|
99
|
+
Dockerfile*
|
|
100
|
+
docker-compose*
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## docker-compose.yml — Local Development
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
services:
|
|
109
|
+
app:
|
|
110
|
+
build:
|
|
111
|
+
context: .
|
|
112
|
+
target: build # Use build stage for hot-reload; swap to production for prod-parity testing
|
|
113
|
+
ports:
|
|
114
|
+
- "3000:3000"
|
|
115
|
+
environment:
|
|
116
|
+
- NODE_ENV=development
|
|
117
|
+
- DATABASE_URL=postgres://app:secret@db:5432/appdb
|
|
118
|
+
- REDIS_URL=redis://cache:6379
|
|
119
|
+
volumes:
|
|
120
|
+
- .:/app # Hot-reload mount
|
|
121
|
+
- /app/node_modules # Prevent host node_modules overwrite
|
|
122
|
+
depends_on:
|
|
123
|
+
db:
|
|
124
|
+
condition: service_healthy
|
|
125
|
+
cache:
|
|
126
|
+
condition: service_started
|
|
127
|
+
|
|
128
|
+
db:
|
|
129
|
+
image: postgres:16-alpine
|
|
130
|
+
environment:
|
|
131
|
+
POSTGRES_DB: appdb
|
|
132
|
+
POSTGRES_USER: app
|
|
133
|
+
POSTGRES_PASSWORD: secret
|
|
134
|
+
volumes:
|
|
135
|
+
- db-data:/var/lib/postgresql/data
|
|
136
|
+
ports:
|
|
137
|
+
- "5432:5432" # Remove in production
|
|
138
|
+
healthcheck:
|
|
139
|
+
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
|
|
140
|
+
interval: 10s
|
|
141
|
+
timeout: 5s
|
|
142
|
+
retries: 5
|
|
143
|
+
|
|
144
|
+
cache:
|
|
145
|
+
image: redis:7-alpine
|
|
146
|
+
volumes:
|
|
147
|
+
- cache-data:/data
|
|
148
|
+
|
|
149
|
+
volumes:
|
|
150
|
+
db-data:
|
|
151
|
+
cache-data:
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> **Key rules:** Never put real secrets in docker-compose.yml. Use a `.env` file (git-ignored) or a secrets manager. The `.env.example` file documents required variables without values.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: data-modeling
|
|
3
|
+
description: "Design database schemas, relationships, indexes, and migration strategies — relational and document stores. Triggers: data model, schema design, ER diagram, database schema, table design, foreign key, index strategy, normalization, denormalization, migration plan, document model, partition key."
|
|
4
|
+
model: sonnet
|
|
5
|
+
allowed-tools: Read, Grep, Glob, Write, Edit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Data Modeling
|
|
9
|
+
|
|
10
|
+
Guide the user through designing data models that are normalized, consistent, and evolvable. Good data models make the right things easy and the wrong things hard.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
### Step 1: Understand the Domain
|
|
15
|
+
|
|
16
|
+
Before touching schemas, understand the business domain:
|
|
17
|
+
|
|
18
|
+
- **What are the core entities?** (nouns in the requirements: User, Order, Product)
|
|
19
|
+
- **What are the relationships?** (verbs: User *places* Order, Order *contains* Products)
|
|
20
|
+
- **What are the cardinalities?** (one-to-one, one-to-many, many-to-many)
|
|
21
|
+
- **What are the access patterns?** (how will the data be queried most often)
|
|
22
|
+
- **What are the invariants?** (rules that must always hold: "an order must have at least one item")
|
|
23
|
+
|
|
24
|
+
If the user describes a feature rather than a domain, extract the entities from the feature description first.
|
|
25
|
+
|
|
26
|
+
### Step 2: Design the Conceptual Model
|
|
27
|
+
|
|
28
|
+
Produce an entity-relationship description listing:
|
|
29
|
+
|
|
30
|
+
- Each entity with its key attributes
|
|
31
|
+
- Relationships with cardinality (1:1, 1:N, M:N)
|
|
32
|
+
- Business rules that constrain the model
|
|
33
|
+
|
|
34
|
+
Present this as a structured list or ASCII diagram. Don't jump to SQL yet — validate the conceptual model with the user first.
|
|
35
|
+
|
|
36
|
+
### Step 3: Apply Normalization
|
|
37
|
+
|
|
38
|
+
Design tables following normalization principles:
|
|
39
|
+
|
|
40
|
+
- **1NF**: No repeating groups; every column holds atomic values
|
|
41
|
+
- **2NF**: Every non-key column depends on the whole primary key
|
|
42
|
+
- **3NF**: No transitive dependencies (non-key → non-key)
|
|
43
|
+
|
|
44
|
+
Denormalize only with explicit justification (specific read performance requirement with measured data). Document every denormalization decision and the access pattern it serves.
|
|
45
|
+
|
|
46
|
+
### Step 4: Define the Physical Schema
|
|
47
|
+
|
|
48
|
+
Produce SQL DDL or ORM model definitions. For each table include:
|
|
49
|
+
|
|
50
|
+
- Primary key strategy (auto-increment, UUID, ULID — justify the choice)
|
|
51
|
+
- Foreign keys with ON DELETE/ON UPDATE behavior
|
|
52
|
+
- Indexes based on identified access patterns
|
|
53
|
+
- Constraints (NOT NULL, UNIQUE, CHECK) that enforce business rules
|
|
54
|
+
- Timestamps (created_at, updated_at) as appropriate
|
|
55
|
+
|
|
56
|
+
Use [templates/schema.md](templates/schema.md) as a starting point for table DDL, index naming, enum patterns, and migration file structure.
|
|
57
|
+
|
|
58
|
+
### Step 5: Plan the Migration
|
|
59
|
+
|
|
60
|
+
If modifying an existing schema:
|
|
61
|
+
|
|
62
|
+
- **Backwards-compatible changes**: Add columns with defaults, add tables, add indexes
|
|
63
|
+
- **Breaking changes**: Require a migration strategy (expand-contract pattern)
|
|
64
|
+
- **Data backfills**: Script them, don't do them manually
|
|
65
|
+
|
|
66
|
+
Produce migration files appropriate to the ORM/framework in use. Each migration should be independently reversible.
|
|
67
|
+
|
|
68
|
+
### Step 6: Validate
|
|
69
|
+
|
|
70
|
+
Cross-check the schema against:
|
|
71
|
+
|
|
72
|
+
- [ ] Every acceptance criterion from the feature plan can be served by the schema
|
|
73
|
+
- [ ] Every identified access pattern has an appropriate index
|
|
74
|
+
- [ ] Every business invariant is enforced by constraints
|
|
75
|
+
- [ ] No data can be orphaned (foreign keys and cascades are correct)
|
|
76
|
+
- [ ] The migration is reversible
|
|
77
|
+
|
|
78
|
+
## Principles Applied
|
|
79
|
+
|
|
80
|
+
- **DRY**: Single source of truth for each piece of data
|
|
81
|
+
- **KISS**: Start normalized; denormalize only when measured performance demands it
|
|
82
|
+
- **Functional Independence**: Each table represents one concept
|
|
83
|
+
- **YAGNI**: Don't add columns or tables "just in case"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "data-modeling",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "I'm building an e-commerce platform and need to design the schema for products, categories, orders, and inventory. Products can belong to multiple categories. We're using PostgreSQL with Django ORM. Estimated scale: 10K products, 1K orders/day.",
|
|
7
|
+
"expected_output": "Should start with conceptual model (entities + relationships), then produce normalized schema with proper foreign keys, indexes for common queries, and Django model definitions.",
|
|
8
|
+
"assertions": [
|
|
9
|
+
"Identifies M:N relationship between products and categories",
|
|
10
|
+
"Creates a join table for product-category relationship",
|
|
11
|
+
"Schema is at least 3NF normalized",
|
|
12
|
+
"Includes indexes for common access patterns (order lookup by user, product search)",
|
|
13
|
+
"Foreign keys have explicit ON DELETE behavior",
|
|
14
|
+
"Includes created_at/updated_at timestamps",
|
|
15
|
+
"Validates schema against likely access patterns"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": 2,
|
|
20
|
+
"prompt": "I need to add a comments feature to our blog. Users can comment on posts and reply to other comments. We need to track who edited comments and when. Using Prisma with PostgreSQL.",
|
|
21
|
+
"expected_output": "Should model the self-referential relationship for threaded comments, include audit fields, and produce Prisma schema.",
|
|
22
|
+
"assertions": [
|
|
23
|
+
"Models the self-referential parent_comment_id relationship",
|
|
24
|
+
"Includes ON DELETE strategy for nested comments",
|
|
25
|
+
"Tracks edit history (edited_at or separate edit_history table)",
|
|
26
|
+
"Produces Prisma schema syntax, not raw SQL",
|
|
27
|
+
"Considers soft delete for comment moderation"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": 3,
|
|
32
|
+
"prompt": "We need to rename our 'username' column to 'display_name' in the users table. We have 2M users and the column is used in about 15 places in the codebase. We can't have downtime. How should I approach this?",
|
|
33
|
+
"expected_output": "Should recommend the expand-contract migration pattern, not a simple column rename. Should produce multiple migration steps with deployment coordination.",
|
|
34
|
+
"assertions": [
|
|
35
|
+
"Does NOT suggest a simple ALTER TABLE RENAME",
|
|
36
|
+
"Recommends expand-contract (add new column, dual-write, backfill, cut over, drop old)",
|
|
37
|
+
"Addresses the zero-downtime requirement explicitly",
|
|
38
|
+
"Warns about table locking on 2M rows",
|
|
39
|
+
"Produces reversible migration steps"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Data Modeling Conventions
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- Naming conventions
|
|
5
|
+
- Primary key strategies
|
|
6
|
+
- Common column types
|
|
7
|
+
- Index naming
|
|
8
|
+
- Migration best practices
|
|
9
|
+
|
|
10
|
+
## Naming Conventions
|
|
11
|
+
|
|
12
|
+
- **Tables**: plural, snake_case (`users`, `order_items`, `payment_methods`)
|
|
13
|
+
- **Columns**: singular, snake_case (`email`, `created_at`, `user_id`)
|
|
14
|
+
- **Foreign keys**: `{referenced_table_singular}_id` (e.g., `user_id`, `order_id`)
|
|
15
|
+
- **Join tables**: alphabetical concatenation (`product_tags`, `role_users`)
|
|
16
|
+
- **Boolean columns**: prefix with `is_` or `has_` (`is_active`, `has_verified_email`)
|
|
17
|
+
- **Timestamps**: suffix with `_at` (`created_at`, `deleted_at`, `last_login_at`)
|
|
18
|
+
|
|
19
|
+
## Primary Key Strategies
|
|
20
|
+
|
|
21
|
+
| Strategy | Use When | Avoid When |
|
|
22
|
+
|----------|----------|------------|
|
|
23
|
+
| Auto-increment integer | Single-database apps, simple CRUD | Distributed systems, public-facing IDs |
|
|
24
|
+
| UUID v4 | Distributed generation needed, merge safety | Storage-sensitive, need sortable IDs |
|
|
25
|
+
| ULID / UUID v7 | Need sortable + distributed + compact | Legacy systems that expect integers |
|
|
26
|
+
| Natural key | Data has a true natural identifier | Natural key might change |
|
|
27
|
+
|
|
28
|
+
Default recommendation: auto-increment for internal apps, ULID for APIs and distributed systems.
|
|
29
|
+
|
|
30
|
+
## Common Column Patterns
|
|
31
|
+
|
|
32
|
+
**Soft deletes**: Add `deleted_at TIMESTAMP NULL` instead of physically deleting rows. Add a partial index: `CREATE INDEX idx_active_users ON users(id) WHERE deleted_at IS NULL;`
|
|
33
|
+
|
|
34
|
+
**Polymorphic associations**: Prefer dedicated join tables over `type`/`id` column pairs. Polymorphic columns lose foreign key enforcement.
|
|
35
|
+
|
|
36
|
+
**JSON columns**: Use for truly schemaless data (user preferences, external API payloads). Never for data you query by — that data belongs in proper columns with indexes.
|
|
37
|
+
|
|
38
|
+
**Enums**: Prefer check constraints or reference tables over database-level enums. Enums are hard to modify in most databases.
|
|
39
|
+
|
|
40
|
+
## Index Naming
|
|
41
|
+
|
|
42
|
+
Pattern: `idx_{table}_{columns}_{type}`
|
|
43
|
+
|
|
44
|
+
- `idx_users_email_unique`
|
|
45
|
+
- `idx_orders_user_id_created_at`
|
|
46
|
+
- `idx_products_name_gin` (for full-text search)
|
|
47
|
+
|
|
48
|
+
## Migration Best Practices
|
|
49
|
+
|
|
50
|
+
1. **One concern per migration**: Don't mix schema changes with data changes
|
|
51
|
+
2. **Always reversible**: Every `up` must have a corresponding `down`
|
|
52
|
+
3. **Expand-contract for breaking changes**:
|
|
53
|
+
- Migration 1: Add new column, backfill data
|
|
54
|
+
- Deploy: Update code to write to both old and new columns
|
|
55
|
+
- Migration 2: Remove old column
|
|
56
|
+
4. **Test migrations on production-like data**: A migration that works on 100 rows might lock the table on 10 million rows
|
|
57
|
+
5. **Avoid renaming columns in production**: Add new column, migrate data, drop old column
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Database Schema Templates
|
|
2
|
+
|
|
3
|
+
PostgreSQL-focused. MySQL notes marked inline. Copy, rename, and remove the columns you don't need.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table Template
|
|
8
|
+
|
|
9
|
+
```sql
|
|
10
|
+
CREATE TABLE orders (
|
|
11
|
+
-- Primary key: use BIGSERIAL for high-volume tables, UUID for distributed/exposed IDs
|
|
12
|
+
id BIGSERIAL PRIMARY KEY,
|
|
13
|
+
-- id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- UUID alternative
|
|
14
|
+
|
|
15
|
+
-- Foreign keys: explicit names, explicit ON DELETE behavior
|
|
16
|
+
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
|
17
|
+
status TEXT NOT NULL DEFAULT 'pending'
|
|
18
|
+
CHECK (status IN ('pending', 'confirmed', 'cancelled', 'refunded')),
|
|
19
|
+
total_cents BIGINT NOT NULL CHECK (total_cents >= 0), -- store money as integer cents
|
|
20
|
+
notes TEXT, -- nullable: OK for optional fields
|
|
21
|
+
|
|
22
|
+
-- Audit timestamps: always include, always have defaults
|
|
23
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
24
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
25
|
+
-- MySQL equivalent: DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
-- updated_at trigger (PostgreSQL)
|
|
29
|
+
CREATE OR REPLACE FUNCTION set_updated_at()
|
|
30
|
+
RETURNS TRIGGER LANGUAGE plpgsql AS $$
|
|
31
|
+
BEGIN NEW.updated_at = NOW(); RETURN NEW; END;
|
|
32
|
+
$$;
|
|
33
|
+
CREATE TRIGGER orders_set_updated_at
|
|
34
|
+
BEFORE UPDATE ON orders
|
|
35
|
+
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Index Conventions
|
|
41
|
+
|
|
42
|
+
```sql
|
|
43
|
+
-- Foreign key indexes: idx_<table>_<column>
|
|
44
|
+
CREATE INDEX idx_orders_user_id ON orders (user_id);
|
|
45
|
+
|
|
46
|
+
-- Composite index: match the query's WHERE + ORDER BY column order
|
|
47
|
+
CREATE INDEX idx_orders_user_status ON orders (user_id, status);
|
|
48
|
+
|
|
49
|
+
-- Partial index: index only the rows the query targets
|
|
50
|
+
CREATE INDEX idx_orders_pending ON orders (created_at)
|
|
51
|
+
WHERE status = 'pending';
|
|
52
|
+
|
|
53
|
+
-- Unique constraint (preferred over CREATE UNIQUE INDEX for constraints)
|
|
54
|
+
ALTER TABLE orders ADD CONSTRAINT uq_orders_external_id UNIQUE (external_id);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> **Naming pattern:** `idx_<table>_<columns>` for regular indexes, `uq_<table>_<columns>` for unique constraints, `fk_<table>_<referenced_table>` for named FK constraints.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Enum Patterns
|
|
62
|
+
|
|
63
|
+
**Option A — PostgreSQL enum type** (fast, type-safe; hard to add values without migration):
|
|
64
|
+
|
|
65
|
+
```sql
|
|
66
|
+
CREATE TYPE order_status AS ENUM ('pending', 'confirmed', 'cancelled', 'refunded');
|
|
67
|
+
ALTER TABLE orders ADD COLUMN status order_status NOT NULL DEFAULT 'pending';
|
|
68
|
+
|
|
69
|
+
-- Adding a value later: ALTER TYPE order_status ADD VALUE 'on_hold'; (irreversible)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Option B — Constrained VARCHAR** (flexible; tradeoff: constraint must be updated for new values):
|
|
73
|
+
|
|
74
|
+
```sql
|
|
75
|
+
ALTER TABLE orders ADD COLUMN status TEXT NOT NULL DEFAULT 'pending'
|
|
76
|
+
CHECK (status IN ('pending', 'confirmed', 'cancelled', 'refunded'));
|
|
77
|
+
-- To add a value: ALTER TABLE orders DROP CONSTRAINT <constraint_name>, ADD CONSTRAINT ...
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
> **Rule of thumb:** Use Option A when the set is truly fixed (e.g., gender: M/F/other). Use Option B when the list may grow over time (e.g., order status, notification type).
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Migration File Template
|
|
85
|
+
|
|
86
|
+
```sql
|
|
87
|
+
-- migrations/20240315120000_add_orders_table.up.sql
|
|
88
|
+
|
|
89
|
+
BEGIN;
|
|
90
|
+
|
|
91
|
+
CREATE TABLE orders (
|
|
92
|
+
id BIGSERIAL PRIMARY KEY,
|
|
93
|
+
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
|
94
|
+
status TEXT NOT NULL DEFAULT 'pending'
|
|
95
|
+
CHECK (status IN ('pending', 'confirmed', 'cancelled')),
|
|
96
|
+
total_cents BIGINT NOT NULL CHECK (total_cents >= 0),
|
|
97
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
98
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
CREATE INDEX idx_orders_user_id ON orders (user_id);
|
|
102
|
+
|
|
103
|
+
COMMIT;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```sql
|
|
107
|
+
-- migrations/20240315120000_add_orders_table.down.sql
|
|
108
|
+
|
|
109
|
+
BEGIN;
|
|
110
|
+
|
|
111
|
+
DROP TABLE IF EXISTS orders;
|
|
112
|
+
|
|
113
|
+
COMMIT;
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> **Migration rules:**
|
|
117
|
+
> - Filename: `<timestamp>_<description>.up.sql` / `.down.sql` — timestamp prefix ensures ordered application.
|
|
118
|
+
> - Wrap in `BEGIN`/`COMMIT` so partial failures roll back.
|
|
119
|
+
> - Down migration must completely undo the up migration.
|
|
120
|
+
> - Backwards-compatible changes (ADD COLUMN with default) are safe to apply before deploying code. Breaking changes (DROP COLUMN, rename) require expand-contract: add new → migrate data → remove old.
|