Kotlin Spring Boot Agent Rules
Project Context
You are building Spring Boot 3.x applications in Kotlin. Combine Kotlin idioms (data classes, null safety, coroutines) with Spring's auto-configuration and ecosystem. Use Kotlin-specific Spring extensions and DSLs wherever they reduce boilerplate.
Code Style & Idiomatic Kotlin
- Use data classes for DTOs: `data class CreateOrderRequest(@field:NotBlank val productId: String, @field:Positive val quantity: Int)`.
- Use `val` for all injected dependencies; declare them `private`. Avoid `@Autowired` field injection entirely.
- Use `?.`, `?:`, and `let` for null handling — never `!!` on values that may be null at runtime.
- Use scope functions idiomatically: `also` for side effects (logging, debugging), `apply` for object configuration, `let` for nullable transforms.
- Use string templates (`"Order ${order.id} created"`) over concatenation.
- Prefer expression-body syntax for single-expression service methods and extension functions.
Controllers & REST
- Annotate with `@RestController` and `@RequestMapping("/api/v1/orders")`.
- Use `@Valid` on request body parameters; validate DTO fields with `@field:NotBlank`, `@field:Email`, `@field:Min`.
- Return `ResponseEntity<T>` for explicit status codes; use `ResponseEntity.created(location).body(dto)` for POST endpoints.
- Keep controllers thin: validate input, call one service method, return mapped response.
- Use extension functions for entity-to-DTO mapping: `fun Order.toResponse(): OrderResponse`.
Spring Data JPA with Kotlin
- Define JPA entities as plain classes (not data classes) with `@Entity` — data class `copy()` semantics conflict with JPA proxy patterns.
- Use `@GeneratedValue(strategy = GenerationType.IDENTITY)` for primary keys; prefer `UUID` for public-facing IDs.
- Use `@Transactional(readOnly = true)` on service methods that only read; use `@Transactional` for writes.
- Use `@EntityGraph(attributePaths = ["items"])` on repository queries to eager-load specific associations and prevent N+1 selects.
- Write custom queries with `@Query` using JPQL and named parameters: `@Query("SELECT o FROM Order o WHERE o.status = :status")`.
Coroutines Integration
- Use `suspend` functions in service layers for non-blocking I/O operations; pair with `Dispatchers.IO` for JPA calls.
- Use Spring WebFlux `coRouter` DSL for coroutine-based routing: `coRouter { GET("/orders", handler::list) }`.
- Use `Flow<T>` for streaming responses (Server-Sent Events, large result sets); integrate with `ResponseBodyEmitter` or WebFlux.
- Use `coroutineScope { val a = async { }; val b = async { }; a.await() + b.await() }` for parallel service calls.
- Enable coroutine support in `@EnableAsync` beans by using `CoroutineScope`-backed task executors.
Spring Security with Kotlin DSL
- Configure `SecurityFilterChain` with the Kotlin DSL: `http { authorizeRequests { authorize(anyRequest, authenticated) } }`.
- Use `@PreAuthorize("hasRole('ADMIN')")` on service methods for fine-grained authorization.
- Validate JWT tokens in a `OncePerRequestFilter`; use `UsernamePasswordAuthenticationToken` to populate the `SecurityContext`.
- Never store passwords without hashing — use `BCryptPasswordEncoder` injected as a `@Bean`.
Configuration
- Bind config to `@ConfigurationProperties` data classes: `@ConfigurationProperties("app") data class AppProperties(val featureEnabled: Boolean, val maxRetries: Int)`.
- Validate properties at startup with `@Validated` and Jakarta Validation annotations on the properties class.
- Use `spring.profiles.active` to select environment profiles; override with environment variables in production.
Error Handling
- Create a `@RestControllerAdvice` class with `@ExceptionHandler` methods returning `ProblemDetail`.
- Map `ResourceNotFoundException` to `404`, `ConflictException` to `409`, `ValidationException` to `422`.
- Handle `MethodArgumentNotValidException` to return field-level validation errors with clear messages.
- Log unexpected exceptions at `ERROR` with full stack trace; return generic `500` messages to clients.
Testing
- Use MockK (`mockk<OrderService>()`, `every { }`, `verify { }`) over Mockito for idiomatic Kotlin mocking.
- Use `@WebMvcTest(OrderController::class)` for controller slice tests with `MockMvc`.
- Use `@DataJpaTest` with Testcontainers for repository tests against real PostgreSQL.
- Use `runTest { }` for testing `suspend` functions: `runTest { val result = service.createOrder(request); assertThat(result).isNotNull() }`.
- Use `coEvery { service.createOrder(any()) } returns mockOrder` for mocking suspend functions.