diff --git a/AGENTS.md b/AGENTS.md index ae230b7..4858e75 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ The project is structured into distinct, decoupled framework modules. **Do not v - **`cache`**: Two-level caching engine (`Cache`), L1 LRU memory cache (`L1Cache`), L2 Valkey client (`ValkeyWrapper`), CBOR binary serialization (`BinaryCodec`), bucket versioning, and single-flight loader deduplication (`SingleFlight`). - **`exposed`**: Database connection management (`DatabaseWrapper`), Exposed ORM integration, Liquibase migrations, `@Transactional` annotations & proxying (`TransactionalProxy`), and repository base classes (`AbstractRepository`). - **`validator`**: Reflection-based validation engine (`Validator`), constraints (`@RequireAtLeastOneValid`, `@NotNull`, `@NotBlank`, `@NotEmpty`), and `ObjectNotValidException`. -- **`ktor`**: Ktor web integrations, route annotation binding (`@RestController`, `@GetMapping`, `@PostMapping`, `@PatchMapping`), request parameter resolvers (`@QueryParam`, `@PathParam`, `@RequestBody`), automatic `@Valid` validation integration, `ResponseEntity` wrapper, `MessageDto` error response standardization, and OpenAPI metadata (`@Operation`, `@ApiResponses`, `@ApiResponse`). +- **`ktor`**: Ktor (server and client) integrations, route annotation binding (`@RestController`, `@GetMapping`, `@PostMapping`, `@PatchMapping`), request parameter resolvers (`@QueryParam`, `@PathParam`, `@RequestBody`), automatic `@Valid` validation integration, `ResponseEntity` wrapper, `MessageDto` error response standardization, OpenAPI metadata (`@Operation`, `@ApiResponses`, `@ApiResponse`), and a preconfigured HTTP client (`createHttpClient`). For detailed architectural principles, read the [Architecture Guide](guidelines/ARCHITECTURE.md). diff --git a/guidelines/ARCHITECTURE.md b/guidelines/ARCHITECTURE.md index ae922d0..3e4c46f 100644 --- a/guidelines/ARCHITECTURE.md +++ b/guidelines/ARCHITECTURE.md @@ -16,7 +16,11 @@ core (base logging & core utils) - **`cache`**: Provides a two-level caching facade (`Cache`), combining an in-memory L1 LRU cache (`L1Cache`) with a distributed L2 Valkey/Redis store (`ValkeyWrapper`), CBOR binary encoding (`BinaryCodec`), bucket versioning, and concurrent loader deduplication (`SingleFlight`). - **`exposed`**: Coordinates database connections via `DatabaseWrapper` (HikariCP + Exposed + Liquibase), provides `TransactionalProxy` dynamic proxies for `@Transactional` methods, and supplies `AbstractRepository` with an upsert DSL (`ifExists`, `newIfNotExists`, `applyFlush`). - **`validator`**: Provides a runtime reflection-based validation engine (`Validator`) and validation annotations (`@RequireAtLeastOneValid`, `@NotNull`, `@NotBlank`, `@NotEmpty`). -- **`ktor`**: Bridges Ktor web server with framework annotations. Discovers `@RestController` endpoints, binds routes (`@GetMapping`, `@PostMapping`, `@PatchMapping`), resolves parameter arguments (`@QueryParam`, `@PathParam`, `@RequestBody`), executes automatic validation via `@Valid`, packages responses with `ResponseEntity`, generates OpenAPI metadata (`@Operation`, `@ApiResponses`), and handles error formatting via `MessageDto`. +- **`ktor`**: Bridges Ktor (server **and client**) with framework conventions. Discovers `@RestController` endpoints, binds routes (`@GetMapping`, `@PostMapping`, `@PatchMapping`), resolves parameter arguments (`@QueryParam`, `@PathParam`, `@RequestBody`), executes automatic validation via `@Valid`, packages responses with `ResponseEntity`, generates OpenAPI metadata (`@Operation`, `@ApiResponses`), handles error formatting via `MessageDto`, and exposes a preconfigured HTTP client (`createHttpClient`). + +## Dependency Sharing + +The framework extends itself to consuming services: **module dependencies are exposed with `api(...)`** so that projects building on the framework can use them to their full potential (e.g. `api(libs.bundles.ktorServerEcosystem)`, `api(libs.bundles.ktorClientEcosystem)`). Use `implementation` only for dependencies that are genuinely internal to a module. ## Technical Stack diff --git a/guidelines/CODE_STYLE.md b/guidelines/CODE_STYLE.md index 4093f06..3c9db26 100644 --- a/guidelines/CODE_STYLE.md +++ b/guidelines/CODE_STYLE.md @@ -9,6 +9,20 @@ - **Format code consistently** adhering to Kotlin standard style guidelines. - **Reuse existing project patterns** (e.g. factory patterns, annotations, proxy handlers). +## Imports + +- **Always import symbols directly** (`import kotlinx.serialization.ExperimentalSerializationApi`); never reference a type by its fully-qualified name inline (e.g. `kotlinx.serialization.ExperimentalSerializationApi::class`). This keeps the code short and readable. + +## Expression Bodies + +- For expression-body functions, put the `=` at the end of the signature line and the body expression on the **next line**, indented one level: + +```kotlin +@GetMapping("/ok") +fun ok(): ResponseEntity = + ResponseEntity.ok(Book(1, "Dune")) +``` + ## Comments & Intent When adding internal framework handlers or reflection logic, document the technical rationale: diff --git a/guidelines/TESTING.md b/guidelines/TESTING.md index a2c6506..9b1de71 100644 --- a/guidelines/TESTING.md +++ b/guidelines/TESTING.md @@ -93,3 +93,12 @@ class MyComponentTest { // ... tests } ``` + +## 6. Test Every Public Framework API + +The framework is **consumed by other projects**: every public API it ships (server controllers, the preconfigured `HttpClient`, argument resolvers, response wrappers, etc.) must be covered by tests. This makes dependency upgrades explicit: a **Ktor** (or other framework dependency) bump that changes behavior — or a version that drifts — immediately breaks a framework test, instead of silently shipping a broken version to consuming projects. + +- **Server side**: use Ktor's test host (`io.ktor:ktor-server-test-host`) to start routes/controllers in-process and exercise them without a real network server. +- **Client side**: use `io.ktor:ktor-client-mock` (MockEngine) to test the `HttpClient` deterministically (request building, content negotiation/serialization, timeouts) with no network, asserting on request/response fixtures. +- **A public API change without a corresponding test is an incomplete change.** +- Run the full suite with `./gradlew test` before submitting. diff --git a/ktor/AGENTS.md b/ktor/AGENTS.md index 4812bf6..576a9e8 100644 --- a/ktor/AGENTS.md +++ b/ktor/AGENTS.md @@ -3,7 +3,7 @@ This file contains specific rules for the `ktor` submodule. All agents working within this submodule must strictly adhere to these guidelines in addition to the root [`AGENTS.md`](../AGENTS.md). ## Module Purpose & Scope -The `ktor` module provides web framework integration for Ktor Server. It handles `@RestController` discovery, route mapping (`@GetMapping`, `@PostMapping`, `@PatchMapping`), request argument resolution (`@QueryParam`, `@PathParam`, `@RequestBody`), automatic `@Valid` validation, `ResponseEntity` packaging, `MessageDto` response serialization, and OpenAPI documentation generation. +The `ktor` module provides web framework integration for Ktor (server **and client**). It handles `@RestController` discovery, route mapping (`@GetMapping`, `@PostMapping`, `@PatchMapping`), request argument resolution (`@QueryParam`, `@PathParam`, `@RequestBody`), automatic `@Valid` validation, `ResponseEntity` packaging, `MessageDto` response serialization, and OpenAPI documentation generation, as well as framework-aware HTTP clients (e.g. a preconfigured `HttpClient`). ## Submodule-Specific Rules (Règles du sous-module)