AGENTS.md@petclinic-backend · git:20260907.335b9da · 2026-09-07 · sha256 2eb8f0b6a5f695d1
AGENTS.md@petclinic-backend git:20260907.335b9daA
Immutable. This exact content never changes and is served at /api/v1/blob/2eb8f0b6a5f695d1.
### Backend Architecture **Layered Structure:** 1. REST Controllers (`petclinic-backend/src/main/java/.../rest/`) - expose API endpoints 2. Mappers (`mapper/`) - hand-written `@Component` entity↔DTO conversion 3. Repository Layer (`repository/`) - Spring Data JPA interfaces (no service layer!) 4. Domain Model (`domain/`) - JPA entities (Owner, Pet, Vet, Visit, Specialty, PetType, User, Role) Two packages sit outside that stack: - `security/` - Spring Security config, off unless `petclinic.security.enable=true` - `mcp/` - `PetClinicMcp` (`@Tool`s exposed at `/mcp`, consumed by `petclinic-chatbot`) + its Tomcat/security customizers **Data Flow:** Request → REST Controller → Repository / Mapper → JPA Entity Response ← REST Controller ← Mapper (Entity→DTO) ← Repository **Test styles, deliberately contrasted on the same logic:** `create_visit` (the most rule-heavy method here — ownership, past date, past time, abuse cap, persist) is covered twice on purpose. `CreateVisitToolTest` is flat and `@SpringBootTest` (~14s); `CreateVisitShould` is hierarchical (`@Nested` + `@DisplayNameGeneration(PrettyTestNames.class)`, in `tools/`) and a social unit test — real `PetClinicMcp`, only the repositories mocked, no Spring, no DB (~0.3s). The duplication is the lesson: run both and read the two trees side by side. Keep them in sync when the rules change. **Key Patterns:** - DTOs are hand-written in `src/main/java/.../rest/dto/` (not generated) - `openapi.yaml` at project root is generated output (from `OpenApiExtractorTest`), not a source spec - Constructor injection, global exception handling via `@RestControllerAdvice` **A @SpringBootTest as a sequence diagram:** annotate the class `@GenerateSequence` (`src/test/java/.../genseq/`), say its sentences with `Steps.given/when/and/then(String)`, and `./run-tests-with-tracing.sh` draws `<TheTest>.java.genseq.puml` beside the test — the same pipeline that draws the browser suites' diagrams, only Tempo has to be running (`./start-grafana.sh`; the tests boot their own embedded Postgres). The OTel agent is attached only under `-Pgenseq`, so a plain `mvn test` is unaffected and the annotation costs nothing. The tooling and the reasoning live in `petclinic-test/README.md` and `petclinic-test/AGENTS.md`. `Steps.java` sets `genseq.participant=Test` on every span it opens, and the renderer keys the test's lifeline off it. That attribute is the whole contract: one JVM, one `service.name`, so nothing else in the trace tells the test apart from the code it drives — drop it on either side and the picture collapses onto `Backend` with the REST hop gone.