agentic-team-templates 0.13.2 → 0.15.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 (54) hide show
  1. package/README.md +6 -1
  2. package/package.json +1 -1
  3. package/src/index.js +91 -13
  4. package/src/index.test.js +95 -1
  5. package/templates/cpp-expert/.cursorrules/concurrency.md +211 -0
  6. package/templates/cpp-expert/.cursorrules/error-handling.md +170 -0
  7. package/templates/cpp-expert/.cursorrules/memory-and-ownership.md +220 -0
  8. package/templates/cpp-expert/.cursorrules/modern-cpp.md +211 -0
  9. package/templates/cpp-expert/.cursorrules/overview.md +87 -0
  10. package/templates/cpp-expert/.cursorrules/performance.md +223 -0
  11. package/templates/cpp-expert/.cursorrules/testing.md +230 -0
  12. package/templates/cpp-expert/.cursorrules/tooling.md +312 -0
  13. package/templates/cpp-expert/CLAUDE.md +242 -0
  14. package/templates/csharp-expert/.cursorrules/aspnet-core.md +311 -0
  15. package/templates/csharp-expert/.cursorrules/async-patterns.md +206 -0
  16. package/templates/csharp-expert/.cursorrules/dependency-injection.md +206 -0
  17. package/templates/csharp-expert/.cursorrules/error-handling.md +235 -0
  18. package/templates/csharp-expert/.cursorrules/language-features.md +204 -0
  19. package/templates/csharp-expert/.cursorrules/overview.md +92 -0
  20. package/templates/csharp-expert/.cursorrules/performance.md +251 -0
  21. package/templates/csharp-expert/.cursorrules/testing.md +282 -0
  22. package/templates/csharp-expert/.cursorrules/tooling.md +254 -0
  23. package/templates/csharp-expert/CLAUDE.md +360 -0
  24. package/templates/java-expert/.cursorrules/concurrency.md +209 -0
  25. package/templates/java-expert/.cursorrules/error-handling.md +205 -0
  26. package/templates/java-expert/.cursorrules/modern-java.md +216 -0
  27. package/templates/java-expert/.cursorrules/overview.md +81 -0
  28. package/templates/java-expert/.cursorrules/performance.md +239 -0
  29. package/templates/java-expert/.cursorrules/persistence.md +262 -0
  30. package/templates/java-expert/.cursorrules/spring-boot.md +262 -0
  31. package/templates/java-expert/.cursorrules/testing.md +272 -0
  32. package/templates/java-expert/.cursorrules/tooling.md +301 -0
  33. package/templates/java-expert/CLAUDE.md +325 -0
  34. package/templates/javascript-expert/.cursorrules/overview.md +5 -3
  35. package/templates/javascript-expert/.cursorrules/typescript-deep-dive.md +348 -0
  36. package/templates/javascript-expert/CLAUDE.md +34 -3
  37. package/templates/kotlin-expert/.cursorrules/coroutines.md +237 -0
  38. package/templates/kotlin-expert/.cursorrules/error-handling.md +149 -0
  39. package/templates/kotlin-expert/.cursorrules/frameworks.md +227 -0
  40. package/templates/kotlin-expert/.cursorrules/language-features.md +231 -0
  41. package/templates/kotlin-expert/.cursorrules/overview.md +77 -0
  42. package/templates/kotlin-expert/.cursorrules/performance.md +185 -0
  43. package/templates/kotlin-expert/.cursorrules/testing.md +213 -0
  44. package/templates/kotlin-expert/.cursorrules/tooling.md +258 -0
  45. package/templates/kotlin-expert/CLAUDE.md +276 -0
  46. package/templates/swift-expert/.cursorrules/concurrency.md +230 -0
  47. package/templates/swift-expert/.cursorrules/error-handling.md +213 -0
  48. package/templates/swift-expert/.cursorrules/language-features.md +246 -0
  49. package/templates/swift-expert/.cursorrules/overview.md +88 -0
  50. package/templates/swift-expert/.cursorrules/performance.md +260 -0
  51. package/templates/swift-expert/.cursorrules/swiftui.md +260 -0
  52. package/templates/swift-expert/.cursorrules/testing.md +286 -0
  53. package/templates/swift-expert/.cursorrules/tooling.md +285 -0
  54. package/templates/swift-expert/CLAUDE.md +275 -0
@@ -0,0 +1,262 @@
1
+ # Spring Boot Patterns
2
+
3
+ Production-grade Spring Boot development. Convention over configuration, done right.
4
+
5
+ ## Application Structure
6
+
7
+ ```java
8
+ @SpringBootApplication
9
+ public class Application {
10
+ public static void main(String[] args) {
11
+ SpringApplication.run(Application.class, args);
12
+ }
13
+ }
14
+ // That's it. No XML. No component scanning tricks. Just this.
15
+ ```
16
+
17
+ ## REST Controllers
18
+
19
+ ```java
20
+ @RestController
21
+ @RequestMapping("/api/v1/orders")
22
+ @RequiredArgsConstructor
23
+ public class OrderController {
24
+
25
+ private final OrderService orderService;
26
+
27
+ @GetMapping("/{id}")
28
+ public ResponseEntity<OrderResponse> getById(@PathVariable UUID id) {
29
+ return orderService.findById(id)
30
+ .map(ResponseEntity::ok)
31
+ .orElse(ResponseEntity.notFound().build());
32
+ }
33
+
34
+ @PostMapping
35
+ public ResponseEntity<OrderResponse> create(
36
+ @Valid @RequestBody CreateOrderRequest request) {
37
+ var order = orderService.create(request);
38
+ var location = URI.create("/api/v1/orders/" + order.id());
39
+ return ResponseEntity.created(location).body(order);
40
+ }
41
+
42
+ @GetMapping
43
+ public Page<OrderResponse> list(
44
+ @RequestParam(defaultValue = "0") int page,
45
+ @RequestParam(defaultValue = "20") int size) {
46
+ return orderService.findAll(PageRequest.of(page, size));
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Service Layer
52
+
53
+ ```java
54
+ @Service
55
+ @RequiredArgsConstructor
56
+ @Transactional(readOnly = true)
57
+ public class OrderService {
58
+
59
+ private final OrderRepository orderRepository;
60
+ private final InventoryClient inventoryClient;
61
+ private final ApplicationEventPublisher eventPublisher;
62
+
63
+ public Optional<OrderResponse> findById(UUID id) {
64
+ return orderRepository.findById(id)
65
+ .map(OrderResponse::from);
66
+ }
67
+
68
+ @Transactional
69
+ public OrderResponse create(CreateOrderRequest request) {
70
+ // Validate business rules
71
+ inventoryClient.checkAvailability(request.items())
72
+ .orElseThrow(() -> new InsufficientInventoryException(request.items()));
73
+
74
+ // Create and persist
75
+ var order = Order.create(request);
76
+ orderRepository.save(order);
77
+
78
+ // Publish domain event
79
+ eventPublisher.publishEvent(new OrderCreatedEvent(order.getId()));
80
+
81
+ return OrderResponse.from(order);
82
+ }
83
+ }
84
+ ```
85
+
86
+ ## Configuration
87
+
88
+ ```java
89
+ // Strongly typed configuration with validation
90
+ @Validated
91
+ @ConfigurationProperties(prefix = "app.orders")
92
+ public record OrderProperties(
93
+ @NotNull Duration processingTimeout,
94
+ @Min(1) @Max(1000) int maxItemsPerOrder,
95
+ @NotBlank String notificationEmail
96
+ ) {}
97
+
98
+ // Enable in Application class or config
99
+ @EnableConfigurationProperties(OrderProperties.class)
100
+
101
+ // application.yml
102
+ // app:
103
+ // orders:
104
+ // processing-timeout: 30s
105
+ // max-items-per-order: 50
106
+ // notification-email: orders@example.com
107
+ ```
108
+
109
+ ## Exception Handling
110
+
111
+ ```java
112
+ @RestControllerAdvice
113
+ public class GlobalExceptionHandler {
114
+
115
+ @ExceptionHandler(NotFoundException.class)
116
+ public ProblemDetail handleNotFound(NotFoundException ex) {
117
+ var problem = ProblemDetail.forStatusAndDetail(
118
+ HttpStatus.NOT_FOUND, ex.getMessage());
119
+ problem.setTitle("Resource Not Found");
120
+ return problem;
121
+ }
122
+
123
+ @ExceptionHandler(MethodArgumentNotValidException.class)
124
+ public ProblemDetail handleValidation(MethodArgumentNotValidException ex) {
125
+ var problem = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
126
+ problem.setTitle("Validation Failed");
127
+ var errors = ex.getBindingResult().getFieldErrors().stream()
128
+ .collect(Collectors.toMap(
129
+ FieldError::getField,
130
+ f -> Objects.requireNonNullElse(f.getDefaultMessage(), "Invalid")));
131
+ problem.setProperty("errors", errors);
132
+ return problem;
133
+ }
134
+
135
+ @ExceptionHandler(Exception.class)
136
+ public ProblemDetail handleUnexpected(Exception ex) {
137
+ log.error("Unexpected error", ex);
138
+ return ProblemDetail.forStatusAndDetail(
139
+ HttpStatus.INTERNAL_SERVER_ERROR,
140
+ "An unexpected error occurred");
141
+ // Never expose stack traces or internal details to clients
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## Security
147
+
148
+ ```java
149
+ @Configuration
150
+ @EnableMethodSecurity
151
+ public class SecurityConfig {
152
+
153
+ @Bean
154
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
155
+ return http
156
+ .csrf(csrf -> csrf.csrfTokenRepository(
157
+ CookieCsrfTokenRepository.withHttpOnlyFalse()))
158
+ .authorizeHttpRequests(auth -> auth
159
+ .requestMatchers("/api/public/**").permitAll()
160
+ .requestMatchers("/actuator/health").permitAll()
161
+ .requestMatchers("/api/admin/**").hasRole("ADMIN")
162
+ .anyRequest().authenticated())
163
+ .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
164
+ .sessionManagement(session ->
165
+ session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
166
+ .build();
167
+ }
168
+ }
169
+ ```
170
+
171
+ ## Health Checks
172
+
173
+ ```java
174
+ @Component
175
+ public class ExternalServiceHealthIndicator implements HealthIndicator {
176
+
177
+ private final ExternalServiceClient client;
178
+
179
+ @Override
180
+ public Health health() {
181
+ try {
182
+ client.ping();
183
+ return Health.up()
184
+ .withDetail("service", "external-api")
185
+ .build();
186
+ } catch (Exception ex) {
187
+ return Health.down()
188
+ .withDetail("service", "external-api")
189
+ .withException(ex)
190
+ .build();
191
+ }
192
+ }
193
+ }
194
+
195
+ // application.yml
196
+ // management:
197
+ // endpoints:
198
+ // web:
199
+ // exposure:
200
+ // include: health,info,prometheus
201
+ // endpoint:
202
+ // health:
203
+ // show-details: when-authorized
204
+ ```
205
+
206
+ ## Profiles and Environment
207
+
208
+ ```yaml
209
+ # application.yml — shared defaults
210
+ spring:
211
+ application:
212
+ name: order-service
213
+ jpa:
214
+ open-in-view: false # Always disable — prevents lazy loading bugs
215
+
216
+ ---
217
+ # application-local.yml
218
+ spring:
219
+ config:
220
+ activate:
221
+ on-profile: local
222
+ datasource:
223
+ url: jdbc:postgresql://localhost:5432/orders
224
+
225
+ ---
226
+ # application-prod.yml
227
+ spring:
228
+ config:
229
+ activate:
230
+ on-profile: prod
231
+ datasource:
232
+ url: ${DATABASE_URL} # From environment
233
+ ```
234
+
235
+ ## Anti-Patterns
236
+
237
+ ```java
238
+ // Never: field injection
239
+ @Autowired
240
+ private OrderRepository repository; // Untestable, hides dependencies
241
+ // Use constructor injection (Lombok @RequiredArgsConstructor)
242
+
243
+ // Never: business logic in controllers
244
+ @PostMapping
245
+ public Order create(@RequestBody CreateOrderRequest request) {
246
+ var order = new Order();
247
+ order.setStatus("PENDING");
248
+ order.setItems(request.items()); // Logic belongs in service/domain
249
+ return orderRepository.save(order);
250
+ }
251
+
252
+ // Never: open-in-view (lazy loading in controllers)
253
+ spring.jpa.open-in-view=true // N+1 queries, unclear data access patterns
254
+ // Set to false, use eager fetching or DTOs
255
+
256
+ // Never: catching and ignoring exceptions
257
+ try { externalService.call(); }
258
+ catch (Exception e) { /* ignore */ }
259
+ // Log, wrap, or rethrow — never swallow
260
+
261
+ // Never: @Transactional on private methods (Spring proxy can't intercept them)
262
+ ```
@@ -0,0 +1,272 @@
1
+ # Java Testing
2
+
3
+ Test behavior, not implementation. Every test answers: "what does this code do?"
4
+
5
+ ## Framework Stack
6
+
7
+ | Tool | Purpose |
8
+ |------|---------|
9
+ | JUnit 5 | Test framework |
10
+ | AssertJ | Fluent assertions |
11
+ | Mockito | Mocking (with strict stubs) |
12
+ | Testcontainers | Real databases/services |
13
+ | Spring Boot Test | Integration testing |
14
+ | WireMock | HTTP API mocking |
15
+ | ArchUnit | Architecture tests |
16
+
17
+ ## Unit Test Structure
18
+
19
+ ```java
20
+ class OrderServiceTest {
21
+
22
+ private final OrderRepository repository = mock(OrderRepository.class);
23
+ private final InventoryClient inventory = mock(InventoryClient.class);
24
+ private final OrderService sut = new OrderService(repository, inventory);
25
+
26
+ @Test
27
+ void create_withValidRequest_savesAndReturnsOrder() {
28
+ // Arrange
29
+ var request = new CreateOrderRequest("customer-1", List.of(
30
+ new OrderItemRequest("SKU-001", 2)));
31
+ when(inventory.checkAvailability("SKU-001", 2)).thenReturn(true);
32
+
33
+ // Act
34
+ var result = sut.create(request);
35
+
36
+ // Assert
37
+ assertThat(result.customerId()).isEqualTo("customer-1");
38
+ assertThat(result.status()).isEqualTo(OrderStatus.PENDING);
39
+ verify(repository).save(any(Order.class));
40
+ }
41
+
42
+ @Test
43
+ void create_withInsufficientInventory_throwsException() {
44
+ var request = new CreateOrderRequest("customer-1", List.of(
45
+ new OrderItemRequest("SKU-001", 100)));
46
+ when(inventory.checkAvailability("SKU-001", 100)).thenReturn(false);
47
+
48
+ assertThatThrownBy(() -> sut.create(request))
49
+ .isInstanceOf(InsufficientInventoryException.class)
50
+ .hasMessageContaining("SKU-001");
51
+
52
+ verify(repository, never()).save(any());
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Test Naming
58
+
59
+ ```java
60
+ // Pattern: method_scenario_expectedBehavior
61
+ @Test void findById_whenExists_returnsUser() {}
62
+ @Test void findById_whenNotFound_returnsEmpty() {}
63
+ @Test void create_withDuplicateEmail_throwsConflictException() {}
64
+
65
+ // Or descriptive sentences
66
+ @Test void newly_created_order_has_pending_status() {}
67
+ @Test void expired_orders_are_automatically_cancelled() {}
68
+ ```
69
+
70
+ ## Parameterized Tests
71
+
72
+ ```java
73
+ @ParameterizedTest
74
+ @CsvSource({
75
+ "'', false",
76
+ "ab, false",
77
+ "abc, true",
78
+ "valid123, true"
79
+ })
80
+ void validatePassword_checksMinLength(String input, boolean expected) {
81
+ assertThat(PasswordValidator.isValid(input)).isEqualTo(expected);
82
+ }
83
+
84
+ @ParameterizedTest
85
+ @MethodSource("invalidOrderRequests")
86
+ void create_withInvalidData_throwsValidationException(CreateOrderRequest request) {
87
+ assertThatThrownBy(() -> sut.create(request))
88
+ .isInstanceOf(ValidationException.class);
89
+ }
90
+
91
+ static Stream<Arguments> invalidOrderRequests() {
92
+ return Stream.of(
93
+ Arguments.of(new CreateOrderRequest(null, List.of())),
94
+ Arguments.of(new CreateOrderRequest("", List.of())),
95
+ Arguments.of(new CreateOrderRequest("c1", List.of()))
96
+ );
97
+ }
98
+ ```
99
+
100
+ ## Spring Boot Integration Tests
101
+
102
+ ```java
103
+ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
104
+ @Testcontainers
105
+ class OrderControllerIntegrationTest {
106
+
107
+ @Container
108
+ static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
109
+
110
+ @DynamicPropertySource
111
+ static void configureProperties(DynamicPropertyRegistry registry) {
112
+ registry.add("spring.datasource.url", postgres::getJdbcUrl);
113
+ registry.add("spring.datasource.username", postgres::getUsername);
114
+ registry.add("spring.datasource.password", postgres::getPassword);
115
+ }
116
+
117
+ @Autowired
118
+ private TestRestTemplate restTemplate;
119
+
120
+ @Autowired
121
+ private OrderRepository orderRepository;
122
+
123
+ @BeforeEach
124
+ void setUp() {
125
+ orderRepository.deleteAll();
126
+ }
127
+
128
+ @Test
129
+ void postOrders_withValidRequest_returnsCreated() {
130
+ var request = new CreateOrderRequest("customer-1", List.of(
131
+ new OrderItemRequest("SKU-001", 2)));
132
+
133
+ var response = restTemplate.postForEntity("/api/v1/orders", request, OrderResponse.class);
134
+
135
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
136
+ assertThat(response.getBody()).isNotNull();
137
+ assertThat(response.getBody().customerId()).isEqualTo("customer-1");
138
+ assertThat(response.getHeaders().getLocation()).isNotNull();
139
+ }
140
+
141
+ @Test
142
+ void getOrders_whenNotFound_returns404() {
143
+ var response = restTemplate.getForEntity(
144
+ "/api/v1/orders/" + UUID.randomUUID(), ProblemDetail.class);
145
+
146
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
147
+ }
148
+ }
149
+ ```
150
+
151
+ ## WireMock for External APIs
152
+
153
+ ```java
154
+ @SpringBootTest
155
+ @WireMockTest(httpPort = 8089)
156
+ class PaymentServiceTest {
157
+
158
+ @Autowired
159
+ private PaymentService paymentService;
160
+
161
+ @Test
162
+ void charge_whenPaymentSucceeds_returnsTransactionId() {
163
+ stubFor(post("/payments/charge")
164
+ .willReturn(okJson("""
165
+ {"transactionId": "tx-123", "status": "SUCCESS"}
166
+ """)));
167
+
168
+ var result = paymentService.charge(new ChargeRequest("order-1", BigDecimal.TEN));
169
+
170
+ assertThat(result.transactionId()).isEqualTo("tx-123");
171
+ verify(postRequestedFor(urlEqualTo("/payments/charge"))
172
+ .withRequestBody(matchingJsonPath("$.orderId", equalTo("order-1"))));
173
+ }
174
+
175
+ @Test
176
+ void charge_whenPaymentServiceDown_throwsException() {
177
+ stubFor(post("/payments/charge")
178
+ .willReturn(serverError()));
179
+
180
+ assertThatThrownBy(() -> paymentService.charge(
181
+ new ChargeRequest("order-1", BigDecimal.TEN)))
182
+ .isInstanceOf(PaymentException.class);
183
+ }
184
+ }
185
+ ```
186
+
187
+ ## Architecture Tests (ArchUnit)
188
+
189
+ ```java
190
+ class ArchitectureTest {
191
+
192
+ private final JavaClasses classes = new ClassFileImporter()
193
+ .importPackages("com.example.myapp");
194
+
195
+ @Test
196
+ void domain_should_not_depend_on_infrastructure() {
197
+ noClasses()
198
+ .that().resideInAPackage("..domain..")
199
+ .should().dependOnClassesThat()
200
+ .resideInAnyPackage("..infrastructure..", "..api..")
201
+ .check(classes);
202
+ }
203
+
204
+ @Test
205
+ void controllers_should_not_access_repositories_directly() {
206
+ noClasses()
207
+ .that().resideInAPackage("..api..")
208
+ .should().dependOnClassesThat()
209
+ .resideInAPackage("..persistence..")
210
+ .check(classes);
211
+ }
212
+
213
+ @Test
214
+ void services_should_be_annotated_with_service() {
215
+ classes()
216
+ .that().resideInAPackage("..application..")
217
+ .and().haveSimpleNameEndingWith("Service")
218
+ .should().beAnnotatedWith(Service.class)
219
+ .check(classes);
220
+ }
221
+ }
222
+ ```
223
+
224
+ ## Test Data Builders
225
+
226
+ ```java
227
+ public class TestOrders {
228
+
229
+ public static Order.Builder aValidOrder() {
230
+ return Order.builder()
231
+ .customerId("customer-1")
232
+ .status(OrderStatus.PENDING)
233
+ .items(List.of(anOrderItem().build()));
234
+ }
235
+
236
+ public static OrderItem.Builder anOrderItem() {
237
+ return OrderItem.builder()
238
+ .sku("SKU-" + ThreadLocalRandom.current().nextInt(1000))
239
+ .quantity(1)
240
+ .price(BigDecimal.valueOf(9.99));
241
+ }
242
+ }
243
+
244
+ // Usage in tests
245
+ var order = TestOrders.aValidOrder()
246
+ .status(OrderStatus.SHIPPED)
247
+ .build();
248
+ ```
249
+
250
+ ## Anti-Patterns
251
+
252
+ ```java
253
+ // Never: testing implementation details
254
+ verify(repository, times(1)).save(any()); // How, not what
255
+ // Test the outcome: verify the order exists, has correct status
256
+
257
+ // Never: @SpringBootTest for unit tests (slow startup)
258
+ @SpringBootTest // Loads entire context for testing one service
259
+ class OrderServiceTest {} // Use plain JUnit + Mockito instead
260
+
261
+ // Never: Thread.sleep in tests
262
+ Thread.sleep(5000); // Flaky and slow
263
+ // Use Awaitility: await().atMost(5, SECONDS).until(() -> condition);
264
+
265
+ // Never: shared mutable state between tests
266
+ static List<Order> testOrders = new ArrayList<>(); // Tests pollute each other
267
+ // Use @BeforeEach to reset state
268
+
269
+ // Never: ignoring test failures with @Disabled without a reason
270
+ @Disabled // Why? When will it be fixed?
271
+ @Disabled("Flaky due to #1234 — external API timeout. Fix by 2025-02-01")
272
+ ```