@wipal/agent-team 1.0.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/.claude/rules/common/general-rules.md +141 -0
- package/.claude/rules/lessons/lessons.md +91 -0
- package/.claude/rules/role-rules/dev-fe-rules.md +146 -0
- package/.claude/rules/role-rules/sa-rules.md +226 -0
- package/.claude/skills/SKILL-INDEX.md +299 -0
- package/.claude/skills/community/security-validator/SKILL.md +392 -0
- package/.claude/skills/core/agent-creation/SKILL.md +338 -0
- package/.claude/skills/core/code-review/SKILL.md +154 -0
- package/.claude/skills/core/git-automation/SKILL.md +93 -0
- package/.claude/skills/core/retrospect-work/SKILL.md +172 -0
- package/.claude/skills/domain/architecture/adr-writing/SKILL.md +254 -0
- package/.claude/skills/domain/architecture/adr-writing/references/adr-best-practices.md +257 -0
- package/.claude/skills/domain/architecture/adr-writing/references/adr-examples.md +246 -0
- package/.claude/skills/domain/architecture/adr-writing/references/adr-template.md +160 -0
- package/.claude/skills/domain/architecture/architecture-patterns/SKILL.md +316 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/event-driven.md +393 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/microservices.md +315 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/monolith.md +321 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/serverless.md +457 -0
- package/.claude/skills/domain/architecture/performance-engineering/SKILL.md +227 -0
- package/.claude/skills/domain/architecture/performance-engineering/references/benchmarking.md +336 -0
- package/.claude/skills/domain/architecture/performance-engineering/references/caching-strategies.md +284 -0
- package/.claude/skills/domain/architecture/performance-engineering/references/optimization.md +298 -0
- package/.claude/skills/domain/architecture/security-architecture/SKILL.md +206 -0
- package/.claude/skills/domain/architecture/security-architecture/references/auth-patterns.md +209 -0
- package/.claude/skills/domain/architecture/security-architecture/references/compliance.md +246 -0
- package/.claude/skills/domain/architecture/security-architecture/references/threat-modeling.md +219 -0
- package/.claude/skills/domain/architecture/system-design/SKILL.md +227 -0
- package/.claude/skills/domain/architecture/system-design/references/distributed-systems.md +231 -0
- package/.claude/skills/domain/architecture/system-design/references/resilience.md +344 -0
- package/.claude/skills/domain/architecture/system-design/references/scalability.md +303 -0
- package/.claude/skills/domain/architecture/tech-selection/SKILL.md +192 -0
- package/.claude/skills/domain/architecture/tech-selection/references/build-vs-buy.md +258 -0
- package/.claude/skills/domain/architecture/tech-selection/references/evaluation-framework.md +203 -0
- package/.claude/skills/domain/architecture/tech-selection/references/tech-radar.md +257 -0
- package/.claude/skills/domain/backend/api-design/SKILL.md +121 -0
- package/.claude/skills/domain/backend/database-design/SKILL.md +156 -0
- package/.claude/skills/domain/backend/performance-be/SKILL.md +210 -0
- package/.claude/skills/domain/backend/security/SKILL.md +138 -0
- package/.claude/skills/domain/backend/testing-be/SKILL.md +203 -0
- package/.claude/skills/domain/devops/ci-cd/SKILL.md +188 -0
- package/.claude/skills/domain/devops/containerization/SKILL.md +177 -0
- package/.claude/skills/domain/devops/deployment/SKILL.md +198 -0
- package/.claude/skills/domain/devops/infrastructure-as-code/SKILL.md +178 -0
- package/.claude/skills/domain/devops/monitoring/SKILL.md +163 -0
- package/.claude/skills/domain/frontend/accessibility/SKILL.md +179 -0
- package/.claude/skills/domain/frontend/frontend-design/SKILL.md +138 -0
- package/.claude/skills/domain/frontend/performance-fe/SKILL.md +195 -0
- package/.claude/skills/domain/frontend/state-management/SKILL.md +190 -0
- package/.claude/skills/domain/frontend/testing-fe/SKILL.md +193 -0
- package/.claude/skills/domain/product/requirements-gathering/SKILL.md +136 -0
- package/.claude/skills/domain/product/roadmap-planning/SKILL.md +169 -0
- package/.claude/skills/domain/product/sprint-planning/SKILL.md +151 -0
- package/.claude/skills/domain/product/stakeholder-communication/SKILL.md +162 -0
- package/.claude/skills/domain/product/user-stories/SKILL.md +141 -0
- package/.claude/skills/domain/quality/bug-reporting/SKILL.md +150 -0
- package/.claude/skills/domain/quality/regression-testing/SKILL.md +178 -0
- package/.claude/skills/domain/quality/test-automation/SKILL.md +185 -0
- package/.claude/skills/domain/quality/test-planning/SKILL.md +177 -0
- package/.claude/skills/leadership/code-review-advanced/SKILL.md +167 -0
- package/.claude/skills/leadership/mentoring/SKILL.md +151 -0
- package/.claude/skills/leadership/technical-debt/SKILL.md +166 -0
- package/.claude/skills/leadership/technical-decision/SKILL.md +160 -0
- package/.claude/skills/security-reports/.gitkeep +0 -0
- package/.claude/skills/skills-registry.yaml +441 -0
- package/README.md +232 -0
- package/bin/agent-team.js +107 -0
- package/package.json +51 -0
- package/src/commands/add.js +227 -0
- package/src/commands/init.js +136 -0
- package/src/commands/list.js +66 -0
- package/src/commands/remove.js +71 -0
- package/src/commands/switch.js +53 -0
- package/src/index.js +11 -0
- package/src/interactive/prompts.js +153 -0
- package/src/server/api/agents.js +150 -0
- package/src/server/api/roles.js +97 -0
- package/src/server/api/skills.js +79 -0
- package/src/server/index.js +78 -0
- package/src/ui/agents.html +174 -0
- package/src/ui/css/styles.css +470 -0
- package/src/ui/index.html +107 -0
- package/src/ui/roles.html +371 -0
- package/src/ui/skills.html +332 -0
- package/src/utils/file-utils.js +193 -0
- package/src/utils/skill-resolver.js +594 -0
- package/src/utils/skill-scanner.js +154 -0
- package/templates/CLAUDE.md.tmpl +42 -0
- package/templates/knowledge.md.tmpl +31 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-be
|
|
3
|
+
description: |
|
|
4
|
+
Backend testing patterns with Jest, Vitest, and integration testing. Use when:
|
|
5
|
+
writing unit tests, integration tests, API tests, or when user mentions "test",
|
|
6
|
+
"unit test", "integration test", "API test", "mock", "fixture". Test behavior,
|
|
7
|
+
not implementation.
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
category: backend
|
|
10
|
+
tags:
|
|
11
|
+
- testing
|
|
12
|
+
- unit-test
|
|
13
|
+
- integration-test
|
|
14
|
+
- api-test
|
|
15
|
+
depends_on:
|
|
16
|
+
- code-review
|
|
17
|
+
- api-design
|
|
18
|
+
recommends: []
|
|
19
|
+
used_by: []
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Skill: Testing BE
|
|
23
|
+
|
|
24
|
+
## Core Principle
|
|
25
|
+
**Test behavior, not implementation.** Good tests survive refactors. They document expected behavior.
|
|
26
|
+
|
|
27
|
+
## Testing Pyramid
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
▲
|
|
31
|
+
/E2E\ Few, slow
|
|
32
|
+
/─────\
|
|
33
|
+
/ API \ Some, medium
|
|
34
|
+
/─────────\
|
|
35
|
+
/ Unit \ Many, fast
|
|
36
|
+
/─────────────\
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Hard Rules
|
|
40
|
+
|
|
41
|
+
1. **NEVER test implementation** - Test behavior/output
|
|
42
|
+
2. **NEVER share state between tests** - Each test is isolated
|
|
43
|
+
3. **ALWAYS clean up resources** - Close connections, delete data
|
|
44
|
+
4. **ALWAYS use descriptive names** - `should_..._when_...`
|
|
45
|
+
5. **ALWAYS mock external services** - No real API calls
|
|
46
|
+
|
|
47
|
+
## Unit Tests
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// userService.test.ts
|
|
51
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
52
|
+
import { UserService } from './userService';
|
|
53
|
+
import { UserRepository } from './userRepository';
|
|
54
|
+
|
|
55
|
+
describe('UserService', () => {
|
|
56
|
+
let service: UserService;
|
|
57
|
+
let mockRepo: UserRepository;
|
|
58
|
+
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
mockRepo = {
|
|
61
|
+
findById: vi.fn(),
|
|
62
|
+
create: vi.fn(),
|
|
63
|
+
update: vi.fn(),
|
|
64
|
+
};
|
|
65
|
+
service = new UserService(mockRepo);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('getUser', () => {
|
|
69
|
+
it('should return user when found', async () => {
|
|
70
|
+
const mockUser = { id: '1', name: 'John' };
|
|
71
|
+
vi.mocked(mockRepo.findById).mockResolvedValue(mockUser);
|
|
72
|
+
|
|
73
|
+
const result = await service.getUser('1');
|
|
74
|
+
|
|
75
|
+
expect(result).toEqual(mockUser);
|
|
76
|
+
expect(mockRepo.findById).toHaveBeenCalledWith('1');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should throw NotFoundError when user not found', async () => {
|
|
80
|
+
vi.mocked(mockRepo.findById).mockResolvedValue(null);
|
|
81
|
+
|
|
82
|
+
await expect(service.getUser('999')).rejects.toThrow(NotFoundError);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Integration Tests
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// api.test.ts
|
|
92
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
93
|
+
import { FastifyInstance } from 'fastify';
|
|
94
|
+
import { buildApp } from './app';
|
|
95
|
+
import { prisma } from './db';
|
|
96
|
+
|
|
97
|
+
describe('User API', () => {
|
|
98
|
+
let app: FastifyInstance;
|
|
99
|
+
|
|
100
|
+
beforeAll(async () => {
|
|
101
|
+
app = await buildApp();
|
|
102
|
+
await app.ready();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
afterAll(async () => {
|
|
106
|
+
await app.close();
|
|
107
|
+
await prisma.$disconnect();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('GET /users/:id', () => {
|
|
111
|
+
it('should return user', async () => {
|
|
112
|
+
const user = await prisma.user.create({
|
|
113
|
+
data: { name: 'Test User', email: 'test@example.com' },
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const response = await app.inject({
|
|
117
|
+
method: 'GET',
|
|
118
|
+
url: `/users/${user.id}`,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
expect(response.statusCode).toBe(200);
|
|
122
|
+
expect(response.json()).toMatchObject({
|
|
123
|
+
id: user.id,
|
|
124
|
+
name: 'Test User',
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Test Database
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// test/setup.ts
|
|
135
|
+
import { PrismaClient } from '@prisma/client';
|
|
136
|
+
import { execSync } from 'child_process';
|
|
137
|
+
|
|
138
|
+
const prisma = new PrismaClient();
|
|
139
|
+
|
|
140
|
+
beforeAll(async () => {
|
|
141
|
+
// Use test database
|
|
142
|
+
process.env.DATABASE_URL = 'postgresql://test:test@localhost:5432/test_db';
|
|
143
|
+
|
|
144
|
+
// Run migrations
|
|
145
|
+
execSync('npx prisma migrate deploy');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
afterEach(async () => {
|
|
149
|
+
// Clean up between tests
|
|
150
|
+
const tables = ['User', 'Order', 'Product'];
|
|
151
|
+
for (const table of tables) {
|
|
152
|
+
await prisma.$executeRawUnsafe(`TRUNCATE TABLE "${table}" CASCADE`);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
afterAll(async () => {
|
|
157
|
+
await prisma.$disconnect();
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Common Mistakes
|
|
162
|
+
|
|
163
|
+
| ❌ Mistake | ✅ Fix |
|
|
164
|
+
|------------|--------|
|
|
165
|
+
| Testing private methods | Test public interface |
|
|
166
|
+
| Shared mutable state | Isolated test data |
|
|
167
|
+
| Real external APIs | Mock them |
|
|
168
|
+
| Slow tests | Use in-memory DB |
|
|
169
|
+
| Flaky tests | Fix or delete |
|
|
170
|
+
|
|
171
|
+
## Mocking Patterns
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// Mock module
|
|
175
|
+
vi.mock('./emailService', () => ({
|
|
176
|
+
sendEmail: vi.fn().mockResolvedValue({ success: true }),
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
// Mock environment
|
|
180
|
+
vi.stubEnv('NODE_ENV', 'test');
|
|
181
|
+
|
|
182
|
+
// Mock time
|
|
183
|
+
vi.useFakeTimers();
|
|
184
|
+
vi.setSystemTime(new Date('2024-01-01'));
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Test Naming
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// Pattern: should_[expected]_when_[condition]
|
|
191
|
+
it('should_return_empty_list_when_no_users_exist')
|
|
192
|
+
it('should_throw_ValidationError_when_email_invalid')
|
|
193
|
+
it('should_create_order_when_valid_request')
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Quick Checklist
|
|
197
|
+
|
|
198
|
+
- [ ] Each test is isolated
|
|
199
|
+
- [ ] External services mocked
|
|
200
|
+
- [ ] Database cleaned between tests
|
|
201
|
+
- [ ] Descriptive test names
|
|
202
|
+
- [ ] Fast test execution
|
|
203
|
+
- [ ] CI integration
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ci-cd
|
|
3
|
+
description: |
|
|
4
|
+
CI/CD pipeline design and implementation for GitHub Actions, GitLab CI.
|
|
5
|
+
Use when: setting up pipelines, automating builds, running tests automatically,
|
|
6
|
+
deploying code, or when user mentions "CI", "CD", "pipeline", "GitHub Actions",
|
|
7
|
+
"GitLab CI", "build", "deploy", "automation". Ensures reliable, fast pipelines.
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
category: devops
|
|
10
|
+
tags:
|
|
11
|
+
- ci-cd
|
|
12
|
+
- github-actions
|
|
13
|
+
- gitlab-ci
|
|
14
|
+
- automation
|
|
15
|
+
- pipeline
|
|
16
|
+
depends_on:
|
|
17
|
+
- git-automation
|
|
18
|
+
recommends:
|
|
19
|
+
- containerization
|
|
20
|
+
- deployment
|
|
21
|
+
used_by:
|
|
22
|
+
- deployment
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Skill: CI/CD
|
|
26
|
+
|
|
27
|
+
## Core Principle
|
|
28
|
+
**Fast, reliable, automated pipelines.** Every commit should be tested. Every merge should be deployable.
|
|
29
|
+
|
|
30
|
+
## Hard Rules
|
|
31
|
+
|
|
32
|
+
1. **NEVER skip tests in CI** - Tests are mandatory
|
|
33
|
+
2. **NEVER store secrets in code** - Use secrets management
|
|
34
|
+
3. **ALWAYS fail fast** - Run fastest tests first
|
|
35
|
+
4. **ALWAYS cache dependencies** - Speed matters
|
|
36
|
+
5. **ALWAYS use specific action versions** - Not `@main` or `@latest`
|
|
37
|
+
|
|
38
|
+
## Pipeline Stages
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
42
|
+
│ Lint │──▶│ Build │──▶│ Test │──▶│ Deploy │
|
|
43
|
+
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
|
44
|
+
(1 min) (3 min) (5 min) (2 min)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## GitHub Actions Template
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
# .github/workflows/ci.yml
|
|
51
|
+
name: CI
|
|
52
|
+
|
|
53
|
+
on:
|
|
54
|
+
push:
|
|
55
|
+
branches: [main]
|
|
56
|
+
pull_request:
|
|
57
|
+
branches: [main]
|
|
58
|
+
|
|
59
|
+
env:
|
|
60
|
+
NODE_VERSION: '20'
|
|
61
|
+
|
|
62
|
+
jobs:
|
|
63
|
+
lint:
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
- uses: actions/setup-node@v4
|
|
68
|
+
with:
|
|
69
|
+
node-version: ${{ env.NODE_VERSION }}
|
|
70
|
+
cache: 'npm'
|
|
71
|
+
- run: npm ci
|
|
72
|
+
- run: npm run lint
|
|
73
|
+
|
|
74
|
+
test:
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
needs: lint
|
|
77
|
+
steps:
|
|
78
|
+
- uses: actions/checkout@v4
|
|
79
|
+
- uses: actions/setup-node@v4
|
|
80
|
+
with:
|
|
81
|
+
node-version: ${{ env.NODE_VERSION }}
|
|
82
|
+
cache: 'npm'
|
|
83
|
+
- run: npm ci
|
|
84
|
+
- run: npm run test:coverage
|
|
85
|
+
- uses: codecov/codecov-action@v4
|
|
86
|
+
with:
|
|
87
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
88
|
+
|
|
89
|
+
build:
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
needs: test
|
|
92
|
+
steps:
|
|
93
|
+
- uses: actions/checkout@v4
|
|
94
|
+
- uses: actions/setup-node@v4
|
|
95
|
+
with:
|
|
96
|
+
node-version: ${{ env.NODE_VERSION }}
|
|
97
|
+
cache: 'npm'
|
|
98
|
+
- run: npm ci
|
|
99
|
+
- run: npm run build
|
|
100
|
+
- uses: actions/upload-artifact@v4
|
|
101
|
+
with:
|
|
102
|
+
name: build
|
|
103
|
+
path: dist/
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## GitLab CI Template
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
# .gitlab-ci.yml
|
|
110
|
+
stages:
|
|
111
|
+
- lint
|
|
112
|
+
- test
|
|
113
|
+
- build
|
|
114
|
+
- deploy
|
|
115
|
+
|
|
116
|
+
variables:
|
|
117
|
+
NODE_VERSION: '20'
|
|
118
|
+
|
|
119
|
+
.node_template:
|
|
120
|
+
image: node:${NODE_VERSION}
|
|
121
|
+
cache:
|
|
122
|
+
paths:
|
|
123
|
+
- node_modules/
|
|
124
|
+
|
|
125
|
+
lint:
|
|
126
|
+
extends: .node_template
|
|
127
|
+
stage: lint
|
|
128
|
+
script:
|
|
129
|
+
- npm ci
|
|
130
|
+
- npm run lint
|
|
131
|
+
|
|
132
|
+
test:
|
|
133
|
+
extends: .node_template
|
|
134
|
+
stage: test
|
|
135
|
+
script:
|
|
136
|
+
- npm ci
|
|
137
|
+
- npm run test:coverage
|
|
138
|
+
coverage: '/Lines\s*:\s*(\d+.\d+)%/'
|
|
139
|
+
|
|
140
|
+
build:
|
|
141
|
+
extends: .node_template
|
|
142
|
+
stage: build
|
|
143
|
+
script:
|
|
144
|
+
- npm ci
|
|
145
|
+
- npm run build
|
|
146
|
+
artifacts:
|
|
147
|
+
paths:
|
|
148
|
+
- dist/
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Common Mistakes
|
|
152
|
+
|
|
153
|
+
| ❌ Mistake | ✅ Fix |
|
|
154
|
+
|------------|--------|
|
|
155
|
+
| Using `@main` for actions | Pin to version: `@v4.0.0` |
|
|
156
|
+
| No caching | Add `cache: 'npm'` |
|
|
157
|
+
| Running all tests at once | Parallelize, matrix strategy |
|
|
158
|
+
| Secrets in code | Use GitHub/GitLab secrets |
|
|
159
|
+
| Long pipelines | Fail fast, cache, parallelize |
|
|
160
|
+
|
|
161
|
+
## Performance Optimization
|
|
162
|
+
|
|
163
|
+
```yaml
|
|
164
|
+
# Matrix strategy for parallel tests
|
|
165
|
+
strategy:
|
|
166
|
+
matrix:
|
|
167
|
+
shard: [1/4, 2/4, 3/4, 4/4]
|
|
168
|
+
steps:
|
|
169
|
+
- run: npm run test -- --shard=${{ matrix.shard }}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Security Best Practices
|
|
173
|
+
|
|
174
|
+
- Use `SECRETS` for sensitive data
|
|
175
|
+
- Limit `GITHUB_TOKEN` permissions
|
|
176
|
+
- Pin action versions
|
|
177
|
+
- Scan for vulnerabilities
|
|
178
|
+
- Use OIDC for cloud auth
|
|
179
|
+
|
|
180
|
+
## Quick Checklist
|
|
181
|
+
|
|
182
|
+
- [ ] Tests run on every PR
|
|
183
|
+
- [ ] Dependencies cached
|
|
184
|
+
- [ ] Actions pinned to versions
|
|
185
|
+
- [ ] Secrets properly managed
|
|
186
|
+
- [ ] Pipeline fails fast
|
|
187
|
+
- [ ] Build artifacts uploaded
|
|
188
|
+
- [ ] Coverage reported
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: containerization
|
|
3
|
+
description: |
|
|
4
|
+
Docker containerization patterns and best practices. Use when: creating
|
|
5
|
+
Dockerfiles, building images, optimizing container size, multi-stage builds,
|
|
6
|
+
or when user mentions "Docker", "container", "image", "Dockerfile", "Compose".
|
|
7
|
+
Ensures efficient, secure, production-ready containers.
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
category: devops
|
|
10
|
+
tags:
|
|
11
|
+
- docker
|
|
12
|
+
- containers
|
|
13
|
+
- containerization
|
|
14
|
+
- images
|
|
15
|
+
depends_on: []
|
|
16
|
+
recommends:
|
|
17
|
+
- ci-cd
|
|
18
|
+
- deployment
|
|
19
|
+
used_by:
|
|
20
|
+
- deployment
|
|
21
|
+
- ci-cd
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Skill: Containerization
|
|
25
|
+
|
|
26
|
+
## Core Principle
|
|
27
|
+
**Small, secure, immutable containers.** Every byte matters. Every layer counts.
|
|
28
|
+
|
|
29
|
+
## Hard Rules
|
|
30
|
+
|
|
31
|
+
1. **NEVER run as root** - Use non-root user
|
|
32
|
+
2. **NEVER store secrets in images** - Use environment variables
|
|
33
|
+
3. **ALWAYS use multi-stage builds** - Separate build from runtime
|
|
34
|
+
4. **ALWAYS pin base image versions** - Not `:latest`
|
|
35
|
+
5. **ALWAYS minimize layers** - Combine RUN commands
|
|
36
|
+
|
|
37
|
+
## Multi-Stage Dockerfile
|
|
38
|
+
|
|
39
|
+
```dockerfile
|
|
40
|
+
# Build stage
|
|
41
|
+
FROM node:20-alpine AS builder
|
|
42
|
+
WORKDIR /app
|
|
43
|
+
COPY package*.json ./
|
|
44
|
+
RUN npm ci --only=production
|
|
45
|
+
|
|
46
|
+
# Runtime stage
|
|
47
|
+
FROM node:20-alpine AS runtime
|
|
48
|
+
|
|
49
|
+
# Security: non-root user
|
|
50
|
+
RUN addgroup -g 1001 -S nodejs && \
|
|
51
|
+
adduser -S nextjs -u 1001
|
|
52
|
+
|
|
53
|
+
WORKDIR /app
|
|
54
|
+
|
|
55
|
+
# Copy only production dependencies
|
|
56
|
+
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
|
|
57
|
+
COPY --chown=nextjs:nodejs . .
|
|
58
|
+
|
|
59
|
+
USER nextjs
|
|
60
|
+
|
|
61
|
+
EXPOSE 3000
|
|
62
|
+
|
|
63
|
+
HEALTHCHECK --interval=30s --timeout=3s \
|
|
64
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
|
|
65
|
+
|
|
66
|
+
CMD ["node", "server.js"]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Docker Compose Template
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
# docker-compose.yml
|
|
73
|
+
version: '3.8'
|
|
74
|
+
|
|
75
|
+
services:
|
|
76
|
+
app:
|
|
77
|
+
build:
|
|
78
|
+
context: .
|
|
79
|
+
dockerfile: Dockerfile
|
|
80
|
+
target: runtime
|
|
81
|
+
ports:
|
|
82
|
+
- "3000:3000"
|
|
83
|
+
environment:
|
|
84
|
+
- NODE_ENV=production
|
|
85
|
+
- DATABASE_URL=${DATABASE_URL}
|
|
86
|
+
depends_on:
|
|
87
|
+
- db
|
|
88
|
+
healthcheck:
|
|
89
|
+
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
|
|
90
|
+
interval: 30s
|
|
91
|
+
timeout: 3s
|
|
92
|
+
retries: 3
|
|
93
|
+
|
|
94
|
+
db:
|
|
95
|
+
image: postgres:16-alpine
|
|
96
|
+
volumes:
|
|
97
|
+
- postgres_data:/var/lib/postgresql/data
|
|
98
|
+
environment:
|
|
99
|
+
- POSTGRES_USER=${DB_USER}
|
|
100
|
+
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
|
101
|
+
healthcheck:
|
|
102
|
+
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
|
|
103
|
+
interval: 10s
|
|
104
|
+
timeout: 3s
|
|
105
|
+
|
|
106
|
+
volumes:
|
|
107
|
+
postgres_data:
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Common Mistakes
|
|
111
|
+
|
|
112
|
+
| ❌ Mistake | ✅ Fix |
|
|
113
|
+
|------------|--------|
|
|
114
|
+
| `FROM node:latest` | `FROM node:20-alpine` |
|
|
115
|
+
| Running as root | Add non-root user |
|
|
116
|
+
| No health check | Add HEALTHCHECK |
|
|
117
|
+
| Large images | Multi-stage builds |
|
|
118
|
+
| Secrets in ENV | Use Docker secrets |
|
|
119
|
+
| Single layer | Combine RUN commands |
|
|
120
|
+
|
|
121
|
+
## Image Size Optimization
|
|
122
|
+
|
|
123
|
+
```dockerfile
|
|
124
|
+
# ❌ Bad: Multiple layers, large image
|
|
125
|
+
RUN npm install
|
|
126
|
+
RUN npm run build
|
|
127
|
+
RUN npm prune
|
|
128
|
+
|
|
129
|
+
# ✅ Good: Single layer, smaller image
|
|
130
|
+
RUN npm ci --only=production && \
|
|
131
|
+
npm cache clean --force
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Security Checklist
|
|
135
|
+
|
|
136
|
+
```dockerfile
|
|
137
|
+
# 1. Non-root user
|
|
138
|
+
USER appuser
|
|
139
|
+
|
|
140
|
+
# 2. Read-only filesystem
|
|
141
|
+
COPY --chown=appuser:appgroup . .
|
|
142
|
+
|
|
143
|
+
# 3. No secrets
|
|
144
|
+
# Use docker secrets or environment
|
|
145
|
+
|
|
146
|
+
# 4. Minimal base image
|
|
147
|
+
FROM alpine:3.19
|
|
148
|
+
|
|
149
|
+
# 5. Health check
|
|
150
|
+
HEALTHCHECK CMD curl -f http://localhost/health || exit 1
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Quick Commands
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Build
|
|
157
|
+
docker build -t myapp:v1.0.0 .
|
|
158
|
+
|
|
159
|
+
# Run
|
|
160
|
+
docker run -d -p 3000:3000 --env-file .env myapp:v1.0.0
|
|
161
|
+
|
|
162
|
+
# Debug
|
|
163
|
+
docker exec -it <container> sh
|
|
164
|
+
|
|
165
|
+
# Clean up
|
|
166
|
+
docker system prune -af
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Quick Checklist
|
|
170
|
+
|
|
171
|
+
- [ ] Multi-stage build used
|
|
172
|
+
- [ ] Base image pinned to version
|
|
173
|
+
- [ ] Non-root user configured
|
|
174
|
+
- [ ] Health check added
|
|
175
|
+
- [ ] Secrets not in image
|
|
176
|
+
- [ ] Layers minimized
|
|
177
|
+
- [ ] .dockerignore present
|