Sample Module — C3/C4 Architecture¶
Auto-generated by c4docgen on 2026-04-27. Do not edit manually — regenerate with
./gradlew generateC4Docs.
Component and code-level architecture for the Sample module. For system-wide context (C1 — System Context, C2 — Container), see docs/c4-architecture.md.
C3 — Component¶
Internal components of the Sample module, following the flat package structure established by the sample module.
C4Component
title Sample Module — Component Diagram
Container_Boundary(sample, "Sample Module") {
Component(controllers, "Controllers", "@RestController", "REST endpoints for Todo")
Component(services, "Services", "@Service", "Business logic, caching, event publishing")
Component(repositories, "Repositories", "JpaRepository", "Data access interfaces")
Component(mappers, "Mappers", "@Component", "Entity ↔ DTO conversion")
Component(producers, "Event Producers", "@Component", "Publishes domain events to Kafka")
Component(listeners, "Event Listeners", "@KafkaListener", "Consumes domain events from Kafka")
Component(entities, "Entities", "@Entity", "JPA entity classes")
ComponentDb(dtos, "DTOs", "Java Records", "Request/response data transfer objects")
Component(constants, "Constants", "static final", "API paths, Kafka topics, cache names")
}
Rel(controllers, services, "Delegates to")
Rel(controllers, mappers, "Converts via")
Rel(services, repositories, "Persists via")
Rel(services, mappers, "Converts via")
Rel(services, producers, "Emits events via")
Rel(listeners, services, "May trigger")
Rel(repositories, entities, "Manages")
Component → Package mapping¶
| Component | Package | Key classes |
|---|---|---|
| Controllers | controllers/ |
TodoController |
| Request DTOs | controllers/dto/request/ |
CreateTodoRequest, UpdateTodoRequest, etc. |
| Response DTOs | controllers/dto/response/ |
TodoResponse, etc. |
| Services | services/ |
TodoService |
| Repositories | repositories/ |
TodoRepository |
| Entities | entities/ |
Todo |
| Mappers | mappers/ |
TodoMapper |
| Event Producers | events/producers/ |
TodoEventProducer |
| Event Listeners | events/listeners/ |
TodoEventListener |
| Constants | constants/ |
Constants, KafkaTopics, CacheNames |
C3.1 — Entity Relationship Model¶
The 1 core entities and their relationships.
erDiagram
Todo {
UUID id PK
String title
String description
TodoStatus status "PENDING, IN_PROGRESS, COMPLETED"
Instant createdAt
Instant updatedAt
}
C3.2 — REST API Structure¶
All endpoints follow the pattern established by the sample module.
| Entity | Base path | Operations |
|---|---|---|
| Todo | /api/sample/todos |
GET (list, paginated), GET /{id}, POST, PUT /{id}, DELETE /{id} |
All list endpoints support page (default: 0) and size (default: 20) query parameters, returning PagedResponse<T> from modules/shared/.
C3.3 — Event Flow¶
Domain events are published to Kafka on key state changes.
flowchart LR
Service -->|publish| Producer
Producer -->|send| Kafka["Kafka Topic<br/>sample.*"]
Kafka -->|consume| Listener
subgraph Topics
T1["sample.todos"]
end
Event payload structure (Java record):
*Event {
type: EventType (CREATED, UPDATED, DELETED)
id: UUID
... entity-specific fields ...
timestamp: Instant
}
C3.4 — Caching Strategy¶
Redis caching at the service layer, following the sample module pattern.
| Cache name | Key | Populated by | Evicted by |
|---|---|---|---|
todoById |
entity UUID | findById, update, create |
delete |
Annotations: @Cacheable (read), @CachePut (write), @CacheEvict (delete).
C4 — Code Patterns¶
Implementation follows the conventions from the sample module.
Request flow¶
HTTP Request
→ Controller (validates, delegates)
→ Mapper.toEntity(request)
→ Service (business logic)
→ Repository.save(entity)
→ Mapper.toEvent(entity, CREATED)
→ EventProducer.publish(event)
→ Redis cache updated
→ Mapper.toResponse(entity)
→ HTTP Response (JSON)
Shared utilities (reuse from modules/shared/)¶
| Class | Usage |
|---|---|
PagedResponse<T> |
Wrap all paginated list responses |
ResourceNotFoundException |
Throw on entity-not-found (auto-mapped to 404 ProblemDetail) |
Conventions¶
- All DTOs are immutable Java records
- Constructor injection only (no
@Autowiredfields) - OpenAPI annotations on all controllers and DTOs (
@Tag,@Operation,@Schema) - Constants for API paths, Kafka topics, and cache names (no magic strings)
- Integration tests with Testcontainers (real Postgres, Kafka, Redis)
Related documents¶
| Document | Path |
|---|---|
| Sample module guide | Sample Guide |
| Root PRD index | docs/PRD.md |
| Backend system README | backend/README.md |