@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,334 @@
1
+ ---
2
+ paths:
3
+ - "**/*.ts"
4
+ - "**/*.tsx"
5
+ - "**/*.js"
6
+ - "**/*.py"
7
+ - "**/*.cs"
8
+ ---
9
+
10
+ # Software Engineering Principles
11
+
12
+ ## YAGNI - You Aren't Gonna Need It
13
+
14
+ Don't implement features until they're actually needed.
15
+
16
+ ```typescript
17
+ // BAD - Building for hypothetical future
18
+ interface UserService {
19
+ getUser(id: string): User;
20
+ getUserWithCache(id: string, ttl?: number): User;
21
+ getUserAsync(id: string): Promise<User>;
22
+ getUserBatch(ids: string[]): User[];
23
+ getUserByEmail(email: string): User;
24
+ getUserByPhone(phone: string): User; // No one asked for this
25
+ getUserBySSN(ssn: string): User; // No one asked for this
26
+ }
27
+
28
+ // GOOD - Only what's needed now
29
+ interface UserService {
30
+ getUser(id: string): Promise<User>;
31
+ getUserByEmail(email: string): Promise<User>;
32
+ }
33
+ ```
34
+
35
+ ```typescript
36
+ // BAD - Premature abstraction
37
+ class AbstractDataProcessor<T, R, C extends Config> {
38
+ // 200 lines of "flexible" code no one uses
39
+ }
40
+
41
+ // GOOD - Concrete implementation
42
+ function processUserData(users: User[]): ProcessedUser[] {
43
+ return users.map(u => ({ ...u, fullName: `${u.first} ${u.last}` }));
44
+ }
45
+ ```
46
+
47
+ ## KISS - Keep It Simple, Stupid
48
+
49
+ Choose the simplest solution that works.
50
+
51
+ ```typescript
52
+ // BAD - Over-engineered
53
+ class StringUtils {
54
+ private static instance: StringUtils;
55
+ private constructor() {}
56
+
57
+ static getInstance(): StringUtils {
58
+ if (!this.instance) this.instance = new StringUtils();
59
+ return this.instance;
60
+ }
61
+
62
+ capitalize(str: string): string {
63
+ return str.charAt(0).toUpperCase() + str.slice(1);
64
+ }
65
+ }
66
+ // Usage: StringUtils.getInstance().capitalize('hello')
67
+
68
+ // GOOD - Simple function
69
+ function capitalize(str: string): string {
70
+ return str.charAt(0).toUpperCase() + str.slice(1);
71
+ }
72
+ // Usage: capitalize('hello')
73
+ ```
74
+
75
+ ```typescript
76
+ // BAD - Unnecessary complexity
77
+ const isAdult = (age: number) =>
78
+ new AgeValidator(new AgePolicy(18)).validate(age).isValid();
79
+
80
+ // GOOD - Direct and clear
81
+ const isAdult = (age: number) => age >= 18;
82
+ ```
83
+
84
+ ## SOLID Principles
85
+
86
+ ### S - Single Responsibility
87
+
88
+ A class/function should have only one reason to change.
89
+
90
+ ```typescript
91
+ // BAD - Multiple responsibilities
92
+ class UserService {
93
+ createUser(data: UserData) { /* ... */ }
94
+ sendWelcomeEmail(user: User) { /* ... */ }
95
+ generatePDF(user: User) { /* ... */ }
96
+ validateCreditCard(card: Card) { /* ... */ }
97
+ }
98
+
99
+ // GOOD - Single responsibility each
100
+ class UserService {
101
+ createUser(data: UserData) { /* ... */ }
102
+ }
103
+
104
+ class EmailService {
105
+ sendWelcomeEmail(user: User) { /* ... */ }
106
+ }
107
+
108
+ class PDFService {
109
+ generateUserReport(user: User) { /* ... */ }
110
+ }
111
+ ```
112
+
113
+ ### O - Open/Closed
114
+
115
+ Open for extension, closed for modification.
116
+
117
+ ```typescript
118
+ // BAD - Must modify to add new types
119
+ function calculateArea(shape: Shape) {
120
+ if (shape.type === 'circle') {
121
+ return Math.PI * shape.radius ** 2;
122
+ } else if (shape.type === 'rectangle') {
123
+ return shape.width * shape.height;
124
+ }
125
+ // Must add new else-if for each shape
126
+ }
127
+
128
+ // GOOD - Extend without modifying
129
+ interface Shape {
130
+ area(): number;
131
+ }
132
+
133
+ class Circle implements Shape {
134
+ constructor(private radius: number) {}
135
+ area() { return Math.PI * this.radius ** 2; }
136
+ }
137
+
138
+ class Rectangle implements Shape {
139
+ constructor(private width: number, private height: number) {}
140
+ area() { return this.width * this.height; }
141
+ }
142
+
143
+ // Add new shapes without changing existing code
144
+ class Triangle implements Shape {
145
+ constructor(private base: number, private height: number) {}
146
+ area() { return 0.5 * this.base * this.height; }
147
+ }
148
+ ```
149
+
150
+ ### L - Liskov Substitution
151
+
152
+ Subtypes must be substitutable for their base types.
153
+
154
+ ```typescript
155
+ // BAD - Violates LSP
156
+ class Bird {
157
+ fly() { /* ... */ }
158
+ }
159
+
160
+ class Penguin extends Bird {
161
+ fly() { throw new Error("Can't fly!"); } // Breaks substitutability
162
+ }
163
+
164
+ // GOOD - Proper hierarchy
165
+ interface Bird {
166
+ move(): void;
167
+ }
168
+
169
+ class FlyingBird implements Bird {
170
+ move() { this.fly(); }
171
+ private fly() { /* ... */ }
172
+ }
173
+
174
+ class Penguin implements Bird {
175
+ move() { this.swim(); }
176
+ private swim() { /* ... */ }
177
+ }
178
+ ```
179
+
180
+ ### I - Interface Segregation
181
+
182
+ Clients shouldn't depend on interfaces they don't use.
183
+
184
+ ```typescript
185
+ // BAD - Fat interface
186
+ interface Worker {
187
+ work(): void;
188
+ eat(): void;
189
+ sleep(): void;
190
+ attendMeeting(): void;
191
+ writeReport(): void;
192
+ }
193
+
194
+ // GOOD - Segregated interfaces
195
+ interface Workable {
196
+ work(): void;
197
+ }
198
+
199
+ interface Meetable {
200
+ attendMeeting(): void;
201
+ }
202
+
203
+ interface Reportable {
204
+ writeReport(): void;
205
+ }
206
+
207
+ class Developer implements Workable, Meetable {
208
+ work() { /* ... */ }
209
+ attendMeeting() { /* ... */ }
210
+ }
211
+
212
+ class Robot implements Workable {
213
+ work() { /* ... */ }
214
+ // Doesn't need eat, sleep, or meetings
215
+ }
216
+ ```
217
+
218
+ ### D - Dependency Inversion
219
+
220
+ Depend on abstractions, not concretions.
221
+
222
+ ```typescript
223
+ // BAD - Depends on concrete implementation
224
+ class OrderService {
225
+ private db = new MySQLDatabase();
226
+ private mailer = new SendGridMailer();
227
+
228
+ createOrder(order: Order) {
229
+ this.db.save(order);
230
+ this.mailer.send(order.userEmail, 'Order confirmed');
231
+ }
232
+ }
233
+
234
+ // GOOD - Depends on abstractions
235
+ class OrderService {
236
+ constructor(
237
+ private repository: OrderRepository,
238
+ private notifier: Notifier,
239
+ ) {}
240
+
241
+ createOrder(order: Order) {
242
+ this.repository.save(order);
243
+ this.notifier.notify(order.userEmail, 'Order confirmed');
244
+ }
245
+ }
246
+
247
+ // Can inject any implementation
248
+ new OrderService(new PostgresOrderRepo(), new EmailNotifier());
249
+ new OrderService(new MongoOrderRepo(), new SMSNotifier());
250
+ ```
251
+
252
+ ## SoC - Separation of Concerns
253
+
254
+ Separate code into distinct sections, each handling a specific concern.
255
+
256
+ ```typescript
257
+ // BAD - Mixed concerns
258
+ async function handleUserRegistration(req: Request, res: Response) {
259
+ // Validation
260
+ if (!req.body.email.includes('@')) {
261
+ return res.status(400).json({ error: 'Invalid email' });
262
+ }
263
+
264
+ // Business logic
265
+ const hashedPassword = await bcrypt.hash(req.body.password, 10);
266
+
267
+ // Data access
268
+ const user = await db.query(
269
+ 'INSERT INTO users (email, password) VALUES ($1, $2)',
270
+ [req.body.email, hashedPassword]
271
+ );
272
+
273
+ // Presentation
274
+ return res.json({ id: user.id, email: user.email });
275
+ }
276
+
277
+ // GOOD - Separated concerns
278
+ // validation.ts
279
+ const userSchema = z.object({
280
+ email: z.string().email(),
281
+ password: z.string().min(8),
282
+ });
283
+
284
+ // user.service.ts
285
+ class UserService {
286
+ async register(data: CreateUserDto): Promise<User> {
287
+ const hashedPassword = await this.hashPassword(data.password);
288
+ return this.userRepository.create({ ...data, password: hashedPassword });
289
+ }
290
+ }
291
+
292
+ // user.controller.ts
293
+ async function register(req: Request, res: Response) {
294
+ const data = userSchema.parse(req.body);
295
+ const user = await userService.register(data);
296
+ return res.json(toUserResponse(user));
297
+ }
298
+ ```
299
+
300
+ ## DRY - Don't Repeat Yourself
301
+
302
+ But don't over-apply it. Duplication is better than the wrong abstraction.
303
+
304
+ ```typescript
305
+ // BAD - Premature DRY (wrong abstraction)
306
+ function processEntity(entity: User | Product | Order, action: string) {
307
+ // 100 lines of if/else handling all cases
308
+ }
309
+
310
+ // GOOD - Some duplication is OK when contexts differ
311
+ function processUser(user: User) { /* user-specific logic */ }
312
+ function processProduct(product: Product) { /* product-specific logic */ }
313
+ function processOrder(order: Order) { /* order-specific logic */ }
314
+
315
+ // GOOD - DRY when truly duplicated
316
+ function formatCurrency(amount: number): string {
317
+ return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount);
318
+ }
319
+ // Use everywhere instead of repeating the formatting logic
320
+ ```
321
+
322
+ ## Summary
323
+
324
+ | Principle | Remember |
325
+ |-----------|----------|
326
+ | YAGNI | Build what you need now, not what you might need |
327
+ | KISS | Simple > Clever. If it's hard to explain, simplify it |
328
+ | SRP | One reason to change per class/function |
329
+ | OCP | Add new code, don't modify existing code |
330
+ | LSP | Subtypes must honor parent contracts |
331
+ | ISP | Small, focused interfaces > large, general ones |
332
+ | DIP | Inject dependencies, don't instantiate them |
333
+ | SoC | Validation, business logic, data access = separate |
334
+ | DRY | Avoid duplication, but not at the cost of clarity |
@@ -0,0 +1,262 @@
1
+ ---
2
+ paths:
3
+ - ".github/workflows/**"
4
+ - ".gitlab-ci.yml"
5
+ - "azure-pipelines.yml"
6
+ - "Jenkinsfile"
7
+ - ".circleci/**"
8
+ ---
9
+
10
+ # CI/CD Best Practices
11
+
12
+ ## Pipeline Principles
13
+
14
+ - **Fast feedback**: Run quick checks first (lint, type-check)
15
+ - **Fail fast**: Stop pipeline on first failure
16
+ - **Parallelization**: Run independent jobs in parallel
17
+ - **Caching**: Cache dependencies between runs
18
+ - **Artifacts**: Pass build outputs between jobs
19
+
20
+ ## GitHub Actions
21
+
22
+ ### Basic Pipeline
23
+
24
+ ```yaml
25
+ # .github/workflows/ci.yml
26
+ name: CI
27
+
28
+ on:
29
+ push:
30
+ branches: [main, develop]
31
+ pull_request:
32
+ branches: [main]
33
+
34
+ concurrency:
35
+ group: ${{ github.workflow }}-${{ github.ref }}
36
+ cancel-in-progress: true
37
+
38
+ jobs:
39
+ lint:
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ - uses: actions/setup-node@v4
44
+ with:
45
+ node-version: '20'
46
+ cache: 'npm'
47
+ - run: npm ci
48
+ - run: npm run lint
49
+
50
+ test:
51
+ runs-on: ubuntu-latest
52
+ needs: lint
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - uses: actions/setup-node@v4
56
+ with:
57
+ node-version: '20'
58
+ cache: 'npm'
59
+ - run: npm ci
60
+ - run: npm test -- --coverage
61
+ - uses: codecov/codecov-action@v3
62
+
63
+ build:
64
+ runs-on: ubuntu-latest
65
+ needs: test
66
+ steps:
67
+ - uses: actions/checkout@v4
68
+ - uses: actions/setup-node@v4
69
+ with:
70
+ node-version: '20'
71
+ cache: 'npm'
72
+ - run: npm ci
73
+ - run: npm run build
74
+ - uses: actions/upload-artifact@v4
75
+ with:
76
+ name: build
77
+ path: dist/
78
+ ```
79
+
80
+ ### Nx Monorepo Pipeline
81
+
82
+ ```yaml
83
+ name: CI (Nx)
84
+
85
+ on:
86
+ push:
87
+ branches: [main]
88
+ pull_request:
89
+
90
+ jobs:
91
+ main:
92
+ runs-on: ubuntu-latest
93
+ steps:
94
+ - uses: actions/checkout@v4
95
+ with:
96
+ fetch-depth: 0
97
+
98
+ - uses: actions/setup-node@v4
99
+ with:
100
+ node-version: '20'
101
+ cache: 'npm'
102
+
103
+ - run: npm ci
104
+
105
+ - uses: nrwl/nx-set-shas@v4
106
+
107
+ # Run affected commands
108
+ - run: npx nx affected -t lint --parallel=3
109
+ - run: npx nx affected -t test --parallel=3 --coverage
110
+ - run: npx nx affected -t build --parallel=3
111
+ ```
112
+
113
+ ### Deploy Pipeline
114
+
115
+ ```yaml
116
+ # .github/workflows/deploy.yml
117
+ name: Deploy
118
+
119
+ on:
120
+ push:
121
+ branches: [main]
122
+
123
+ jobs:
124
+ deploy:
125
+ runs-on: ubuntu-latest
126
+ environment: production
127
+ steps:
128
+ - uses: actions/checkout@v4
129
+
130
+ - name: Build Docker image
131
+ run: |
132
+ docker build -t myapp:${{ github.sha }} .
133
+
134
+ - name: Login to Registry
135
+ uses: docker/login-action@v3
136
+ with:
137
+ registry: ghcr.io
138
+ username: ${{ github.actor }}
139
+ password: ${{ secrets.GITHUB_TOKEN }}
140
+
141
+ - name: Push image
142
+ run: |
143
+ docker tag myapp:${{ github.sha }} ghcr.io/${{ github.repository }}:${{ github.sha }}
144
+ docker tag myapp:${{ github.sha }} ghcr.io/${{ github.repository }}:latest
145
+ docker push ghcr.io/${{ github.repository }} --all-tags
146
+
147
+ - name: Deploy to production
148
+ run: |
149
+ # kubectl, ssh, or cloud CLI deployment
150
+ echo "Deploying ${{ github.sha }}"
151
+ ```
152
+
153
+ ## Branch Protection
154
+
155
+ Configure in GitHub Settings:
156
+
157
+ - Require PR reviews before merging
158
+ - Require status checks (CI must pass)
159
+ - Require branches to be up to date
160
+ - Enforce linear history (squash or rebase)
161
+ - Restrict force pushes
162
+
163
+ ## Secrets Management
164
+
165
+ ```yaml
166
+ # Reference secrets (never hardcode!)
167
+ env:
168
+ DATABASE_URL: ${{ secrets.DATABASE_URL }}
169
+ API_KEY: ${{ secrets.API_KEY }}
170
+
171
+ # Use environments for different configs
172
+ jobs:
173
+ deploy:
174
+ environment: production # Uses production secrets
175
+ ```
176
+
177
+ ## Caching Strategies
178
+
179
+ ```yaml
180
+ # Node.js
181
+ - uses: actions/setup-node@v4
182
+ with:
183
+ cache: 'npm' # Built-in caching
184
+
185
+ # Custom cache
186
+ - uses: actions/cache@v4
187
+ with:
188
+ path: |
189
+ ~/.npm
190
+ node_modules
191
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
192
+ restore-keys: |
193
+ ${{ runner.os }}-node-
194
+
195
+ # Docker layer caching
196
+ - uses: docker/build-push-action@v5
197
+ with:
198
+ cache-from: type=gha
199
+ cache-to: type=gha,mode=max
200
+ ```
201
+
202
+ ## Matrix Builds
203
+
204
+ ```yaml
205
+ jobs:
206
+ test:
207
+ strategy:
208
+ matrix:
209
+ node: [18, 20, 22]
210
+ os: [ubuntu-latest, windows-latest]
211
+ runs-on: ${{ matrix.os }}
212
+ steps:
213
+ - uses: actions/setup-node@v4
214
+ with:
215
+ node-version: ${{ matrix.node }}
216
+ ```
217
+
218
+ ## Release Automation
219
+
220
+ ```yaml
221
+ # .github/workflows/release.yml
222
+ name: Release
223
+
224
+ on:
225
+ push:
226
+ tags:
227
+ - 'v*'
228
+
229
+ jobs:
230
+ release:
231
+ runs-on: ubuntu-latest
232
+ steps:
233
+ - uses: actions/checkout@v4
234
+
235
+ - name: Create Release
236
+ uses: softprops/action-gh-release@v1
237
+ with:
238
+ generate_release_notes: true
239
+ files: |
240
+ dist/*.zip
241
+ ```
242
+
243
+ ## Quality Gates
244
+
245
+ | Check | Tool | Threshold |
246
+ |-------|------|-----------|
247
+ | Lint | ESLint/Ruff | 0 errors |
248
+ | Type check | TypeScript/mypy | 0 errors |
249
+ | Unit tests | Jest/pytest | 100% pass |
250
+ | Coverage | Codecov | ≥80% |
251
+ | Security | Snyk/Dependabot | 0 critical |
252
+ | Build | Framework CLI | Success |
253
+
254
+ ## Anti-patterns
255
+
256
+ - Running all tests on every commit (use affected)
257
+ - Not caching dependencies
258
+ - Hardcoding secrets
259
+ - Not using concurrency limits
260
+ - Deploying without approval gates
261
+ - Missing rollback strategy
262
+ - No artifact retention policy