@malamute/ai-rules 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +270 -121
  2. package/bin/cli.js +5 -2
  3. package/configs/_shared/.claude/rules/conventions/documentation.md +324 -0
  4. package/configs/_shared/.claude/rules/conventions/git.md +265 -0
  5. package/configs/_shared/.claude/rules/{performance.md → conventions/performance.md} +1 -1
  6. package/configs/_shared/.claude/rules/conventions/principles.md +334 -0
  7. package/configs/_shared/.claude/rules/devops/ci-cd.md +262 -0
  8. package/configs/_shared/.claude/rules/devops/docker.md +275 -0
  9. package/configs/_shared/.claude/rules/devops/nx.md +194 -0
  10. package/configs/_shared/.claude/rules/domain/backend/api-design.md +203 -0
  11. package/configs/_shared/.claude/rules/lang/csharp/async.md +220 -0
  12. package/configs/_shared/.claude/rules/lang/csharp/csharp.md +314 -0
  13. package/configs/_shared/.claude/rules/lang/csharp/linq.md +210 -0
  14. package/configs/_shared/.claude/rules/lang/python/async.md +337 -0
  15. package/configs/_shared/.claude/rules/lang/python/celery.md +476 -0
  16. package/configs/_shared/.claude/rules/lang/python/config.md +339 -0
  17. package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/database/sqlalchemy.md +6 -1
  18. package/configs/_shared/.claude/rules/lang/python/deployment.md +523 -0
  19. package/configs/_shared/.claude/rules/lang/python/error-handling.md +330 -0
  20. package/configs/_shared/.claude/rules/lang/python/migrations.md +421 -0
  21. package/configs/_shared/.claude/rules/lang/python/python.md +172 -0
  22. package/configs/_shared/.claude/rules/lang/python/repository.md +383 -0
  23. package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/testing.md +2 -69
  24. package/configs/_shared/.claude/rules/lang/typescript/async.md +447 -0
  25. package/configs/_shared/.claude/rules/lang/typescript/generics.md +356 -0
  26. package/configs/_shared/.claude/rules/lang/typescript/typescript.md +212 -0
  27. package/configs/_shared/.claude/rules/quality/error-handling.md +48 -0
  28. package/configs/_shared/.claude/rules/quality/logging.md +45 -0
  29. package/configs/_shared/.claude/rules/quality/observability.md +240 -0
  30. package/configs/_shared/.claude/rules/quality/testing-patterns.md +65 -0
  31. package/configs/_shared/.claude/rules/security/secrets-management.md +222 -0
  32. package/configs/_shared/.claude/skills/analysis/explore/SKILL.md +257 -0
  33. package/configs/_shared/.claude/skills/analysis/security-audit/SKILL.md +184 -0
  34. package/configs/_shared/.claude/skills/dev/api-endpoint/SKILL.md +126 -0
  35. package/configs/_shared/.claude/{commands/generate-tests.md → skills/dev/generate-tests/SKILL.md} +6 -0
  36. package/configs/_shared/.claude/{commands/fix-issue.md → skills/git/fix-issue/SKILL.md} +6 -0
  37. package/configs/_shared/.claude/{commands/review-pr.md → skills/git/review-pr/SKILL.md} +6 -0
  38. package/configs/_shared/.claude/skills/infra/deploy/SKILL.md +139 -0
  39. package/configs/_shared/.claude/skills/infra/docker/SKILL.md +95 -0
  40. package/configs/_shared/.claude/skills/infra/migration/SKILL.md +158 -0
  41. package/configs/_shared/.claude/skills/nx/nx-affected/SKILL.md +72 -0
  42. package/configs/_shared/.claude/skills/nx/nx-lib/SKILL.md +375 -0
  43. package/configs/_shared/CLAUDE.md +52 -149
  44. package/configs/angular/.claude/rules/{components.md → core/components.md} +69 -15
  45. package/configs/angular/.claude/rules/core/resource.md +285 -0
  46. package/configs/angular/.claude/rules/core/signals.md +323 -0
  47. package/configs/angular/.claude/rules/http.md +338 -0
  48. package/configs/angular/.claude/rules/routing.md +291 -0
  49. package/configs/angular/.claude/rules/ssr.md +312 -0
  50. package/configs/angular/.claude/rules/state/signal-store.md +408 -0
  51. package/configs/angular/.claude/rules/{state.md → state/state.md} +2 -2
  52. package/configs/angular/.claude/rules/testing.md +7 -7
  53. package/configs/angular/.claude/rules/ui/aria.md +422 -0
  54. package/configs/angular/.claude/rules/ui/forms.md +424 -0
  55. package/configs/angular/.claude/rules/ui/pipes-directives.md +335 -0
  56. package/configs/angular/.claude/settings.json +1 -0
  57. package/configs/angular/.claude/skills/ngrx-slice/SKILL.md +362 -0
  58. package/configs/angular/.claude/skills/signal-store/SKILL.md +445 -0
  59. package/configs/angular/CLAUDE.md +24 -216
  60. package/configs/dotnet/.claude/rules/background-services.md +552 -0
  61. package/configs/dotnet/.claude/rules/configuration.md +426 -0
  62. package/configs/dotnet/.claude/rules/ddd.md +447 -0
  63. package/configs/dotnet/.claude/rules/dependency-injection.md +343 -0
  64. package/configs/dotnet/.claude/rules/mediatr.md +320 -0
  65. package/configs/dotnet/.claude/rules/middleware.md +489 -0
  66. package/configs/dotnet/.claude/rules/result-pattern.md +363 -0
  67. package/configs/dotnet/.claude/rules/validation.md +388 -0
  68. package/configs/dotnet/.claude/settings.json +21 -3
  69. package/configs/dotnet/CLAUDE.md +53 -286
  70. package/configs/fastapi/.claude/rules/background-tasks.md +254 -0
  71. package/configs/fastapi/.claude/rules/dependencies.md +170 -0
  72. package/configs/{python → fastapi}/.claude/rules/fastapi.md +61 -1
  73. package/configs/fastapi/.claude/rules/lifespan.md +274 -0
  74. package/configs/fastapi/.claude/rules/middleware.md +229 -0
  75. package/configs/fastapi/.claude/rules/pydantic.md +433 -0
  76. package/configs/fastapi/.claude/rules/responses.md +251 -0
  77. package/configs/fastapi/.claude/rules/routers.md +202 -0
  78. package/configs/fastapi/.claude/rules/security.md +222 -0
  79. package/configs/fastapi/.claude/rules/testing.md +251 -0
  80. package/configs/fastapi/.claude/rules/websockets.md +298 -0
  81. package/configs/fastapi/.claude/settings.json +33 -0
  82. package/configs/fastapi/CLAUDE.md +144 -0
  83. package/configs/flask/.claude/rules/blueprints.md +208 -0
  84. package/configs/flask/.claude/rules/cli.md +285 -0
  85. package/configs/flask/.claude/rules/configuration.md +281 -0
  86. package/configs/flask/.claude/rules/context.md +238 -0
  87. package/configs/flask/.claude/rules/error-handlers.md +278 -0
  88. package/configs/flask/.claude/rules/extensions.md +278 -0
  89. package/configs/flask/.claude/rules/flask.md +171 -0
  90. package/configs/flask/.claude/rules/marshmallow.md +206 -0
  91. package/configs/flask/.claude/rules/security.md +267 -0
  92. package/configs/flask/.claude/rules/testing.md +284 -0
  93. package/configs/flask/.claude/settings.json +33 -0
  94. package/configs/flask/CLAUDE.md +166 -0
  95. package/configs/nestjs/.claude/rules/common-patterns.md +300 -0
  96. package/configs/nestjs/.claude/rules/filters.md +376 -0
  97. package/configs/nestjs/.claude/rules/interceptors.md +317 -0
  98. package/configs/nestjs/.claude/rules/middleware.md +321 -0
  99. package/configs/nestjs/.claude/rules/modules.md +26 -0
  100. package/configs/nestjs/.claude/rules/pipes.md +351 -0
  101. package/configs/nestjs/.claude/rules/websockets.md +451 -0
  102. package/configs/nestjs/.claude/settings.json +16 -2
  103. package/configs/nestjs/CLAUDE.md +57 -215
  104. package/configs/nextjs/.claude/rules/api-routes.md +358 -0
  105. package/configs/nextjs/.claude/rules/authentication.md +355 -0
  106. package/configs/nextjs/.claude/rules/components.md +52 -0
  107. package/configs/nextjs/.claude/rules/data-fetching.md +249 -0
  108. package/configs/nextjs/.claude/rules/database.md +400 -0
  109. package/configs/nextjs/.claude/rules/middleware.md +303 -0
  110. package/configs/nextjs/.claude/rules/routing.md +324 -0
  111. package/configs/nextjs/.claude/rules/seo.md +350 -0
  112. package/configs/nextjs/.claude/rules/server-actions.md +353 -0
  113. package/configs/nextjs/.claude/rules/state/zustand.md +6 -6
  114. package/configs/nextjs/.claude/settings.json +5 -0
  115. package/configs/nextjs/CLAUDE.md +69 -331
  116. package/package.json +23 -9
  117. package/src/cli.js +220 -0
  118. package/src/config.js +29 -0
  119. package/src/index.js +13 -0
  120. package/src/installer.js +361 -0
  121. package/src/merge.js +116 -0
  122. package/src/tech-config.json +29 -0
  123. package/src/utils.js +96 -0
  124. package/configs/python/.claude/rules/flask.md +0 -332
  125. package/configs/python/.claude/settings.json +0 -18
  126. package/configs/python/CLAUDE.md +0 -273
  127. package/src/install.js +0 -315
  128. /package/configs/_shared/.claude/rules/{accessibility.md → domain/frontend/accessibility.md} +0 -0
  129. /package/configs/_shared/.claude/rules/{security.md → security/security.md} +0 -0
  130. /package/configs/_shared/.claude/skills/{debug → dev/debug}/SKILL.md +0 -0
  131. /package/configs/_shared/.claude/skills/{learning → dev/learning}/SKILL.md +0 -0
  132. /package/configs/_shared/.claude/skills/{spec → dev/spec}/SKILL.md +0 -0
  133. /package/configs/_shared/.claude/skills/{review → git/review}/SKILL.md +0 -0
@@ -0,0 +1,523 @@
1
+ ---
2
+ paths:
3
+ - "Dockerfile"
4
+ - "docker-compose*.yml"
5
+ - "gunicorn.conf.py"
6
+ - "uvicorn_config.py"
7
+ - "**/deploy/**"
8
+ - ".github/workflows/*.yml"
9
+ ---
10
+
11
+ # Python Deployment
12
+
13
+ ## Dockerfile (FastAPI)
14
+
15
+ ```dockerfile
16
+ # Dockerfile
17
+ FROM python:3.12-slim AS base
18
+
19
+ # Set environment variables
20
+ ENV PYTHONDONTWRITEBYTECODE=1 \
21
+ PYTHONUNBUFFERED=1 \
22
+ PYTHONFAULTHANDLER=1 \
23
+ PIP_NO_CACHE_DIR=1 \
24
+ PIP_DISABLE_PIP_VERSION_CHECK=1
25
+
26
+ WORKDIR /app
27
+
28
+ # Install system dependencies
29
+ RUN apt-get update && apt-get install -y --no-install-recommends \
30
+ curl \
31
+ && rm -rf /var/lib/apt/lists/*
32
+
33
+ # Builder stage
34
+ FROM base AS builder
35
+
36
+ # Install build dependencies
37
+ RUN apt-get update && apt-get install -y --no-install-recommends \
38
+ build-essential \
39
+ libpq-dev \
40
+ && rm -rf /var/lib/apt/lists/*
41
+
42
+ # Install Python dependencies
43
+ COPY requirements.txt .
44
+ RUN pip install --user -r requirements.txt
45
+
46
+ # Production stage
47
+ FROM base AS production
48
+
49
+ # Copy installed packages from builder
50
+ COPY --from=builder /root/.local /root/.local
51
+ ENV PATH=/root/.local/bin:$PATH
52
+
53
+ # Copy application code
54
+ COPY ./app ./app
55
+ COPY ./alembic ./alembic
56
+ COPY alembic.ini .
57
+
58
+ # Create non-root user
59
+ RUN useradd --create-home --shell /bin/bash appuser
60
+ USER appuser
61
+
62
+ # Health check
63
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
64
+ CMD curl -f http://localhost:8000/health || exit 1
65
+
66
+ EXPOSE 8000
67
+
68
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
69
+ ```
70
+
71
+ ## Gunicorn Configuration
72
+
73
+ ```python
74
+ # gunicorn.conf.py
75
+ import multiprocessing
76
+ import os
77
+
78
+ # Server socket
79
+ bind = os.getenv("BIND", "0.0.0.0:8000")
80
+ backlog = 2048
81
+
82
+ # Worker processes
83
+ workers = int(os.getenv("WORKERS", multiprocessing.cpu_count() * 2 + 1))
84
+ worker_class = "uvicorn.workers.UvicornWorker"
85
+ worker_connections = 1000
86
+ max_requests = 1000
87
+ max_requests_jitter = 100
88
+ timeout = 120
89
+ graceful_timeout = 30
90
+ keepalive = 5
91
+
92
+ # Preload app for memory efficiency
93
+ preload_app = True
94
+
95
+ # Logging
96
+ accesslog = "-"
97
+ errorlog = "-"
98
+ loglevel = os.getenv("LOG_LEVEL", "info")
99
+ access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
100
+
101
+ # Process naming
102
+ proc_name = "myapp"
103
+
104
+ # Server mechanics
105
+ daemon = False
106
+ pidfile = None
107
+ umask = 0
108
+ user = None
109
+ group = None
110
+ tmp_upload_dir = None
111
+
112
+ # Hooks
113
+ def on_starting(server):
114
+ """Called before the master process is initialized."""
115
+ pass
116
+
117
+
118
+ def on_reload(server):
119
+ """Called to recycle workers during a reload via SIGHUP."""
120
+ pass
121
+
122
+
123
+ def worker_int(worker):
124
+ """Called when a worker receives SIGINT or SIGQUIT."""
125
+ pass
126
+
127
+
128
+ def worker_abort(worker):
129
+ """Called when a worker receives SIGABRT."""
130
+ pass
131
+ ```
132
+
133
+ ## Docker Compose
134
+
135
+ ```yaml
136
+ # docker-compose.yml
137
+ services:
138
+ app:
139
+ build:
140
+ context: .
141
+ target: production
142
+ ports:
143
+ - "8000:8000"
144
+ environment:
145
+ - DATABASE_URL=postgresql://user:pass@db:5432/app
146
+ - REDIS_URL=redis://redis:6379/0
147
+ - SECRET_KEY=${SECRET_KEY}
148
+ depends_on:
149
+ db:
150
+ condition: service_healthy
151
+ redis:
152
+ condition: service_started
153
+ healthcheck:
154
+ test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
155
+ interval: 30s
156
+ timeout: 10s
157
+ retries: 3
158
+ deploy:
159
+ replicas: 2
160
+ resources:
161
+ limits:
162
+ cpus: "1"
163
+ memory: 512M
164
+ reservations:
165
+ cpus: "0.25"
166
+ memory: 256M
167
+
168
+ worker:
169
+ build:
170
+ context: .
171
+ target: production
172
+ command: celery -A app.celery worker --loglevel=info
173
+ environment:
174
+ - DATABASE_URL=postgresql://user:pass@db:5432/app
175
+ - REDIS_URL=redis://redis:6379/0
176
+ depends_on:
177
+ - db
178
+ - redis
179
+ deploy:
180
+ replicas: 2
181
+
182
+ beat:
183
+ build:
184
+ context: .
185
+ target: production
186
+ command: celery -A app.celery beat --loglevel=info
187
+ environment:
188
+ - DATABASE_URL=postgresql://user:pass@db:5432/app
189
+ - REDIS_URL=redis://redis:6379/0
190
+ depends_on:
191
+ - db
192
+ - redis
193
+
194
+ db:
195
+ image: postgres:16-alpine
196
+ volumes:
197
+ - postgres_data:/var/lib/postgresql/data
198
+ environment:
199
+ - POSTGRES_USER=user
200
+ - POSTGRES_PASSWORD=pass
201
+ - POSTGRES_DB=app
202
+ healthcheck:
203
+ test: ["CMD-SHELL", "pg_isready -U user -d app"]
204
+ interval: 10s
205
+ timeout: 5s
206
+ retries: 5
207
+
208
+ redis:
209
+ image: redis:7-alpine
210
+ volumes:
211
+ - redis_data:/data
212
+
213
+ volumes:
214
+ postgres_data:
215
+ redis_data:
216
+ ```
217
+
218
+ ## GitHub Actions CI/CD
219
+
220
+ ```yaml
221
+ # .github/workflows/deploy.yml
222
+ name: Deploy
223
+
224
+ on:
225
+ push:
226
+ branches: [main]
227
+
228
+ env:
229
+ REGISTRY: ghcr.io
230
+ IMAGE_NAME: ${{ github.repository }}
231
+
232
+ jobs:
233
+ test:
234
+ runs-on: ubuntu-latest
235
+ services:
236
+ postgres:
237
+ image: postgres:16
238
+ env:
239
+ POSTGRES_PASSWORD: test
240
+ options: >-
241
+ --health-cmd pg_isready
242
+ --health-interval 10s
243
+ --health-timeout 5s
244
+ --health-retries 5
245
+ ports:
246
+ - 5432:5432
247
+
248
+ steps:
249
+ - uses: actions/checkout@v4
250
+
251
+ - name: Set up Python
252
+ uses: actions/setup-python@v5
253
+ with:
254
+ python-version: "3.12"
255
+ cache: "pip"
256
+
257
+ - name: Install dependencies
258
+ run: |
259
+ pip install -r requirements.txt
260
+ pip install -r requirements-dev.txt
261
+
262
+ - name: Run linting
263
+ run: |
264
+ ruff check .
265
+ ruff format --check .
266
+
267
+ - name: Run type checking
268
+ run: mypy app
269
+
270
+ - name: Run tests
271
+ run: pytest --cov=app --cov-report=xml
272
+ env:
273
+ DATABASE_URL: postgresql://postgres:test@localhost:5432/test
274
+
275
+ - name: Upload coverage
276
+ uses: codecov/codecov-action@v4
277
+ with:
278
+ file: ./coverage.xml
279
+
280
+ build:
281
+ needs: test
282
+ runs-on: ubuntu-latest
283
+ permissions:
284
+ contents: read
285
+ packages: write
286
+
287
+ steps:
288
+ - uses: actions/checkout@v4
289
+
290
+ - name: Set up Docker Buildx
291
+ uses: docker/setup-buildx-action@v3
292
+
293
+ - name: Log in to Container Registry
294
+ uses: docker/login-action@v3
295
+ with:
296
+ registry: ${{ env.REGISTRY }}
297
+ username: ${{ github.actor }}
298
+ password: ${{ secrets.GITHUB_TOKEN }}
299
+
300
+ - name: Extract metadata
301
+ id: meta
302
+ uses: docker/metadata-action@v5
303
+ with:
304
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
305
+ tags: |
306
+ type=sha
307
+ type=raw,value=latest,enable={{is_default_branch}}
308
+
309
+ - name: Build and push
310
+ uses: docker/build-push-action@v5
311
+ with:
312
+ context: .
313
+ push: true
314
+ tags: ${{ steps.meta.outputs.tags }}
315
+ labels: ${{ steps.meta.outputs.labels }}
316
+ cache-from: type=gha
317
+ cache-to: type=gha,mode=max
318
+
319
+ deploy:
320
+ needs: build
321
+ runs-on: ubuntu-latest
322
+ environment: production
323
+
324
+ steps:
325
+ - name: Deploy to production
326
+ run: |
327
+ # Trigger deployment (e.g., ArgoCD, kubectl, etc.)
328
+ curl -X POST ${{ secrets.DEPLOY_WEBHOOK_URL }}
329
+ ```
330
+
331
+ ## Kubernetes Deployment
332
+
333
+ ```yaml
334
+ # k8s/deployment.yaml
335
+ apiVersion: apps/v1
336
+ kind: Deployment
337
+ metadata:
338
+ name: myapp
339
+ labels:
340
+ app: myapp
341
+ spec:
342
+ replicas: 3
343
+ selector:
344
+ matchLabels:
345
+ app: myapp
346
+ template:
347
+ metadata:
348
+ labels:
349
+ app: myapp
350
+ spec:
351
+ containers:
352
+ - name: app
353
+ image: ghcr.io/org/myapp:latest
354
+ ports:
355
+ - containerPort: 8000
356
+ env:
357
+ - name: DATABASE_URL
358
+ valueFrom:
359
+ secretKeyRef:
360
+ name: myapp-secrets
361
+ key: database-url
362
+ resources:
363
+ requests:
364
+ memory: "256Mi"
365
+ cpu: "250m"
366
+ limits:
367
+ memory: "512Mi"
368
+ cpu: "1000m"
369
+ readinessProbe:
370
+ httpGet:
371
+ path: /health
372
+ port: 8000
373
+ initialDelaySeconds: 5
374
+ periodSeconds: 10
375
+ livenessProbe:
376
+ httpGet:
377
+ path: /health
378
+ port: 8000
379
+ initialDelaySeconds: 15
380
+ periodSeconds: 20
381
+ ---
382
+ apiVersion: v1
383
+ kind: Service
384
+ metadata:
385
+ name: myapp
386
+ spec:
387
+ selector:
388
+ app: myapp
389
+ ports:
390
+ - port: 80
391
+ targetPort: 8000
392
+ ---
393
+ apiVersion: networking.k8s.io/v1
394
+ kind: Ingress
395
+ metadata:
396
+ name: myapp
397
+ annotations:
398
+ kubernetes.io/ingress.class: nginx
399
+ cert-manager.io/cluster-issuer: letsencrypt-prod
400
+ spec:
401
+ tls:
402
+ - hosts:
403
+ - api.example.com
404
+ secretName: myapp-tls
405
+ rules:
406
+ - host: api.example.com
407
+ http:
408
+ paths:
409
+ - path: /
410
+ pathType: Prefix
411
+ backend:
412
+ service:
413
+ name: myapp
414
+ port:
415
+ number: 80
416
+ ```
417
+
418
+ ## Health Check Endpoint
419
+
420
+ ```python
421
+ # app/api/health.py
422
+ from fastapi import APIRouter, Depends
423
+ from sqlalchemy.ext.asyncio import AsyncSession
424
+ from sqlalchemy import text
425
+ from redis import Redis
426
+ import time
427
+
428
+ router = APIRouter(tags=["health"])
429
+
430
+
431
+ @router.get("/health")
432
+ async def health_check(
433
+ db: AsyncSession = Depends(get_db),
434
+ redis: Redis = Depends(get_redis),
435
+ ) -> dict:
436
+ """Health check endpoint for load balancers."""
437
+ checks = {}
438
+
439
+ # Database check
440
+ try:
441
+ start = time.time()
442
+ await db.execute(text("SELECT 1"))
443
+ checks["database"] = {
444
+ "status": "healthy",
445
+ "latency_ms": round((time.time() - start) * 1000, 2),
446
+ }
447
+ except Exception as e:
448
+ checks["database"] = {"status": "unhealthy", "error": str(e)}
449
+
450
+ # Redis check
451
+ try:
452
+ start = time.time()
453
+ redis.ping()
454
+ checks["redis"] = {
455
+ "status": "healthy",
456
+ "latency_ms": round((time.time() - start) * 1000, 2),
457
+ }
458
+ except Exception as e:
459
+ checks["redis"] = {"status": "unhealthy", "error": str(e)}
460
+
461
+ # Overall status
462
+ all_healthy = all(c.get("status") == "healthy" for c in checks.values())
463
+
464
+ return {
465
+ "status": "healthy" if all_healthy else "unhealthy",
466
+ "checks": checks,
467
+ }
468
+
469
+
470
+ @router.get("/ready")
471
+ async def readiness_check() -> dict:
472
+ """Readiness probe - is the app ready to receive traffic?"""
473
+ return {"status": "ready"}
474
+
475
+
476
+ @router.get("/live")
477
+ async def liveness_check() -> dict:
478
+ """Liveness probe - is the app alive?"""
479
+ return {"status": "alive"}
480
+ ```
481
+
482
+ ## Anti-patterns
483
+
484
+ ```python
485
+ # BAD: Running as root
486
+ FROM python:3.12
487
+ WORKDIR /app
488
+ COPY . .
489
+ CMD ["python", "main.py"] # Runs as root!
490
+
491
+ # GOOD: Non-root user
492
+ RUN useradd --create-home appuser
493
+ USER appuser
494
+
495
+ # BAD: Installing dev dependencies in production
496
+ COPY requirements.txt requirements-dev.txt ./
497
+ RUN pip install -r requirements.txt -r requirements-dev.txt
498
+
499
+ # GOOD: Only production dependencies
500
+ COPY requirements.txt ./
501
+ RUN pip install -r requirements.txt
502
+
503
+ # BAD: No health checks
504
+ # Container appears healthy even if app is broken
505
+
506
+ # GOOD: Proper health checks
507
+ HEALTHCHECK CMD curl -f http://localhost:8000/health || exit 1
508
+
509
+ # BAD: Hardcoded secrets
510
+ ENV DATABASE_URL=postgresql://user:password@db/app
511
+
512
+ # GOOD: Use secrets or environment variables at runtime
513
+ ENV DATABASE_URL=${DATABASE_URL}
514
+
515
+ # BAD: No resource limits
516
+ # Worker can consume all memory
517
+
518
+ # GOOD: Set resource limits in docker-compose/k8s
519
+ deploy:
520
+ resources:
521
+ limits:
522
+ memory: 512M
523
+ ```