@kodrunhq/opencode-autopilot 1.12.2 → 1.14.1
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/assets/commands/oc-brainstorm.md +1 -0
- package/assets/commands/oc-new-agent.md +1 -0
- package/assets/commands/oc-new-command.md +1 -0
- package/assets/commands/oc-new-skill.md +1 -0
- package/assets/commands/oc-quick.md +1 -0
- package/assets/commands/oc-refactor.md +26 -0
- package/assets/commands/oc-review-agents.md +1 -0
- package/assets/commands/oc-review-pr.md +1 -0
- package/assets/commands/oc-security-audit.md +20 -0
- package/assets/commands/oc-stocktake.md +1 -0
- package/assets/commands/oc-tdd.md +1 -0
- package/assets/commands/oc-update-docs.md +1 -0
- package/assets/commands/oc-write-plan.md +1 -0
- package/assets/skills/api-design/SKILL.md +391 -0
- package/assets/skills/brainstorming/SKILL.md +1 -0
- package/assets/skills/code-review/SKILL.md +1 -0
- package/assets/skills/coding-standards/SKILL.md +1 -0
- package/assets/skills/csharp-patterns/SKILL.md +1 -0
- package/assets/skills/database-patterns/SKILL.md +270 -0
- package/assets/skills/docker-deployment/SKILL.md +326 -0
- package/assets/skills/e2e-testing/SKILL.md +1 -0
- package/assets/skills/frontend-design/SKILL.md +1 -0
- package/assets/skills/git-worktrees/SKILL.md +1 -0
- package/assets/skills/go-patterns/SKILL.md +1 -0
- package/assets/skills/java-patterns/SKILL.md +1 -0
- package/assets/skills/plan-executing/SKILL.md +1 -0
- package/assets/skills/plan-writing/SKILL.md +1 -0
- package/assets/skills/python-patterns/SKILL.md +1 -0
- package/assets/skills/rust-patterns/SKILL.md +1 -0
- package/assets/skills/security-patterns/SKILL.md +312 -0
- package/assets/skills/strategic-compaction/SKILL.md +1 -0
- package/assets/skills/systematic-debugging/SKILL.md +1 -0
- package/assets/skills/tdd-workflow/SKILL.md +1 -0
- package/assets/skills/typescript-patterns/SKILL.md +1 -0
- package/assets/skills/verification/SKILL.md +1 -0
- package/package.json +1 -1
- package/src/agents/db-specialist.ts +295 -0
- package/src/agents/devops.ts +352 -0
- package/src/agents/frontend-engineer.ts +541 -0
- package/src/agents/index.ts +12 -0
- package/src/agents/security-auditor.ts +348 -0
- package/src/hooks/anti-slop.ts +40 -1
- package/src/hooks/slop-patterns.ts +24 -4
- package/src/installer.ts +29 -2
- package/src/memory/capture.ts +9 -4
- package/src/memory/decay.ts +11 -0
- package/src/memory/retrieval.ts +31 -2
- package/src/orchestrator/artifacts.ts +7 -2
- package/src/orchestrator/confidence.ts +3 -2
- package/src/orchestrator/handlers/architect.ts +11 -8
- package/src/orchestrator/handlers/build.ts +12 -10
- package/src/orchestrator/handlers/challenge.ts +9 -3
- package/src/orchestrator/handlers/plan.ts +115 -9
- package/src/orchestrator/handlers/recon.ts +9 -4
- package/src/orchestrator/handlers/retrospective.ts +3 -1
- package/src/orchestrator/handlers/ship.ts +8 -7
- package/src/orchestrator/handlers/types.ts +1 -0
- package/src/orchestrator/lesson-memory.ts +2 -1
- package/src/orchestrator/orchestration-logger.ts +40 -0
- package/src/orchestrator/phase.ts +14 -0
- package/src/orchestrator/schemas.ts +1 -0
- package/src/orchestrator/skill-injection.ts +11 -6
- package/src/orchestrator/state.ts +2 -1
- package/src/review/selection.ts +4 -32
- package/src/skills/adaptive-injector.ts +96 -5
- package/src/skills/loader.ts +4 -1
- package/src/tools/orchestrate.ts +141 -18
- package/src/tools/review.ts +2 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
# opencode-autopilot
|
|
3
|
+
name: database-patterns
|
|
4
|
+
description: Database design, query optimization, migration strategies, indexing, connection pooling, transactions, and data modeling patterns
|
|
5
|
+
stacks: []
|
|
6
|
+
requires: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Database Patterns
|
|
10
|
+
|
|
11
|
+
Practical patterns for database design, query optimization, and operational management. Covers schema design, indexing, query optimization, migrations, connection pooling, transactions, data modeling, and backup/recovery. Apply these when designing schemas, reviewing queries, planning migrations, or troubleshooting performance.
|
|
12
|
+
|
|
13
|
+
## 1. Schema Design Principles
|
|
14
|
+
|
|
15
|
+
**DO:** Design schemas that balance normalization with practical query performance.
|
|
16
|
+
|
|
17
|
+
- Normalize to 3NF by default -- eliminate data duplication and update anomalies
|
|
18
|
+
- Denormalize deliberately when read performance justifies it (document the trade-off)
|
|
19
|
+
- Use consistent naming conventions:
|
|
20
|
+
```
|
|
21
|
+
-- Tables: plural snake_case
|
|
22
|
+
users, order_items, payment_methods
|
|
23
|
+
|
|
24
|
+
-- Columns: singular snake_case
|
|
25
|
+
user_id, created_at, is_active, total_amount
|
|
26
|
+
|
|
27
|
+
-- Foreign keys: referenced_table_singular_id
|
|
28
|
+
user_id, order_id, category_id
|
|
29
|
+
|
|
30
|
+
-- Indexes: idx_table_column(s)
|
|
31
|
+
idx_users_email, idx_orders_user_id_created_at
|
|
32
|
+
```
|
|
33
|
+
- Include standard metadata columns: `id`, `created_at`, `updated_at`
|
|
34
|
+
- Use UUIDs for public-facing identifiers; auto-increment for internal references
|
|
35
|
+
- Add `NOT NULL` constraints by default -- make nullable columns the exception with justification
|
|
36
|
+
|
|
37
|
+
**DON'T:**
|
|
38
|
+
|
|
39
|
+
- Over-normalize to 5NF+ (diminishing returns, excessive joins)
|
|
40
|
+
- Use reserved words as column names (`order`, `user`, `group`, `select`)
|
|
41
|
+
- Create tables without primary keys
|
|
42
|
+
- Use floating-point types for monetary values (use `DECIMAL`/`NUMERIC`)
|
|
43
|
+
- Store comma-separated values in a single column (normalize into a junction table)
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
-- DO: Junction table for many-to-many
|
|
47
|
+
CREATE TABLE user_roles (
|
|
48
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
49
|
+
role_id INTEGER NOT NULL REFERENCES roles(id),
|
|
50
|
+
PRIMARY KEY (user_id, role_id)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
-- DON'T: CSV in a column
|
|
54
|
+
ALTER TABLE users ADD COLUMN roles TEXT; -- "admin,editor,viewer"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 2. Indexing Strategy
|
|
58
|
+
|
|
59
|
+
**DO:** Create indexes based on actual query patterns, not guesswork.
|
|
60
|
+
|
|
61
|
+
- **B-tree indexes** (default): equality and range queries (`WHERE`, `ORDER BY`, `JOIN`)
|
|
62
|
+
- **Hash indexes**: exact equality lookups only (faster than B-tree for `=`, no range support)
|
|
63
|
+
- **Composite indexes**: order columns by selectivity (most selective first) and match query patterns
|
|
64
|
+
```sql
|
|
65
|
+
-- Query: WHERE status = 'active' AND created_at > '2024-01-01' ORDER BY created_at
|
|
66
|
+
-- Index: (status, created_at) -- status for equality, created_at for range + sort
|
|
67
|
+
CREATE INDEX idx_orders_status_created ON orders(status, created_at);
|
|
68
|
+
```
|
|
69
|
+
- **Covering indexes**: include all columns needed by the query to avoid table lookups
|
|
70
|
+
```sql
|
|
71
|
+
-- Query only needs id, email, name -- index covers it entirely
|
|
72
|
+
CREATE INDEX idx_users_email_covering ON users(email) INCLUDE (id, name);
|
|
73
|
+
```
|
|
74
|
+
- Use `EXPLAIN ANALYZE` to verify index usage before and after adding indexes
|
|
75
|
+
- Index foreign key columns (required for efficient joins and cascade deletes)
|
|
76
|
+
|
|
77
|
+
**DON'T:**
|
|
78
|
+
|
|
79
|
+
- Index every column (indexes slow writes and consume storage)
|
|
80
|
+
- Create indexes on low-cardinality columns alone (`is_active` with 2 values -- combine with other columns)
|
|
81
|
+
- Ignore index maintenance (rebuild/reindex fragmented indexes periodically)
|
|
82
|
+
- Forget that composite index column order matters: `(a, b)` serves `WHERE a = ?` but NOT `WHERE b = ?`
|
|
83
|
+
- Add indexes without checking if an existing index already covers the query
|
|
84
|
+
|
|
85
|
+
## 3. Query Optimization
|
|
86
|
+
|
|
87
|
+
**DO:** Write efficient queries and use EXPLAIN to verify execution plans.
|
|
88
|
+
|
|
89
|
+
- **Read EXPLAIN output** to understand:
|
|
90
|
+
- Scan type: Sequential Scan (bad for large tables) vs Index Scan (good)
|
|
91
|
+
- Join strategy: Nested Loop (small datasets), Hash Join (equality), Merge Join (sorted)
|
|
92
|
+
- Estimated vs actual row counts (large discrepancies indicate stale statistics)
|
|
93
|
+
|
|
94
|
+
- **Avoid N+1 queries** -- the most common ORM performance problem:
|
|
95
|
+
```
|
|
96
|
+
// DON'T: N+1 -- 1 query for users + N queries for orders
|
|
97
|
+
users = await User.findAll()
|
|
98
|
+
for (user of users) {
|
|
99
|
+
user.orders = await Order.findAll({ where: { userId: user.id } })
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// DO: Eager loading -- 1 or 2 queries total
|
|
103
|
+
users = await User.findAll({ include: [Order] })
|
|
104
|
+
|
|
105
|
+
// DO: Batch loading
|
|
106
|
+
users = await User.findAll()
|
|
107
|
+
userIds = users.map(u => u.id)
|
|
108
|
+
orders = await Order.findAll({ where: { userId: { in: userIds } } })
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- Use `LIMIT` on all queries that don't need full result sets
|
|
112
|
+
- Use `EXISTS` instead of `COUNT(*)` when checking for existence
|
|
113
|
+
- Avoid `SELECT *` -- request only needed columns
|
|
114
|
+
- Use batch operations for bulk inserts/updates (not individual queries in a loop)
|
|
115
|
+
|
|
116
|
+
**DON'T:**
|
|
117
|
+
|
|
118
|
+
- Use `OFFSET` for deep pagination (use cursor-based pagination instead)
|
|
119
|
+
- Wrap queries in unnecessary subqueries
|
|
120
|
+
- Use functions on indexed columns in WHERE clauses (`WHERE LOWER(email) = ?` -- use a functional index or store normalized)
|
|
121
|
+
- Ignore slow query logs -- review them regularly
|
|
122
|
+
|
|
123
|
+
## 4. Migration Strategies
|
|
124
|
+
|
|
125
|
+
**DO:** Use versioned, incremental migrations with rollback plans.
|
|
126
|
+
|
|
127
|
+
- Number migrations sequentially or by timestamp: `001_create_users.sql`, `20240115_add_email_index.sql`
|
|
128
|
+
- Each migration must be idempotent or have a corresponding down migration
|
|
129
|
+
- Test migrations against a copy of production data volume (not just empty schemas)
|
|
130
|
+
- Plan zero-downtime migrations for production:
|
|
131
|
+
```
|
|
132
|
+
-- Step 1: Add nullable column (no downtime)
|
|
133
|
+
ALTER TABLE users ADD COLUMN phone TEXT;
|
|
134
|
+
|
|
135
|
+
-- Step 2: Backfill data (background job)
|
|
136
|
+
UPDATE users SET phone = 'unknown' WHERE phone IS NULL;
|
|
137
|
+
|
|
138
|
+
-- Step 3: Add NOT NULL constraint (after backfill completes)
|
|
139
|
+
ALTER TABLE users ALTER COLUMN phone SET NOT NULL;
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- For column renames or type changes, use the expand-contract pattern:
|
|
143
|
+
1. Add new column
|
|
144
|
+
2. Deploy code that writes to both old and new columns
|
|
145
|
+
3. Backfill new column from old
|
|
146
|
+
4. Deploy code that reads from new column
|
|
147
|
+
5. Drop old column
|
|
148
|
+
|
|
149
|
+
**DON'T:**
|
|
150
|
+
|
|
151
|
+
- Run destructive migrations without a rollback plan (`DROP TABLE`, `DROP COLUMN`)
|
|
152
|
+
- Apply schema changes and code changes in the same deployment (deploy schema first)
|
|
153
|
+
- Lock large tables with `ALTER TABLE` during peak traffic
|
|
154
|
+
- Skip testing migrations on production-like data (row counts, constraints, FK relationships)
|
|
155
|
+
- Use ORM auto-migration in production (unpredictable, no rollback)
|
|
156
|
+
|
|
157
|
+
## 5. Connection Pooling
|
|
158
|
+
|
|
159
|
+
**DO:** Use connection pools to manage database connections efficiently.
|
|
160
|
+
|
|
161
|
+
- Size the pool based on: `pool_size = (core_count * 2) + disk_spindles` (start with this, tune under load)
|
|
162
|
+
- Set connection timeouts (acquisition: 5s, idle: 60s, max lifetime: 30min)
|
|
163
|
+
- Use a connection pool per service instance, not a global shared pool
|
|
164
|
+
- Monitor pool metrics: active connections, waiting requests, timeout rate
|
|
165
|
+
- Close connections gracefully on application shutdown
|
|
166
|
+
|
|
167
|
+
**DON'T:**
|
|
168
|
+
|
|
169
|
+
- Create a new connection per query (connection setup is expensive: TCP + TLS + auth)
|
|
170
|
+
- Set pool size equal to `max_connections` on the database (leave room for admin, monitoring, other services)
|
|
171
|
+
- Use unbounded pools (set a maximum to prevent connection exhaustion)
|
|
172
|
+
- Ignore idle connection cleanup (stale connections waste database resources)
|
|
173
|
+
- Share connection pools across unrelated services
|
|
174
|
+
|
|
175
|
+
## 6. Transactions and Locking
|
|
176
|
+
|
|
177
|
+
**DO:** Use transactions to maintain data integrity for multi-step operations.
|
|
178
|
+
|
|
179
|
+
- Choose the appropriate isolation level:
|
|
180
|
+
|
|
181
|
+
| Level | Dirty Read | Non-repeatable Read | Phantom Read | Use Case |
|
|
182
|
+
|-------|-----------|-------------------|-------------|---------|
|
|
183
|
+
| READ COMMITTED | No | Yes | Yes | Default for most apps |
|
|
184
|
+
| REPEATABLE READ | No | No | Yes | Financial reports |
|
|
185
|
+
| SERIALIZABLE | No | No | No | Critical financial ops |
|
|
186
|
+
|
|
187
|
+
- Use optimistic locking for low-contention updates:
|
|
188
|
+
```sql
|
|
189
|
+
-- Add version column
|
|
190
|
+
UPDATE orders SET status = 'shipped', version = version + 1
|
|
191
|
+
WHERE id = 123 AND version = 5;
|
|
192
|
+
-- If 0 rows affected: someone else updated first (retry or error)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- Use pessimistic locking (`SELECT ... FOR UPDATE`) only when contention is high and retries are expensive
|
|
196
|
+
- Keep transactions as short as possible -- do computation outside the transaction
|
|
197
|
+
- Always handle deadlocks: retry with exponential backoff (2-3 attempts max)
|
|
198
|
+
|
|
199
|
+
**DON'T:**
|
|
200
|
+
|
|
201
|
+
- Hold transactions open during user input or external API calls
|
|
202
|
+
- Use `SERIALIZABLE` as the default isolation level (performance impact)
|
|
203
|
+
- Nest transactions without understanding savepoint semantics
|
|
204
|
+
- Ignore deadlock errors -- they are expected in concurrent systems; handle them
|
|
205
|
+
- Lock entire tables when row-level locks suffice
|
|
206
|
+
|
|
207
|
+
## 7. Data Modeling Patterns
|
|
208
|
+
|
|
209
|
+
**DO:** Use established patterns for common data modeling challenges.
|
|
210
|
+
|
|
211
|
+
- **Soft deletes:** Add `deleted_at TIMESTAMP NULL` instead of removing rows. Filter with `WHERE deleted_at IS NULL` by default. Use a partial index for performance:
|
|
212
|
+
```sql
|
|
213
|
+
CREATE INDEX idx_users_active ON users(email) WHERE deleted_at IS NULL;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- **Temporal data (audit history):** Use a separate history table or event sourcing:
|
|
217
|
+
```sql
|
|
218
|
+
CREATE TABLE order_events (
|
|
219
|
+
id SERIAL PRIMARY KEY,
|
|
220
|
+
order_id INTEGER NOT NULL REFERENCES orders(id),
|
|
221
|
+
event_type TEXT NOT NULL, -- 'created', 'updated', 'shipped'
|
|
222
|
+
payload JSONB NOT NULL,
|
|
223
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
224
|
+
);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
- **Polymorphic associations:** Use a discriminator column or separate tables per type:
|
|
228
|
+
```sql
|
|
229
|
+
-- DO: Separate tables (type-safe, indexable)
|
|
230
|
+
CREATE TABLE comment_on_post (comment_id INT, post_id INT);
|
|
231
|
+
CREATE TABLE comment_on_photo (comment_id INT, photo_id INT);
|
|
232
|
+
|
|
233
|
+
-- Acceptable: Discriminator column (simpler, less type-safe)
|
|
234
|
+
CREATE TABLE comments (
|
|
235
|
+
id SERIAL, body TEXT,
|
|
236
|
+
commentable_type TEXT NOT NULL, -- 'post', 'photo'
|
|
237
|
+
commentable_id INTEGER NOT NULL
|
|
238
|
+
);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
- **JSON columns:** Use for semi-structured data that doesn't need relational queries. Index with GIN for JSONB queries:
|
|
242
|
+
```sql
|
|
243
|
+
ALTER TABLE products ADD COLUMN metadata JSONB;
|
|
244
|
+
CREATE INDEX idx_products_metadata ON products USING GIN(metadata);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**DON'T:**
|
|
248
|
+
|
|
249
|
+
- Use soft deletes without filtering them by default (data leaks)
|
|
250
|
+
- Store structured, queryable data in JSON columns (normalize instead)
|
|
251
|
+
- Create polymorphic foreign keys without application-level integrity checks
|
|
252
|
+
- Use EAV (Entity-Attribute-Value) pattern when a proper schema is feasible
|
|
253
|
+
|
|
254
|
+
## 8. Backup and Recovery
|
|
255
|
+
|
|
256
|
+
**DO:** Plan for data loss scenarios before they happen.
|
|
257
|
+
|
|
258
|
+
- Implement automated daily backups with point-in-time recovery (PITR) capability
|
|
259
|
+
- Store backups in a different region/account than the database
|
|
260
|
+
- Test backup restoration quarterly -- an untested backup is not a backup
|
|
261
|
+
- Document the recovery procedure: who, what, where, how long (RTO/RPO targets)
|
|
262
|
+
- Use logical backups (pg_dump, mysqldump) for portability and physical backups (WAL archiving, snapshots) for speed
|
|
263
|
+
|
|
264
|
+
**DON'T:**
|
|
265
|
+
|
|
266
|
+
- Keep backups on the same server/disk as the database
|
|
267
|
+
- Skip backup verification (restore to a test environment periodically)
|
|
268
|
+
- Rely solely on database replication as a backup strategy (replication propagates corruption)
|
|
269
|
+
- Store backup credentials in the same place as database credentials
|
|
270
|
+
- Assume cloud provider handles backup without verifying configuration and retention policy
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
---
|
|
2
|
+
# opencode-autopilot
|
|
3
|
+
name: docker-deployment
|
|
4
|
+
description: Dockerfile best practices, container orchestration, CI/CD deployment patterns, container security, and health checks
|
|
5
|
+
stacks: []
|
|
6
|
+
requires: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Docker and Deployment Patterns
|
|
10
|
+
|
|
11
|
+
Practical patterns for containerizing applications, orchestrating services, and deploying through CI/CD pipelines. Covers Dockerfile best practices, docker-compose patterns, CI/CD pipeline design, container security, health checks, logging, deployment strategies, and environment configuration. Apply these when building containers, reviewing Dockerfiles, designing pipelines, or troubleshooting deployments.
|
|
12
|
+
|
|
13
|
+
## 1. Dockerfile Best Practices
|
|
14
|
+
|
|
15
|
+
**DO:** Write Dockerfiles that produce small, secure, reproducible images.
|
|
16
|
+
|
|
17
|
+
- Use multi-stage builds to separate build dependencies from runtime:
|
|
18
|
+
```dockerfile
|
|
19
|
+
# Stage 1: Build
|
|
20
|
+
FROM node:20-alpine AS builder
|
|
21
|
+
WORKDIR /app
|
|
22
|
+
COPY package.json package-lock.json ./
|
|
23
|
+
RUN npm ci --production=false
|
|
24
|
+
COPY src/ src/
|
|
25
|
+
RUN npm run build
|
|
26
|
+
|
|
27
|
+
# Stage 2: Runtime (no build tools, no dev dependencies)
|
|
28
|
+
FROM node:20-alpine AS runtime
|
|
29
|
+
WORKDIR /app
|
|
30
|
+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
31
|
+
COPY --from=builder /app/dist ./dist
|
|
32
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
33
|
+
USER appuser
|
|
34
|
+
EXPOSE 3000
|
|
35
|
+
CMD ["node", "dist/server.js"]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Order layers from least to most frequently changing (dependencies before source code)
|
|
39
|
+
- Use `.dockerignore` to exclude unnecessary files:
|
|
40
|
+
```
|
|
41
|
+
node_modules
|
|
42
|
+
.git
|
|
43
|
+
.env
|
|
44
|
+
*.md
|
|
45
|
+
tests/
|
|
46
|
+
.github/
|
|
47
|
+
```
|
|
48
|
+
- Pin base image versions with SHA digests for reproducibility (get the digest from `docker pull <image>`):
|
|
49
|
+
```dockerfile
|
|
50
|
+
FROM node:20-alpine@sha256:<64-char-hex-digest>
|
|
51
|
+
```
|
|
52
|
+
- Use `COPY` instead of `ADD` (unless extracting archives)
|
|
53
|
+
- Combine `RUN` commands to reduce layers:
|
|
54
|
+
```dockerfile
|
|
55
|
+
RUN apk add --no-cache curl && \
|
|
56
|
+
curl -fsSL https://example.com/install.sh | sh && \
|
|
57
|
+
apk del curl
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**DON'T:**
|
|
61
|
+
|
|
62
|
+
- Use `latest` tag for base images (non-reproducible builds)
|
|
63
|
+
- Run containers as root (use `USER` directive)
|
|
64
|
+
- Copy the entire build context when only specific files are needed
|
|
65
|
+
- Store secrets in image layers (`ENV`, `ARG`, or `COPY` of `.env` files)
|
|
66
|
+
- Install unnecessary packages in the runtime image
|
|
67
|
+
- Use `apt-get upgrade` in Dockerfiles (non-reproducible; pin package versions instead)
|
|
68
|
+
|
|
69
|
+
## 2. Docker Compose Patterns
|
|
70
|
+
|
|
71
|
+
**DO:** Structure docker-compose files for development and testing environments.
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
services:
|
|
75
|
+
app:
|
|
76
|
+
build:
|
|
77
|
+
context: .
|
|
78
|
+
target: runtime
|
|
79
|
+
ports:
|
|
80
|
+
- "3000:3000"
|
|
81
|
+
environment:
|
|
82
|
+
- DATABASE_URL=postgres://user:pass@db:5432/myapp
|
|
83
|
+
- REDIS_URL=redis://cache:6379
|
|
84
|
+
depends_on:
|
|
85
|
+
db:
|
|
86
|
+
condition: service_healthy
|
|
87
|
+
cache:
|
|
88
|
+
condition: service_started
|
|
89
|
+
healthcheck:
|
|
90
|
+
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
|
91
|
+
interval: 10s
|
|
92
|
+
timeout: 5s
|
|
93
|
+
retries: 3
|
|
94
|
+
start_period: 15s
|
|
95
|
+
|
|
96
|
+
db:
|
|
97
|
+
image: postgres:16-alpine
|
|
98
|
+
volumes:
|
|
99
|
+
- pgdata:/var/lib/postgresql/data
|
|
100
|
+
env_file: .env # Never hardcode credentials — use env_file or Docker secrets
|
|
101
|
+
healthcheck:
|
|
102
|
+
test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
|
|
103
|
+
interval: 5s
|
|
104
|
+
timeout: 3s
|
|
105
|
+
retries: 5
|
|
106
|
+
|
|
107
|
+
cache:
|
|
108
|
+
image: redis:7-alpine
|
|
109
|
+
volumes:
|
|
110
|
+
- redisdata:/data
|
|
111
|
+
|
|
112
|
+
volumes:
|
|
113
|
+
pgdata:
|
|
114
|
+
redisdata:
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- Use `depends_on` with `condition: service_healthy` for startup ordering
|
|
118
|
+
- Define named volumes for persistent data
|
|
119
|
+
- Use `profiles` to group optional services (monitoring, debug tools)
|
|
120
|
+
- Use environment files for secrets in development: `env_file: .env.local`
|
|
121
|
+
|
|
122
|
+
**DON'T:**
|
|
123
|
+
|
|
124
|
+
- Use `links` (deprecated -- use networks and service names for DNS)
|
|
125
|
+
- Mount code volumes in production (use built images)
|
|
126
|
+
- Hardcode production credentials in docker-compose files
|
|
127
|
+
- Use `restart: always` without health checks (endlessly restarting a broken container)
|
|
128
|
+
|
|
129
|
+
## 3. CI/CD Pipeline Design
|
|
130
|
+
|
|
131
|
+
**DO:** Design pipelines with clear stages, fast feedback, and reliable deployments.
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
Pipeline stages:
|
|
135
|
+
1. Lint & Type Check (fast, catch obvious errors)
|
|
136
|
+
2. Unit Tests (parallel, cached)
|
|
137
|
+
3. Build (Docker image, artifacts)
|
|
138
|
+
4. Integration Tests (against real services via docker-compose)
|
|
139
|
+
5. Security Scan (image scanning, dependency audit)
|
|
140
|
+
6. Deploy to Staging (automatic on main branch)
|
|
141
|
+
7. Smoke Tests (against staging)
|
|
142
|
+
8. Deploy to Production (manual approval or automatic)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- Cache aggressively: dependencies, Docker layers, test results
|
|
146
|
+
- Run lint and unit tests in parallel for fast feedback (<5 min target)
|
|
147
|
+
- Use immutable artifacts: build once, deploy the same image to all environments
|
|
148
|
+
- Tag images with commit SHA (not `latest`) for traceability
|
|
149
|
+
- Implement environment promotion: dev -> staging -> production (same image)
|
|
150
|
+
|
|
151
|
+
**DON'T:**
|
|
152
|
+
|
|
153
|
+
- Build different images for different environments (build once, configure per environment)
|
|
154
|
+
- Skip integration tests to save time (they catch real issues)
|
|
155
|
+
- Deploy without a rollback plan
|
|
156
|
+
- Use CI secrets in build logs (mask all sensitive values)
|
|
157
|
+
- Run production deployments without a preceding staging test
|
|
158
|
+
|
|
159
|
+
## 4. Container Security
|
|
160
|
+
|
|
161
|
+
**DO:** Follow defense-in-depth principles for container security.
|
|
162
|
+
|
|
163
|
+
- Run containers as non-root users:
|
|
164
|
+
```dockerfile
|
|
165
|
+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
166
|
+
USER appuser
|
|
167
|
+
```
|
|
168
|
+
- Use read-only root filesystems where possible:
|
|
169
|
+
```yaml
|
|
170
|
+
services:
|
|
171
|
+
app:
|
|
172
|
+
read_only: true
|
|
173
|
+
tmpfs:
|
|
174
|
+
- /tmp
|
|
175
|
+
- /var/run
|
|
176
|
+
```
|
|
177
|
+
- Set resource limits to prevent DoS:
|
|
178
|
+
```yaml
|
|
179
|
+
services:
|
|
180
|
+
app:
|
|
181
|
+
deploy:
|
|
182
|
+
resources:
|
|
183
|
+
limits:
|
|
184
|
+
cpus: "1.0"
|
|
185
|
+
memory: 512M
|
|
186
|
+
reservations:
|
|
187
|
+
cpus: "0.25"
|
|
188
|
+
memory: 128M
|
|
189
|
+
```
|
|
190
|
+
- Scan images for vulnerabilities in CI (Trivy, Snyk, Grype)
|
|
191
|
+
- Use minimal base images (Alpine, distroless, scratch)
|
|
192
|
+
- Inject secrets via environment variables or mounted volumes at runtime -- never bake into images
|
|
193
|
+
|
|
194
|
+
**DON'T:**
|
|
195
|
+
|
|
196
|
+
- Run containers with `--privileged` (breaks all container isolation)
|
|
197
|
+
- Mount the Docker socket inside containers (enables container escape)
|
|
198
|
+
- Use images from untrusted registries without scanning
|
|
199
|
+
- Skip security scanning in CI ("it works" does not mean "it is safe")
|
|
200
|
+
- Store secrets in environment variables in docker-compose for production (use Docker secrets or external vault)
|
|
201
|
+
|
|
202
|
+
## 5. Health Checks and Readiness Probes
|
|
203
|
+
|
|
204
|
+
**DO:** Implement health checks at every level.
|
|
205
|
+
|
|
206
|
+
- **Liveness probe:** Is the process alive and not deadlocked?
|
|
207
|
+
```
|
|
208
|
+
GET /healthz -> 200 OK
|
|
209
|
+
Checks: process is running, not in deadlock
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
- **Readiness probe:** Can the service handle requests?
|
|
213
|
+
```
|
|
214
|
+
GET /readyz -> 200 OK
|
|
215
|
+
Checks: database connected, cache reachable, required services available
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
- **Startup probe:** Has the service finished initializing?
|
|
219
|
+
```
|
|
220
|
+
GET /startupz -> 200 OK
|
|
221
|
+
Use for services with long startup times (loading ML models, warming caches)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
- Return structured health check responses:
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"status": "healthy",
|
|
228
|
+
"checks": {
|
|
229
|
+
"database": { "status": "up", "latency_ms": 12 },
|
|
230
|
+
"cache": { "status": "up", "latency_ms": 2 },
|
|
231
|
+
"disk": { "status": "up", "free_gb": 45.2 }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**DON'T:**
|
|
237
|
+
|
|
238
|
+
- Use the same endpoint for liveness and readiness (different failure modes)
|
|
239
|
+
- Make liveness checks depend on external services (liveness = process health only)
|
|
240
|
+
- Set health check intervals too short (adds load) or too long (slow failure detection)
|
|
241
|
+
- Return 200 from health endpoints when the service is actually degraded
|
|
242
|
+
|
|
243
|
+
## 6. Logging and Monitoring
|
|
244
|
+
|
|
245
|
+
**DO:** Design containers for observability from the start.
|
|
246
|
+
|
|
247
|
+
- Write logs to stdout/stderr (let the platform handle collection):
|
|
248
|
+
```
|
|
249
|
+
// DO: stdout logging
|
|
250
|
+
console.log(JSON.stringify({ level: "info", msg: "Order created", orderId: 123 }))
|
|
251
|
+
|
|
252
|
+
// DON'T: File logging inside container
|
|
253
|
+
fs.appendFileSync("/var/log/app.log", message)
|
|
254
|
+
```
|
|
255
|
+
- Use structured JSON logging for machine parsing
|
|
256
|
+
- Include correlation IDs in all log entries for request tracing
|
|
257
|
+
- Export metrics in a standard format (Prometheus, OpenTelemetry)
|
|
258
|
+
- Set up alerts for: error rate spikes, latency p99 increases, resource saturation
|
|
259
|
+
|
|
260
|
+
**DON'T:**
|
|
261
|
+
|
|
262
|
+
- Log to files inside containers (ephemeral filesystems, lost on restart)
|
|
263
|
+
- Log sensitive data (credentials, PII, tokens)
|
|
264
|
+
- Use log levels inconsistently (ERROR for expected conditions, INFO for everything)
|
|
265
|
+
- Skip correlation IDs (impossible to trace requests across services without them)
|
|
266
|
+
|
|
267
|
+
## 7. Deployment Strategies
|
|
268
|
+
|
|
269
|
+
**DO:** Choose deployment strategies based on risk tolerance and infrastructure capabilities.
|
|
270
|
+
|
|
271
|
+
- **Rolling update** (default): Replace instances gradually. Zero downtime. Requires backward-compatible changes.
|
|
272
|
+
```yaml
|
|
273
|
+
deploy:
|
|
274
|
+
update_config:
|
|
275
|
+
parallelism: 1
|
|
276
|
+
delay: 10s
|
|
277
|
+
order: start-first
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
- **Blue-green:** Run two identical environments. Switch traffic atomically. Instant rollback by switching back.
|
|
281
|
+
- Best for: critical services, database schema changes, major version upgrades
|
|
282
|
+
- Cost: 2x infrastructure during deployment
|
|
283
|
+
|
|
284
|
+
- **Canary:** Route a small percentage of traffic to the new version. Monitor metrics. Gradually increase.
|
|
285
|
+
- Best for: high-traffic services, risky changes, A/B testing infrastructure
|
|
286
|
+
- Requires: traffic routing (load balancer rules, service mesh)
|
|
287
|
+
|
|
288
|
+
**DON'T:**
|
|
289
|
+
|
|
290
|
+
- Deploy without a rollback plan (every deployment should be reversible within minutes)
|
|
291
|
+
- Use recreate strategy in production (causes downtime)
|
|
292
|
+
- Skip smoke tests after deployment (verify the new version actually works)
|
|
293
|
+
- Deploy breaking changes without a migration strategy (expand-contract pattern)
|
|
294
|
+
|
|
295
|
+
## 8. Environment Configuration (12-Factor App)
|
|
296
|
+
|
|
297
|
+
**DO:** Configure applications through the environment, not through code.
|
|
298
|
+
|
|
299
|
+
- Store config in environment variables (database URLs, API keys, feature flags)
|
|
300
|
+
- Use a `.env.example` file (committed) to document required variables:
|
|
301
|
+
```
|
|
302
|
+
# .env.example (committed to repo)
|
|
303
|
+
DATABASE_URL=postgres://user:password@localhost:5432/myapp
|
|
304
|
+
REDIS_URL=redis://localhost:6379
|
|
305
|
+
API_KEY=your-api-key-here
|
|
306
|
+
LOG_LEVEL=info
|
|
307
|
+
```
|
|
308
|
+
- Validate all environment variables at startup -- fail fast if missing:
|
|
309
|
+
```
|
|
310
|
+
const required = ["DATABASE_URL", "API_KEY", "SESSION_SECRET"]
|
|
311
|
+
for (const key of required) {
|
|
312
|
+
if (!process.env[key]) {
|
|
313
|
+
throw new Error("Missing required environment variable: " + key)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
- Use different values per environment (dev, staging, production) -- same code, different config
|
|
318
|
+
- Use platform-native secret injection (Kubernetes secrets, AWS Parameter Store, Docker secrets)
|
|
319
|
+
|
|
320
|
+
**DON'T:**
|
|
321
|
+
|
|
322
|
+
- Hardcode environment-specific values in source code
|
|
323
|
+
- Commit `.env` files with real credentials to version control
|
|
324
|
+
- Use different code paths per environment (`if (env === 'production')` for config)
|
|
325
|
+
- Mix application config with infrastructure config in the same file
|
|
326
|
+
- Store secrets in ConfigMaps or plain environment variables in production (use encrypted secret stores)
|