cc-codeconductor 0.4.3 → 0.5.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 (141) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +2642 -226
  3. package/package.json +1 -1
  4. package/presets/agy/skills/evaluation/SKILL.md +6 -0
  5. package/presets/agy/skills/openspec/SKILL.md +32 -0
  6. package/presets/agy/workflows/cc-openspec.md +62 -0
  7. package/presets/agy/workflows/cc-scorecard.md +17 -0
  8. package/presets/claude/commands/cc/openspec.md +144 -0
  9. package/presets/claude/commands/cc/review.md +13 -2
  10. package/presets/claude/commands/cc/scorecard.md +65 -0
  11. package/presets/claude/skills/evaluation/SKILL.md +42 -0
  12. package/presets/claude/skills/openspec/SKILL.md +54 -0
  13. package/presets/codex/AGENTS.md +57 -0
  14. package/presets/cursor/.cursorignore +15 -0
  15. package/presets/cursor/AGENTS.md +504 -0
  16. package/presets/cursor/agents/architect.md +211 -0
  17. package/presets/cursor/agents/complexity-auditor.md +76 -0
  18. package/presets/cursor/agents/contract-builder.md +75 -0
  19. package/presets/cursor/agents/docs.md +180 -0
  20. package/presets/cursor/agents/goal-planner.md +71 -0
  21. package/presets/cursor/agents/implementer.md +161 -0
  22. package/presets/cursor/agents/orchestrator.md +377 -0
  23. package/presets/cursor/agents/repo-explorer.md +100 -0
  24. package/presets/cursor/agents/reviewer.md +237 -0
  25. package/presets/cursor/agents/security-reviewer.md +113 -0
  26. package/presets/cursor/agents/task-coach.md +145 -0
  27. package/presets/cursor/agents/tester.md +241 -0
  28. package/presets/cursor/commands/cc/api-contract.md +58 -0
  29. package/presets/cursor/commands/cc/db-migration.md +58 -0
  30. package/presets/cursor/commands/cc/feature.md +115 -0
  31. package/presets/cursor/commands/cc/fix.md +121 -0
  32. package/presets/cursor/commands/cc/openspec.md +144 -0
  33. package/presets/cursor/commands/cc/pagespeed.md +103 -0
  34. package/presets/cursor/commands/cc/refactor.md +148 -0
  35. package/presets/cursor/commands/cc/review.md +137 -0
  36. package/presets/cursor/commands/cc/scorecard.md +65 -0
  37. package/presets/cursor/commands/cc/tdd-cycle.md +226 -0
  38. package/presets/cursor/commands/cc/test-plan.md +138 -0
  39. package/presets/cursor/rules/behavioral-discipline.mdc +14 -0
  40. package/presets/cursor/rules/context-budget.mdc +12 -0
  41. package/presets/cursor/rules/orchestration.mdc +12 -0
  42. package/presets/cursor/rules/yagni-stdlib.mdc +11 -0
  43. package/presets/cursor/skills/android/SKILL.md +122 -0
  44. package/presets/cursor/skills/api-versioning/SKILL.md +394 -0
  45. package/presets/cursor/skills/astro/SKILL.md +322 -0
  46. package/presets/cursor/skills/auth-token-inspector/SKILL.md +33 -0
  47. package/presets/cursor/skills/code-review/SKILL.md +208 -0
  48. package/presets/cursor/skills/conductor-setup/SKILL.md +127 -0
  49. package/presets/cursor/skills/django-orm/SKILL.md +463 -0
  50. package/presets/cursor/skills/django-testing/SKILL.md +417 -0
  51. package/presets/cursor/skills/django-uv/SKILL.md +409 -0
  52. package/presets/cursor/skills/drizzle-schema-architect/SKILL.md +54 -0
  53. package/presets/cursor/skills/evaluation/SKILL.md +8 -0
  54. package/presets/cursor/skills/fastapi-pydantic-strict/SKILL.md +46 -0
  55. package/presets/cursor/skills/find-skills/SKILL.md +144 -0
  56. package/presets/cursor/skills/jpa-nplusone-detector/SKILL.md +49 -0
  57. package/presets/cursor/skills/jpa-postgres/SKILL.md +626 -0
  58. package/presets/cursor/skills/laravel-specialist/SKILL.md +267 -0
  59. package/presets/cursor/skills/laravel-specialist/references/eloquent.md +351 -0
  60. package/presets/cursor/skills/laravel-specialist/references/livewire.md +512 -0
  61. package/presets/cursor/skills/laravel-specialist/references/queues.md +423 -0
  62. package/presets/cursor/skills/laravel-specialist/references/routing.md +362 -0
  63. package/presets/cursor/skills/laravel-specialist/references/testing.md +522 -0
  64. package/presets/cursor/skills/livewire-alpine-bridge/SKILL.md +39 -0
  65. package/presets/cursor/skills/multi-agent-orchestration/README.md +144 -0
  66. package/presets/cursor/skills/multi-agent-orchestration/SKILL.md +579 -0
  67. package/presets/cursor/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
  68. package/presets/cursor/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
  69. package/presets/cursor/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
  70. package/presets/cursor/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
  71. package/presets/cursor/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
  72. package/presets/cursor/skills/nextjs-typescript/SKILL.md +394 -0
  73. package/presets/cursor/skills/openspec/SKILL.md +52 -0
  74. package/presets/cursor/skills/pagespeed-insights/SKILL.md +445 -0
  75. package/presets/cursor/skills/pagespeed-insights/reference.md +50 -0
  76. package/presets/cursor/skills/pagespeed-perf/SKILL.md +281 -0
  77. package/presets/cursor/skills/php-pro/SKILL.md +210 -0
  78. package/presets/cursor/skills/php-pro/references/async-patterns.md +412 -0
  79. package/presets/cursor/skills/php-pro/references/laravel-patterns.md +377 -0
  80. package/presets/cursor/skills/php-pro/references/modern-php-features.md +323 -0
  81. package/presets/cursor/skills/php-pro/references/symfony-patterns.md +466 -0
  82. package/presets/cursor/skills/php-pro/references/testing-quality.md +466 -0
  83. package/presets/cursor/skills/python/SKILL.md +613 -0
  84. package/presets/cursor/skills/python-django-stack/SKILL.md +500 -0
  85. package/presets/cursor/skills/python-fastapi-stack/SKILL.md +464 -0
  86. package/presets/cursor/skills/security/SKILL.md +384 -0
  87. package/presets/cursor/skills/seo-analytics-injector/SKILL.md +44 -0
  88. package/presets/cursor/skills/spring-auth-auditor/SKILL.md +33 -0
  89. package/presets/cursor/skills/spring-boot-feature/SKILL.md +566 -0
  90. package/presets/cursor/skills/spring-boot-kotlin/SKILL.md +408 -0
  91. package/presets/cursor/skills/spring-boot-testing-strategy/SKILL.md +479 -0
  92. package/presets/cursor/skills/sqlalchemy/SKILL.md +473 -0
  93. package/presets/cursor/skills/tailwind-responsive-auditor/SKILL.md +32 -0
  94. package/presets/cursor/skills/tdd-mutation-tester/SKILL.md +28 -0
  95. package/presets/cursor/skills/testing-tdd/SKILL.md +592 -0
  96. package/presets/cursor/skills/workflow-orchestration-patterns/SKILL.md +98 -0
  97. package/presets/cursor/skills/workflow-orchestration-patterns/references/details.md +223 -0
  98. package/presets/opencode/agents/architect.md +1 -2
  99. package/presets/opencode/agents/complexity-auditor.md +1 -0
  100. package/presets/opencode/agents/contract-builder.md +93 -0
  101. package/presets/opencode/agents/docs.md +1 -2
  102. package/presets/opencode/agents/goal-planner.md +82 -0
  103. package/presets/opencode/agents/implementer.md +9 -2
  104. package/presets/opencode/agents/orchestrator.md +50 -12
  105. package/presets/opencode/agents/repo-explorer.md +0 -1
  106. package/presets/opencode/agents/reviewer.md +23 -2
  107. package/presets/opencode/agents/security-reviewer.md +129 -0
  108. package/presets/opencode/agents/task-coach.md +1 -2
  109. package/presets/opencode/agents/tester.md +1 -2
  110. package/presets/opencode/commands/cc-openspec.md +61 -0
  111. package/presets/opencode/commands/cc-scorecard.md +16 -0
  112. package/presets/opencode/prompts/v0.5.0/architect.md +222 -0
  113. package/presets/opencode/prompts/v0.5.0/complexity-auditor.md +91 -0
  114. package/presets/opencode/prompts/v0.5.0/contract-builder.md +84 -0
  115. package/presets/opencode/prompts/v0.5.0/docs.md +190 -0
  116. package/presets/opencode/prompts/v0.5.0/goal-planner.md +80 -0
  117. package/presets/opencode/prompts/v0.5.0/implementer.md +171 -0
  118. package/presets/opencode/prompts/v0.5.0/orchestrator.md +388 -0
  119. package/presets/opencode/prompts/v0.5.0/repo-explorer.md +111 -0
  120. package/presets/opencode/prompts/v0.5.0/reviewer.md +248 -0
  121. package/presets/opencode/prompts/v0.5.0/security-reviewer.md +123 -0
  122. package/presets/opencode/prompts/v0.5.0/task-coach.md +156 -0
  123. package/presets/opencode/prompts/v0.5.0/tester.md +252 -0
  124. package/presets/opencode/skills/evaluation/SKILL.md +6 -0
  125. package/presets/opencode/skills/openspec/SKILL.md +50 -0
  126. package/presets/templates/BACKLOG.md +33 -0
  127. package/presets/templates/execution-profile.yml +6 -0
  128. package/presets/templates/model-comparison.md +11 -0
  129. package/presets/templates/regression-checklist.yml +10 -0
  130. package/src/presets/manifests/agy.yml +2 -2
  131. package/src/presets/manifests/claude.yml +2 -2
  132. package/src/presets/manifests/codex.yml +2 -2
  133. package/src/presets/manifests/cursor.yml +19 -3
  134. package/src/presets/manifests/gemini.yml +2 -2
  135. package/src/presets/manifests/opencode.yml +2 -2
  136. package/src/presets/models/agy.yml +21 -0
  137. package/src/presets/models/claude.yml +18 -0
  138. package/src/presets/models/codex.yml +18 -0
  139. package/src/presets/models/cursor.yml +39 -9
  140. package/src/presets/models/gemini.yml +18 -0
  141. package/src/presets/models/opencode.yml +18 -0
@@ -0,0 +1,592 @@
1
+ ---
2
+ id: testing-tdd
3
+ version: 1.0.0
4
+ name: Test-Driven Development
5
+ description: >
6
+ Provides expert knowledge for applying the Red-Green-Refactor cycle, designing tests at the right pyramid layer, and implementing TDD across Spring Boot + Kotlin, Python (pytest), and Next.js / Astro (Vitest + Playwright) stacks.
7
+
8
+ user-invokable: true
9
+ license: MIT
10
+ metadata:
11
+ author: lgzarturo
12
+ category: testing
13
+
14
+ compatibility:
15
+ tools: [claude, codex, gemini, agy, opencode]
16
+ stacks:
17
+ languages: []
18
+ frameworks: []
19
+
20
+ risk:
21
+ level: low
22
+ can_execute_shell: false
23
+ can_modify_files: true
24
+ requires_network: false
25
+
26
+ inputs: []
27
+
28
+ outputs: []
29
+
30
+ quality:
31
+ reviewed_by: codeconductor-core
32
+ version: 0.1.0
33
+ ---
34
+
35
+
36
+
37
+ # Test-Driven Development
38
+
39
+ ## The Red-Green-Refactor Cycle
40
+
41
+ ```text
42
+ ┌─────────────────────────────────────────────┐
43
+ │ │
44
+ │ RED → write a failing test │
45
+ │ ↓ │
46
+ │ GREEN → write the minimum code to pass │
47
+ │ ↓ │
48
+ │ REFACTOR → clean up without breaking │
49
+ │ ↓ │
50
+ │ repeat ───────────────────────────────────┘
51
+ ```
52
+
53
+ **Red**: Write a test that describes one behavior you want. Run it. It must
54
+ fail — if it passes without implementation, the test is not testing anything.
55
+
56
+ **Green**: Write the simplest code that makes the test pass. Do not optimize.
57
+ Do not add features. Just pass the test.
58
+
59
+ **Refactor**: Clean up duplication, naming, and structure. Run the tests after
60
+ every change. If any test breaks, the refactor changed behavior — that is a bug.
61
+
62
+ The cycle is short. Each iteration should take minutes, not hours. If a cycle
63
+ takes longer than 30 minutes, the behavior being tested is too large — split it.
64
+
65
+ ## When to Apply TDD
66
+
67
+ **Apply TDD for:**
68
+
69
+ - New business logic with clear rules (validation, calculations, state machines)
70
+ - Bug fixes — write a regression test that reproduces the bug first
71
+ - Public service layer methods
72
+ - API endpoints with defined acceptance criteria
73
+
74
+ **Do not apply TDD for:**
75
+
76
+ - Exploratory code where the design is not yet known — spike first, then write
77
+ tests for the final design
78
+ - Trivial scaffolding (data class constructors, getters)
79
+ - Database migrations — test the resulting schema state, not the migration steps
80
+ - Third-party SDK wrappers where behavior is owned by the library
81
+
82
+ ## Test Pyramid
83
+
84
+ ```text
85
+ /\
86
+ / \
87
+ / E2E\ 10% — full browser/API flows, happy path + critical errors
88
+ /------\
89
+ / Integ \ 20% — components with real dependencies (DB, HTTP clients)
90
+ /----------\
91
+ / Unit \ 70% — isolated logic, mocked dependencies, sub-millisecond
92
+ /______________\
93
+ ```
94
+
95
+ Unit tests are the TDD workhorse. Write them first. Integration tests verify
96
+ that components connect correctly. E2E tests verify that the system works for
97
+ the user — keep them minimal and focused on the critical paths.
98
+
99
+ ## TDD Rules
100
+
101
+ **One failing test at a time.** Write one test, make it pass, then write the
102
+ next. Do not write multiple failing tests before implementing.
103
+
104
+ **The test must fail for the right reason.** A `NullPointerException` on setup
105
+ is not a meaningful failure — that is a broken test. The failure must be the
106
+ assertion, not an error in the test itself.
107
+
108
+ **Minimum implementation.** In the Green phase, return a hardcoded value if
109
+ that makes the test pass. The next test will force you to generalize.
110
+
111
+ **Refactor only on green.** Never refactor when tests are failing. You lose the
112
+ safety net that tells you whether the refactor changed behavior.
113
+
114
+ **Tests are not optional after the fact.** Writing tests after implementation
115
+ is not TDD. It is documentation. It catches far fewer design problems.
116
+
117
+ ---
118
+
119
+ ## Spring Boot + Kotlin
120
+
121
+ ### Naming Convention
122
+
123
+ ```kotlin
124
+ @Test
125
+ fun `should [expected behavior] when [condition]`()
126
+ ```
127
+
128
+ ```kotlin
129
+ @Test
130
+ fun `should return user when found by id`() { ... }
131
+
132
+ @Test
133
+ fun `should throw NotFoundException when user does not exist`() { ... }
134
+
135
+ @Test
136
+ fun `should not create user when email already exists`() { ... }
137
+ ```
138
+
139
+ ### TDD Cycle — Unit Test Example
140
+
141
+ **Requirement**: `UserService.create()` should reject duplicate emails.
142
+
143
+ **Red** — write the failing test first:
144
+
145
+ ```kotlin
146
+ @ExtendWith(MockKExtension::class)
147
+ class UserServiceTest {
148
+
149
+ @MockK
150
+ private lateinit var userRepository: UserRepository
151
+
152
+ private lateinit var userService: UserService
153
+
154
+ @BeforeEach
155
+ fun setUp() {
156
+ userService = UserService(userRepository)
157
+ }
158
+
159
+ @Test
160
+ fun `should throw ConflictException when email already exists`() {
161
+ // Arrange
162
+ val email = "existing@example.com"
163
+ every { userRepository.existsByEmail(email) } returns true
164
+
165
+ // Act & Assert
166
+ assertThrows<ConflictException> {
167
+ userService.create(email = email, name = "Test")
168
+ }
169
+ verify(exactly = 0) { userRepository.save(any()) }
170
+ }
171
+ }
172
+ ```
173
+
174
+ Run → fails (method does not exist yet).
175
+
176
+ **Green** — minimum implementation:
177
+
178
+ ```kotlin
179
+ class UserService(private val userRepository: UserRepository) {
180
+
181
+ fun create(email: String, name: String): User {
182
+ if (userRepository.existsByEmail(email)) {
183
+ throw ConflictException("Email $email is already registered")
184
+ }
185
+ return userRepository.save(User(email = email, name = name))
186
+ }
187
+ }
188
+ ```
189
+
190
+ Run → passes.
191
+
192
+ **Refactor** — extract the check into a private guard, add KDoc only if the
193
+ domain rule is non-obvious. Run tests → still green.
194
+
195
+ **Next test** — happy path:
196
+
197
+ ```kotlin
198
+ @Test
199
+ fun `should create and return user when email is unique`() {
200
+ val email = "new@example.com"
201
+ val saved = User(id = UUID.randomUUID(), email = email, name = "New User")
202
+
203
+ every { userRepository.existsByEmail(email) } returns false
204
+ every { userRepository.save(any()) } returns saved
205
+
206
+ val result = userService.create(email = email, name = "New User")
207
+
208
+ assertThat(result.email).isEqualTo(email)
209
+ verify(exactly = 1) { userRepository.save(any()) }
210
+ }
211
+ ```
212
+
213
+ ### TDD Cycle — Integration Test Example
214
+
215
+ **Requirement**: `GET /api/users/{id}` returns 404 when the user does not exist.
216
+
217
+ **Red**:
218
+
219
+ ```kotlin
220
+ @SpringBootTest
221
+ @AutoConfigureMockMvc
222
+ class UserControllerTest {
223
+
224
+ @Autowired
225
+ private lateinit var mockMvc: MockMvc
226
+
227
+ @Test
228
+ fun `should return 404 when user does not exist`() {
229
+ mockMvc.perform(get("/api/users/${UUID.randomUUID()}"))
230
+ .andExpect(status().isNotFound)
231
+ .andExpect(jsonPath("$.code").value("NOT_FOUND"))
232
+ }
233
+ }
234
+ ```
235
+
236
+ Run → fails (endpoint may not exist yet, or returns wrong status).
237
+
238
+ **Green** — add/fix the endpoint and error handler. Run → passes.
239
+
240
+ **Refactor** — extract error response builder if duplicated across handlers.
241
+
242
+ ### MockK Quick Reference
243
+
244
+ ```kotlin
245
+ // Stub return value
246
+ every { repo.findById(id) } returns Optional.of(user)
247
+
248
+ // Stub exception
249
+ every { repo.save(any()) } throws DataIntegrityViolationException("duplicate")
250
+
251
+ // Verify call count
252
+ verify(exactly = 1) { repo.save(any()) }
253
+ verify(exactly = 0) { emailService.send(any()) }
254
+
255
+ // Capture argument
256
+ val slot = slot<User>()
257
+ every { repo.save(capture(slot)) } returns savedUser
258
+ assertThat(slot.captured.email).isEqualTo("expected@example.com")
259
+
260
+ // Coroutines
261
+ coEvery { repo.findById(id) } returns user
262
+ coVerify(exactly = 1) { repo.findById(id) }
263
+ ```
264
+
265
+ ---
266
+
267
+ ## Python (pytest)
268
+
269
+ ### Naming Convention
270
+
271
+ ```python
272
+ def test_[behavior]_when_[condition]():
273
+ ```
274
+
275
+ ```python
276
+ def test_returns_user_when_found_by_id(): ...
277
+ def test_raises_not_found_when_user_does_not_exist(): ...
278
+ def test_does_not_create_user_when_email_already_exists(): ...
279
+ ```
280
+
281
+ ### TDD Cycle — Unit Test Example
282
+
283
+ **Requirement**: `UserService.create()` should reject duplicate emails.
284
+
285
+ **Red**:
286
+
287
+ ```python
288
+ # tests/users/test_services.py
289
+ import pytest
290
+ from unittest.mock import MagicMock
291
+ from apps.users.services import UserService
292
+
293
+
294
+ def test_raises_when_email_already_exists():
295
+ repo = MagicMock()
296
+ repo.exists_by_email.return_value = True
297
+ service = UserService(repo)
298
+
299
+ with pytest.raises(ValueError, match="already registered"):
300
+ service.create(email="taken@example.com", name="Test")
301
+
302
+ repo.save.assert_not_called()
303
+ ```
304
+
305
+ Run → fails (`UserService` does not exist).
306
+
307
+ **Green**:
308
+
309
+ ```python
310
+ # apps/users/services.py
311
+ class UserService:
312
+
313
+ def __init__(self, repository):
314
+ self._repo = repository
315
+
316
+ def create(self, *, email: str, name: str):
317
+ if self._repo.exists_by_email(email):
318
+ raise ValueError(f"Email {email!r} is already registered")
319
+ return self._repo.save({"email": email, "name": name})
320
+ ```
321
+
322
+ Run → passes.
323
+
324
+ ### pytest with Django and factory-boy
325
+
326
+ ```python
327
+ # tests/users/factories.py
328
+ import factory
329
+ from factory.django import DjangoModelFactory
330
+ from apps.users.models import User
331
+
332
+
333
+ class UserFactory(DjangoModelFactory):
334
+ class Meta:
335
+ model = User
336
+
337
+ email = factory.Sequence(lambda n: f"user{n}@example.com")
338
+ name = factory.Faker("name")
339
+ is_active = True
340
+ ```
341
+
342
+ ```python
343
+ # conftest.py
344
+ import pytest
345
+ from pytest_factoryboy import register
346
+ from tests.users.factories import UserFactory
347
+
348
+ register(UserFactory)
349
+ ```
350
+
351
+ ```python
352
+ # tests/users/test_services.py
353
+ import pytest
354
+ from apps.users.services import UserService
355
+
356
+
357
+ @pytest.mark.django_db
358
+ def test_create_user_succeeds_with_unique_email():
359
+ service = UserService()
360
+
361
+ user = service.create(email="new@example.com", name="Alice")
362
+
363
+ assert user.pk is not None
364
+ assert user.email == "new@example.com"
365
+
366
+
367
+ @pytest.mark.django_db
368
+ def test_create_user_raises_when_email_taken(user_factory):
369
+ user_factory(email="taken@example.com")
370
+
371
+ with pytest.raises(ValueError, match="already registered"):
372
+ UserService().create(email="taken@example.com", name="Bob")
373
+ ```
374
+
375
+ ### pytest Fixtures
376
+
377
+ ```python
378
+ # conftest.py
379
+ import pytest
380
+
381
+
382
+ @pytest.fixture
383
+ def authenticated_client(client, user_factory):
384
+ user = user_factory()
385
+ client.force_login(user)
386
+ return client, user
387
+
388
+
389
+ # In test
390
+ def test_profile_requires_auth(client):
391
+ response = client.get("/api/profile/")
392
+ assert response.status_code == 401
393
+
394
+
395
+ def test_profile_returns_user_data(authenticated_client):
396
+ client, user = authenticated_client
397
+ response = client.get("/api/profile/")
398
+ assert response.status_code == 200
399
+ assert response.json()["email"] == user.email
400
+ ```
401
+
402
+ ---
403
+
404
+ ## Next.js / Astro (Vitest + RTL + Playwright)
405
+
406
+ ### Naming Convention
407
+
408
+ ```typescript
409
+ it('should [behavior] when [condition]', () => { ... })
410
+ describe('ComponentName', () => {
411
+ describe('when [state]', () => {
412
+ it('should [behavior]', () => { ... })
413
+ })
414
+ })
415
+ ```
416
+
417
+ ### TDD Cycle — Component Test Example (Vitest + RTL)
418
+
419
+ **Requirement**: `<Counter>` increments when the button is clicked.
420
+
421
+ **Red**:
422
+
423
+ ```typescript
424
+ // components/counter.test.tsx
425
+ import { render, screen, fireEvent } from '@testing-library/react';
426
+ import { Counter } from './counter';
427
+
428
+ describe('Counter', () => {
429
+ it('should display initial count of 0', () => {
430
+ render(<Counter />);
431
+ expect(screen.getByText('Count: 0')).toBeInTheDocument();
432
+ });
433
+
434
+ it('should increment count when button is clicked', () => {
435
+ render(<Counter />);
436
+ fireEvent.click(screen.getByRole('button', { name: /increment/i }));
437
+ expect(screen.getByText('Count: 1')).toBeInTheDocument();
438
+ });
439
+ });
440
+ ```
441
+
442
+ Run → fails (component does not exist).
443
+
444
+ **Green**:
445
+
446
+ ```tsx
447
+ // components/counter.tsx
448
+ 'use client';
449
+ import { useState } from 'react';
450
+
451
+ export function Counter() {
452
+ const [count, setCount] = useState(0);
453
+ return (
454
+ <div>
455
+ <p>Count: {count}</p>
456
+ <button onClick={() => setCount(c => c + 1)} aria-label="increment">
457
+ +
458
+ </button>
459
+ </div>
460
+ );
461
+ }
462
+ ```
463
+
464
+ Run → passes.
465
+
466
+ **Refactor** — extract `useCounter` hook if logic grows. Run tests → green.
467
+
468
+ ### Vitest Setup
469
+
470
+ ```typescript
471
+ // vitest.config.ts
472
+ import { defineConfig } from 'vitest/config';
473
+ import react from '@vitejs/plugin-react';
474
+
475
+ export default defineConfig({
476
+ plugins: [react()],
477
+ test: {
478
+ environment: 'jsdom',
479
+ globals: true,
480
+ setupFiles: ['./vitest.setup.ts'],
481
+ },
482
+ });
483
+ ```
484
+
485
+ ```typescript
486
+ // vitest.setup.ts
487
+ import '@testing-library/jest-dom';
488
+ ```
489
+
490
+ ### Server Action Testing
491
+
492
+ Test Server Actions by calling them directly in unit tests — no HTTP overhead.
493
+
494
+ ```typescript
495
+ // app/posts/create/actions.test.ts
496
+ import { createPost } from './actions';
497
+
498
+ vi.mock('@/lib/db', () => ({
499
+ db: {
500
+ post: {
501
+ create: vi.fn(),
502
+ },
503
+ },
504
+ }));
505
+
506
+ describe('createPost', () => {
507
+ it('should return validation error when title is empty', async () => {
508
+ const formData = new FormData();
509
+ formData.set('title', '');
510
+ formData.set('content', 'Some content');
511
+
512
+ const result = await createPost(formData);
513
+
514
+ expect(result?.error?.title).toBeDefined();
515
+ });
516
+ });
517
+ ```
518
+
519
+ ### E2E Testing with Playwright
520
+
521
+ Reserve Playwright for critical user flows only. Do not replicate unit test
522
+ scenarios in E2E.
523
+
524
+ ```typescript
525
+ // e2e/auth.spec.ts
526
+ import { test, expect } from '@playwright/test';
527
+
528
+ test.describe('Authentication', () => {
529
+ test('should redirect to login when accessing protected route unauthenticated', async ({ page }) => {
530
+ await page.goto('/dashboard');
531
+ await expect(page).toHaveURL('/login');
532
+ });
533
+
534
+ test('should show dashboard after successful login', async ({ page }) => {
535
+ await page.goto('/login');
536
+ await page.getByLabel('Email').fill('user@example.com');
537
+ await page.getByLabel('Password').fill('password123');
538
+ await page.getByRole('button', { name: 'Sign in' }).click();
539
+ await expect(page).toHaveURL('/dashboard');
540
+ });
541
+ });
542
+ ```
543
+
544
+ ```typescript
545
+ // playwright.config.ts
546
+ import { defineConfig } from '@playwright/test';
547
+
548
+ export default defineConfig({
549
+ testDir: './e2e',
550
+ use: {
551
+ baseURL: 'http://localhost:3000',
552
+ },
553
+ webServer: {
554
+ command: 'npm run build && npm run start',
555
+ port: 3000,
556
+ reuseExistingServer: !process.env.CI,
557
+ },
558
+ });
559
+ ```
560
+
561
+ ---
562
+
563
+ ## CI Integration
564
+
565
+ Run tests in this order — fail fast on the cheapest failures first:
566
+
567
+ ```text
568
+ 1. Unit tests — sub-second feedback; block all subsequent steps on failure
569
+ 2. Integration tests — real DB, real HTTP; slower but necessary
570
+ 3. E2E tests — slowest; run only on main branch or release branches
571
+ ```
572
+
573
+ ```yaml
574
+ # Example GitHub Actions
575
+ jobs:
576
+ test:
577
+ steps:
578
+ - name: Unit tests
579
+ run: npx vitest run --reporter=verbose
580
+ - name: Integration tests
581
+ run: npx vitest run --project=integration
582
+ - name: E2E tests
583
+ if: github.ref == 'refs/heads/main'
584
+ run: npx playwright test
585
+ ```
586
+
587
+ **Pipeline rules:**
588
+
589
+ - A failing unit test blocks the entire pipeline — do not merge broken tests
590
+ - E2E tests are expensive; run them on CI but not in pre-commit hooks
591
+ - Flaky tests must be fixed or deleted — a test that sometimes passes is worse
592
+ than no test, because it erodes trust in the suite
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: workflow-orchestration-patterns
3
+ description: Design durable workflows with Temporal for distributed systems. Covers workflow vs activity separation, saga patterns, state management, and determinism constraints. Use when building long-running processes, distributed transactions, or microservice orchestration.
4
+ ---
5
+
6
+ # Workflow Orchestration Patterns
7
+
8
+ Master workflow orchestration architecture with Temporal, covering fundamental design decisions, resilience patterns, and best practices for building reliable distributed systems.
9
+
10
+ ## When to Use Workflow Orchestration
11
+
12
+ ### Ideal Use Cases (Source: docs.temporal.io)
13
+
14
+ - **Multi-step processes** spanning machines/services/databases
15
+ - **Distributed transactions** requiring all-or-nothing semantics
16
+ - **Long-running workflows** (hours to years) with automatic state persistence
17
+ - **Failure recovery** that must resume from last successful step
18
+ - **Business processes**: bookings, orders, campaigns, approvals
19
+ - **Entity lifecycle management**: inventory tracking, account management, cart workflows
20
+ - **Infrastructure automation**: CI/CD pipelines, provisioning, deployments
21
+ - **Human-in-the-loop** systems requiring timeouts and escalations
22
+
23
+ ### When NOT to Use
24
+
25
+ - Simple CRUD operations (use direct API calls)
26
+ - Pure data processing pipelines (use Airflow, batch processing)
27
+ - Stateless request/response (use standard APIs)
28
+ - Real-time streaming (use Kafka, event processors)
29
+
30
+ ## Detailed patterns and worked examples
31
+
32
+ Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient.
33
+
34
+ ## Best Practices
35
+
36
+ ### Workflow Design
37
+
38
+ 1. **Keep workflows focused** - Single responsibility per workflow
39
+ 2. **Small workflows** - Use child workflows for scalability
40
+ 3. **Clear boundaries** - Workflow orchestrates, activities execute
41
+ 4. **Test locally** - Use time-skipping test environment
42
+
43
+ ### Activity Design
44
+
45
+ 1. **Idempotent operations** - Safe to retry
46
+ 2. **Short-lived** - Seconds to minutes, not hours
47
+ 3. **Timeout configuration** - Always set timeouts
48
+ 4. **Heartbeat for long tasks** - Report progress
49
+ 5. **Error handling** - Distinguish retryable vs non-retryable
50
+
51
+ ### Common Pitfalls
52
+
53
+ **Workflow Violations**:
54
+
55
+ - Using `datetime.now()` instead of `workflow.now()`
56
+ - Threading or async operations in workflow code
57
+ - Calling external APIs directly from workflow
58
+ - Non-deterministic logic in workflows
59
+
60
+ **Activity Mistakes**:
61
+
62
+ - Non-idempotent operations (can't handle retries)
63
+ - Missing timeouts (activities run forever)
64
+ - No error classification (retry validation errors)
65
+ - Ignoring payload limits (2MB per argument)
66
+
67
+ ### Operational Considerations
68
+
69
+ **Monitoring**:
70
+
71
+ - Workflow execution duration
72
+ - Activity failure rates
73
+ - Retry attempts and backoff
74
+ - Pending workflow counts
75
+
76
+ **Scalability**:
77
+
78
+ - Horizontal scaling with workers
79
+ - Task queue partitioning
80
+ - Child workflow decomposition
81
+ - Activity batching when appropriate
82
+
83
+ ## Additional Resources
84
+
85
+ **Official Documentation**:
86
+
87
+ - Temporal Core Concepts: docs.temporal.io/workflows
88
+ - Workflow Patterns: docs.temporal.io/evaluate/use-cases-design-patterns
89
+ - Best Practices: docs.temporal.io/develop/best-practices
90
+ - Saga Pattern: temporal.io/blog/saga-pattern-made-easy
91
+
92
+ **Key Principles**:
93
+
94
+ 1. Workflows = orchestration, Activities = external calls
95
+ 2. Determinism is non-negotiable for workflows
96
+ 3. Idempotency is critical for activities
97
+ 4. State preservation is automatic
98
+ 5. Design for failure and recovery