backend-claude-code 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.
Files changed (51) hide show
  1. package/.claude/settings.json +42 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +35 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +33 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +32 -0
  5. package/.mcp.json +19 -0
  6. package/CLAUDE.md +126 -0
  7. package/README.md +142 -0
  8. package/agents/code-reviewer.md +84 -0
  9. package/agents/database-reviewer.md +91 -0
  10. package/agents/java-build-resolver.md +127 -0
  11. package/agents/java-performance-reviewer.md +262 -0
  12. package/agents/planner.md +99 -0
  13. package/agents/security-reviewer.md +119 -0
  14. package/agents/tdd-guide.md +189 -0
  15. package/bin/cli.js +144 -0
  16. package/commands/db-migrate.md +134 -0
  17. package/commands/dev-build.md +72 -0
  18. package/commands/dev-coverage.md +73 -0
  19. package/commands/dev-fix.md +75 -0
  20. package/commands/dev-plan.md +501 -0
  21. package/commands/dev-review.md +144 -0
  22. package/commands/dev-run.md +385 -0
  23. package/commands/dev-test.md +89 -0
  24. package/commands/dev-verify.md +95 -0
  25. package/commands/dev.md +45 -0
  26. package/commands/git-commit.md +112 -0
  27. package/commands/git-issue.md +74 -0
  28. package/commands/git-pr.md +184 -0
  29. package/commands/git-push.md +28 -0
  30. package/package.json +24 -0
  31. package/rules/architecture.md +33 -0
  32. package/rules/coding-style.md +113 -0
  33. package/rules/controller-patterns.md +63 -0
  34. package/rules/dto-patterns.md +76 -0
  35. package/rules/entity-patterns.md +70 -0
  36. package/rules/error-handling.md +56 -0
  37. package/rules/hooks.md +73 -0
  38. package/rules/repository-patterns.md +75 -0
  39. package/rules/security.md +101 -0
  40. package/rules/service-patterns.md +70 -0
  41. package/rules/testing.md +174 -0
  42. package/skills/api-design/SKILL.md +523 -0
  43. package/skills/architecture-decision-records/SKILL.md +179 -0
  44. package/skills/database-migrations/SKILL.md +429 -0
  45. package/skills/hexagonal-architecture/SKILL.md +276 -0
  46. package/skills/java-coding-standards/SKILL.md +236 -0
  47. package/skills/jpa-patterns/SKILL.md +218 -0
  48. package/skills/postgres-patterns/SKILL.md +147 -0
  49. package/skills/springboot-patterns/SKILL.md +255 -0
  50. package/skills/springboot-security/SKILL.md +241 -0
  51. package/skills/springboot-tdd/SKILL.md +236 -0
@@ -0,0 +1,236 @@
1
+ ---
2
+ name: springboot-tdd
3
+ description: Test-driven development for Spring Boot using JUnit 5, Mockito, MockMvc, Testcontainers, and JaCoCo. Use when adding features, fixing bugs, or refactoring.
4
+ origin: ECC
5
+ ---
6
+
7
+ # Spring Boot TDD Workflow
8
+
9
+ JUnit 5, Mockito, MockMvc, Testcontainers를 사용한 Spring Boot TDD — 80%+ 커버리지.
10
+
11
+ ## When to Use
12
+
13
+ - 새 기능 또는 엔드포인트
14
+ - 버그 수정 또는 리팩토링
15
+ - 데이터 접근 로직 또는 보안 규칙 추가
16
+
17
+ ## Workflow
18
+
19
+ 1) 먼저 테스트 작성 (실패해야 함)
20
+ 2) 통과하는 최소 코드 구현
21
+ 3) 테스트 통과 상태에서 리팩토링
22
+ 4) JaCoCo로 커버리지 강제 적용
23
+
24
+ ## Unit Tests (JUnit 5 + Mockito)
25
+
26
+ ```java
27
+ @ExtendWith(MockitoExtension.class)
28
+ class OrderServiceTest {
29
+ @Mock OrderRepository repo;
30
+ @InjectMocks OrderService service;
31
+
32
+ @Test
33
+ @DisplayName("create — 유효한 요청으로 주문 생성")
34
+ void create_validRequest_createsOrder() {
35
+ var req = new CreateOrderRequest("Alice", BigDecimal.TEN);
36
+ when(repo.save(any())).thenAnswer(inv -> {
37
+ OrderEntity e = inv.getArgument(0);
38
+ return new OrderEntity(1L, e.getCustomerName(), e.getAmount());
39
+ });
40
+
41
+ var result = service.create(req);
42
+
43
+ assertThat(result.customerName()).isEqualTo("Alice");
44
+ assertThat(result.id()).isEqualTo(1L);
45
+ verify(repo).save(any());
46
+ }
47
+
48
+ @Test
49
+ @DisplayName("findById — 존재하지 않는 ID로 예외 발생")
50
+ void findById_notFound_throwsException() {
51
+ when(repo.findById(99L)).thenReturn(Optional.empty());
52
+
53
+ assertThatThrownBy(() -> service.findById(99L))
54
+ .isInstanceOf(OrderNotFoundException.class)
55
+ .hasMessageContaining("99");
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## Web Layer Tests (MockMvc)
61
+
62
+ ```java
63
+ @WebMvcTest(OrderController.class)
64
+ class OrderControllerTest {
65
+ @Autowired MockMvc mockMvc;
66
+ @MockBean OrderService orderService;
67
+
68
+ @Test
69
+ @DisplayName("GET /orders/{id} — 주문 반환")
70
+ void getOrder_returns200() throws Exception {
71
+ when(orderService.findById(1L)).thenReturn(sampleResponse());
72
+
73
+ mockMvc.perform(get("/api/orders/1"))
74
+ .andExpect(status().isOk())
75
+ .andExpect(jsonPath("$.data.customerName").value("Alice"));
76
+ }
77
+
78
+ @Test
79
+ @DisplayName("POST /orders — 유효하지 않은 입력 시 400 반환")
80
+ void createOrder_invalidInput_returns400() throws Exception {
81
+ mockMvc.perform(post("/api/orders")
82
+ .contentType(MediaType.APPLICATION_JSON)
83
+ .content("""{"customerName":"","amount":-1}"""))
84
+ .andExpect(status().isBadRequest());
85
+ }
86
+
87
+ @Test
88
+ @DisplayName("GET /orders/{id} — 존재하지 않는 ID 시 404 반환")
89
+ void getOrder_notFound_returns404() throws Exception {
90
+ when(orderService.findById(99L))
91
+ .thenThrow(new OrderNotFoundException(99L));
92
+
93
+ mockMvc.perform(get("/api/orders/99"))
94
+ .andExpect(status().isNotFound());
95
+ }
96
+ }
97
+ ```
98
+
99
+ ## Integration Tests (SpringBootTest)
100
+
101
+ ```java
102
+ @SpringBootTest
103
+ @AutoConfigureMockMvc
104
+ @ActiveProfiles("test")
105
+ class OrderIntegrationTest {
106
+ @Autowired MockMvc mockMvc;
107
+
108
+ @Test
109
+ @DisplayName("주문 생성 → 조회 통합 테스트")
110
+ void createAndRetrieveOrder() throws Exception {
111
+ // 생성
112
+ var result = mockMvc.perform(post("/api/orders")
113
+ .contentType(MediaType.APPLICATION_JSON)
114
+ .content("""{"customerName":"Bob","amount":50}"""))
115
+ .andExpect(status().isCreated())
116
+ .andReturn();
117
+
118
+ // ID 추출 후 조회
119
+ var id = JsonPath.read(result.getResponse().getContentAsString(), "$.data.id");
120
+ mockMvc.perform(get("/api/orders/" + id))
121
+ .andExpect(status().isOk())
122
+ .andExpect(jsonPath("$.data.customerName").value("Bob"));
123
+ }
124
+ }
125
+ ```
126
+
127
+ ## Persistence Tests (DataJpaTest)
128
+
129
+ ```java
130
+ @DataJpaTest
131
+ @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
132
+ @Import(TestContainersConfig.class)
133
+ class OrderRepositoryTest {
134
+ @Autowired OrderRepository repo;
135
+
136
+ @Test
137
+ @DisplayName("저장 및 조회")
138
+ void saveAndFind() {
139
+ var entity = new OrderEntity(null, "Alice", BigDecimal.TEN);
140
+ var saved = repo.save(entity);
141
+
142
+ var found = repo.findById(saved.getId());
143
+ assertThat(found).isPresent();
144
+ assertThat(found.get().getCustomerName()).isEqualTo("Alice");
145
+ }
146
+ }
147
+ ```
148
+
149
+ ## Testcontainers Config
150
+
151
+ ```java
152
+ // src/test/java/com/example/config/TestContainersConfig.java
153
+ @Configuration
154
+ public class TestContainersConfig {
155
+
156
+ @Container
157
+ static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16")
158
+ .withReuse(true);
159
+
160
+ static {
161
+ postgres.start();
162
+ }
163
+
164
+ @DynamicPropertySource
165
+ static void registerProperties(DynamicPropertyRegistry registry) {
166
+ registry.add("spring.datasource.url", postgres::getJdbcUrl);
167
+ registry.add("spring.datasource.username", postgres::getUsername);
168
+ registry.add("spring.datasource.password", postgres::getPassword);
169
+ }
170
+ }
171
+ ```
172
+
173
+ ## Coverage (JaCoCo)
174
+
175
+ Maven:
176
+ ```xml
177
+ <plugin>
178
+ <groupId>org.jacoco</groupId>
179
+ <artifactId>jacoco-maven-plugin</artifactId>
180
+ <version>0.8.14</version>
181
+ <executions>
182
+ <execution><goals><goal>prepare-agent</goal></goals></execution>
183
+ <execution>
184
+ <id>report</id>
185
+ <phase>verify</phase>
186
+ <goals><goal>report</goal></goals>
187
+ </execution>
188
+ <execution>
189
+ <id>check</id>
190
+ <goals><goal>check</goal></goals>
191
+ <configuration>
192
+ <rules>
193
+ <rule>
194
+ <limits>
195
+ <limit>
196
+ <counter>LINE</counter>
197
+ <value>COVEREDRATIO</value>
198
+ <minimum>0.80</minimum>
199
+ </limit>
200
+ </limits>
201
+ </rule>
202
+ </rules>
203
+ </configuration>
204
+ </execution>
205
+ </executions>
206
+ </plugin>
207
+ ```
208
+
209
+ ## Assertions Cheatsheet
210
+
211
+ ```java
212
+ // 기본
213
+ assertThat(result).isEqualTo(expected);
214
+ assertThat(list).hasSize(3).containsExactly(a, b, c);
215
+ assertThat(optional).isPresent().hasValue(expected);
216
+
217
+ // 예외
218
+ assertThatThrownBy(() -> service.method())
219
+ .isInstanceOf(MyException.class)
220
+ .hasMessageContaining("expected text");
221
+
222
+ // BigDecimal (정밀도 무관)
223
+ assertThat(price).isEqualByComparingTo(new BigDecimal("10.00"));
224
+
225
+ // JSON path
226
+ mockMvc.perform(get("/api/orders/1"))
227
+ .andExpect(jsonPath("$.data.id").value(1))
228
+ .andExpect(jsonPath("$.data.customerName").value("Alice"));
229
+ ```
230
+
231
+ ## CI Commands
232
+
233
+ - Maven: `./mvnw -T 4 test` 또는 `./mvnw verify`
234
+ - Gradle: `./gradlew test jacocoTestReport`
235
+
236
+ **Remember**: 테스트를 빠르게, 격리되게, 결정적으로 유지. 구현 세부사항이 아닌 동작을 테스트.