AGENTS.md@petclinic-backend · diff
git:20260907.335b9da to git:20260928.01b4538
5 added, 25 removed. Audit A to A.
### 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
+ 5. Notification (`notification/`) - `NotificationServiceClient`, called after a visit is booked:
+ an HTTP POST to notification-service, best effort (a failure is logged, the booking stands).
+ Takes plain values, never an entity, and reaches no repository
**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
+ - `openapi.yaml` at project root is generated output (from `OpenApiExtractorTest`), not a source spec;
+ editing it by hand is denied in `.claude/settings.json` — regenerate it instead
- 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.