REST API for managing football players built with Java and Spring Boot. Implements CRUD operations with a layered architecture, Spring Data JPA + SQLite, Bean Validation, Spring Cache, and Swagger documentation. Part of a cross-language comparison study (.NET, Go, Python, Rust, TypeScript).
- Language: Java 25 (LTS, required)
- Framework: Spring Boot 4.0.0 (Spring MVC)
- ORM: Spring Data JPA + Hibernate
- Database: SQLite (file-based runtime, in-memory for tests)
- Build: Maven 3 — always use
./mvnwwrapper - Validation: Bean Validation (JSR-380)
- Caching: Spring
@Cacheable(simple in-memory, no expiry) - Mapping: ModelMapper
- Migrations: Flyway (versioned SQL under
db/migration/; disabled in tests — tests use Spring SQL init instead) - Logging: SLF4J
- Testing: JUnit 5 + AssertJ + MockMvc + Mockito
- Coverage: JaCoCo
- API Docs: SpringDoc OpenAPI 3 (Swagger)
- Boilerplate: Lombok
- Containerization: Docker
src/main/java/
├── controllers/ — HTTP handlers; delegate to services, no business logic [HTTP layer]
├── services/ — Business logic + @Cacheable caching [business layer]
├── repositories/ — Spring Data JPA with derived queries [data layer]
├── models/ — Player entity + DTOs
└── converters/ — JPA AttributeConverter for ISO-8601 date handling
src/main/resources/ — application.properties, Logback config
src/main/resources/db/migration/ — Flyway versioned SQL (V1 schema, V2+V3 seed data; add V{N}__ here to change schema)
src/test/java/ — test classes mirroring main structure
src/test/resources/ — test config, schema (ddl.sql), seed data (dml.sql); Flyway disabled in tests
storage/ — SQLite database file (runtime, created and populated by Flyway on first start)
Layer rule: Controller → Service → Repository → JPA. Controllers must not access repositories directly. Business logic must not live in controllers.
- Naming: camelCase (methods/variables), PascalCase (classes), UPPER_SNAKE_CASE (constants)
- Files: class name matches file name
- DI: Constructor injection via Lombok
@RequiredArgsConstructor; never field injection - Annotations:
@RestController,@Service,@Repository,@Entity,@Data/@Builder/@AllArgsConstructor(Lombok) - Transactions:
@Transactional(readOnly = true)on read service methods;@Transactionalon writes - Errors:
@ControllerAdvicefor global exception handling - Logging: SLF4J only; never
System.out.println - DTOs: Never expose entities directly in controllers — always use DTOs
- Tests: BDD Given-When-Then naming (
givenX_whenY_thenZ); AssertJ BDD style (then(result).isNotNull()); in-memory SQLite auto-clears after each test - Avoid: field injection,
newfor Spring beans, missing@Transactional, exposing entities in controllers, hardcoded configuration
./mvnw spring-boot:run # port 9000
./mvnw clean test # run tests
./mvnw clean test jacoco:report # tests + coverage
open target/site/jacoco/index.html # view coverage report
docker compose up
docker compose down -v./mvnw clean install— must succeed- All tests pass
- Check coverage at
target/site/jacoco/index.html - No compilation warnings
- Commit message follows Conventional Commits format (enforced by commitlint)
- If this commit introduces or changes an architectural decision, update
CLAUDE.mdand create or amend the relevant ADR indocs/adr/.
Format: type(scope): description (#issue) — max 80 chars
Types: feat fix chore docs test refactor ci perf
Example: feat(api): add player stats endpoint (#42)
- Route handlers and controller endpoints
- Service layer business logic
- Repository custom queries
- Unit and integration tests
- Exception handling in
@ControllerAdvice - Documentation updates, bug fixes, and refactoring
- Utility classes and helpers
- Database schema (entity fields, relationships)
- Dependencies (
pom.xml) - CI/CD configuration (
.github/workflows/) - Docker setup
- Application properties
- API contracts (breaking DTO changes)
- Caching strategy or TTL values
- Package structure
.java-version(JDK 25 required)- Maven wrapper scripts (
mvnw,mvnw.cmd) - Port configuration (9000/9001)
- Test database configuration (in-memory SQLite)
- Production configurations or deployment secrets
This project uses Spec-Driven Development (SDD): discuss in Plan mode first, create a GitHub Issue as the spec artifact, then implement. Always offer to draft an issue before writing code.
Feature request (enhancement label):
- Problem: the pain point being solved
- Proposed Solution: expected behavior and functionality
- Suggested Approach (optional): implementation plan if known
- Acceptance Criteria: at minimum — behaves as proposed, tests added/updated, no regressions
- References: related issues, docs, or examples
Bug report (bug label):
- Description: clear summary of the bug
- Steps to Reproduce: numbered, minimal steps
- Expected / Actual Behavior: one section each
- Environment: runtime versions + OS
- Additional Context: logs, screenshots, stack traces
- Possible Solution (optional): suggested fix or workaround
Add an endpoint: Define DTO in models/ with Bean Validation → add service method in services/ with @Transactional → create controller endpoint with @Operation annotation → add tests → run ./mvnw clean test jacoco:report.
Modify schema: Create a new Flyway migration src/main/resources/db/migration/V{N}__description.sql (production path) → update @Entity in models/Player.java → update DTOs if API changes → also update src/test/resources/ddl.sql and dml.sql (tests use Spring SQL init, not Flyway) → update service, repository, and tests → run ./mvnw clean test. Do not manually edit the SQLite file in storage/; Flyway owns it.
After completing work: Suggest a branch name (e.g. feat/add-player-stats) and a commit message following Conventional Commits including co-author line:
feat(scope): description (#issue)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Port: 9000
- API contract: endpoints, HTTP status codes, and response shapes are fixed; do not change them without explicit discussion
- Commit format:
type(scope): description (#issue)— max 80 chars - Conventional Commits types:
featfixchoredocstestrefactorciperf CHANGELOG.md[Unreleased]section must be updated before every commit
Architectural decisions are documented in docs/adr/.
When proposing structural changes, check both this file and the relevant ADR.
When a decision changes, update this file and create or amend the relevant ADR.
- Architecture Decision Records:
docs/adr/— 14 ADRs documenting the "why" behind major architectural and technology choices in this project. - New architecturally significant decisions (framework changes, persistence strategy, API contract changes, test strategy shifts) should include a new ADR in
docs/adr/following the template indocs/adr/template.md.
- Run
/pre-committo execute the full pre-commit checklist for this project.