Skip to content

Commit 5314eff

Browse files
nanotaboadaclaude
andcommitted
docs: normalize README structure and add RELEASES.md (#296)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7d39cc2 commit 5314eff

File tree

3 files changed

+143
-240
lines changed

3 files changed

+143
-240
lines changed

.markdownlint.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"MD013": false,
3+
"MD024": {
4+
"siblings_only": true
5+
}
6+
}

README.md

Lines changed: 63 additions & 240 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,12 @@
1313

1414
Proof of Concept for a RESTful Web Service built with **Spring Boot 4** targeting **JDK 25 (LTS)**. This project demonstrates best practices for building a layered, testable, and maintainable API implementing CRUD operations for a Players resource (Argentina 2022 FIFA World Cup squad).
1515

16-
## Table of Contents
17-
18-
- [Features](#features)
19-
- [Tech Stack](#tech-stack)
20-
- [Project Structure](#project-structure)
21-
- [Architecture](#architecture)
22-
- [API Reference](#api-reference)
23-
- [Prerequisites](#prerequisites)
24-
- [Quick Start](#quick-start)
25-
- [Clone](#clone)
26-
- [Build](#build)
27-
- [Run](#run)
28-
- [Access](#access)
29-
- [Testing](#testing)
30-
- [Containers](#containers)
31-
- [Build and Start](#build-and-start)
32-
- [Stop](#stop)
33-
- [Reset Database](#reset-database)
34-
- [Environment Variables](#environment-variables)
35-
- [Command Summary](#command-summary)
36-
- [Releases](#releases)
37-
- [Contributing](#contributing)
38-
- [Legal](#legal)
39-
4016
## Features
4117

42-
- 🔌 **RESTful API** - Full CRUD operations for Players resource
4318
- 📚 **Clean Architecture** - Layered design with clear separation of concerns
19+
- 📝 **Interactive Documentation** - Live API exploration and testing interface
4420
- 🚦 **Input Validation** - Bean Validation (JSR-380) constraints
4521
-**Performance Caching** - Optimized data retrieval with cache annotations
46-
- 🔍 **Advanced Search** - League search with JPQL and squad number lookup with derived queries
47-
- 📝 **Interactive Documentation** - Live API exploration and testing interface
48-
- 🩺 **Health Monitoring** - Application health and metrics endpoints
49-
-**Comprehensive Testing** - High code coverage with automated reporting
5022
- 🐳 **Containerized Deployment** - Multi-stage builds with pre-seeded database
5123
- 🔄 **Automated Pipeline** - Continuous integration with automated testing and builds
5224

@@ -68,31 +40,6 @@ Proof of Concept for a RESTful Web Service built with **Spring Boot 4** targetin
6840

6941
> 💡 **Note:** Maven wrapper (`./mvnw`) is included, so Maven installation is optional.
7042
71-
## Project Structure
72-
73-
```tree
74-
src/main/java/ar/com/nanotaboada/java/samples/spring/boot/
75-
├── Application.java # Main entry point, @SpringBootApplication
76-
├── controllers/ # REST endpoints (@RestController)
77-
│ └── PlayersController.java
78-
├── services/ # Business logic (@Service, caching)
79-
│ └── PlayersService.java
80-
├── repositories/ # Data access (@Repository, Spring Data JPA)
81-
│ └── PlayersRepository.java
82-
├── models/ # Domain entities & DTOs
83-
│ ├── Player.java # JPA entity
84-
│ └── PlayerDTO.java # Data Transfer Object with validation
85-
└── converters/ # Infrastructure converters
86-
└── IsoDateConverter.java # JPA converter for ISO-8601 dates
87-
88-
src/test/java/.../test/
89-
├── controllers/ # Controller tests (@WebMvcTest)
90-
├── services/ # Service layer tests
91-
├── repositories/ # Repository tests (@DataJpaTest)
92-
├── PlayerFakes.java # Test data factory for Player entities
93-
└── PlayerDTOFakes.java # Test data factory for PlayerDTO
94-
```
95-
9643
## Architecture
9744

9845
Layered architecture with dependency injection via Spring Boot's IoC container and constructor injection using Lombok's `@RequiredArgsConstructor`.
@@ -187,42 +134,24 @@ graph RL
187134
class tests test
188135
```
189136

190-
*Simplified, conceptual view — not all components or dependencies are shown.*
191-
192-
### Arrow Semantics
193-
194-
Arrows follow the injection direction: `A --> B` means A is injected into B. Solid arrows (`-->`) represent active Spring dependencies — beans wired by the IoC container and invoked at runtime. Dotted arrows (`-.->`) represent test dependencies — test classes reference the types they exercise but are not injected into them.
195-
196-
### Composition Root Pattern
197-
198-
`Application` is the composition root: `@SpringBootApplication` triggers component scanning that discovers and registers all beans, `@EnableCaching` activates the caching infrastructure, and `@Bean ModelMapper` declares the mapping dependency explicitly. Constructor injection is enforced throughout via Lombok's `@RequiredArgsConstructor` on `final` fields.
199-
200-
### Layered Architecture
201-
202-
Four layers: Initialization (`Application`), HTTP (`controllers`), Business (`services`), and Data (`repositories`).
203-
204-
Spring and third-party packages are placed inside the subgraph of the layer that uses them — co-residency communicates the relationship without extra arrows: `Spring Boot` and `SpringDoc` in Initialization, `Spring Validation` in HTTP, `Spring Cache` and `ModelMapper` in Business, `Spring Data JPA` in Data.
205-
206-
`models` and `converters` are cross-cutting: `models` defines the JPA entity and DTOs shared across all layers; `converters` holds the `AttributeConverter` that handles ISO-8601 date serialization for `models`. `Jakarta Persistence` and `Lombok` are their respective dependencies. `Lombok` is also used in `services` and `controllers` via `@RequiredArgsConstructor` and `@Slf4j`, though those arrows are omitted for clarity.
207-
208-
### Color Coding
209-
210-
Blue = core application packages, yellow = Spring ecosystem, red = third-party libraries, green = tests.
137+
> *Arrows follow the injection direction (A → B means A is injected into B). Solid = runtime dependency, dotted = structural. Blue = core domain, red = third-party, green = tests.*
211138
212139
## API Reference
213140

214141
Interactive API documentation is available via Swagger UI at `http://localhost:9000/swagger/index.html` when the server is running.
215142

216-
**Quick Reference:**
143+
| Method | Endpoint | Description | Status |
144+
| ------ | -------- | ----------- | ------ |
145+
| `GET` | `/players` | List all players | `200 OK` |
146+
| `GET` | `/players/{id}` | Get player by ID | `200 OK` |
147+
| `GET` | `/players/search/league/{league}` | Search players by league | `200 OK` |
148+
| `GET` | `/players/squadnumber/{squadNumber}` | Get player by squad number | `200 OK` |
149+
| `POST` | `/players` | Create new player | `201 Created` |
150+
| `PUT` | `/players/{id}` | Update player by ID | `200 OK` |
151+
| `DELETE` | `/players/{id}` | Remove player by ID | `204 No Content` |
152+
| `GET` | `/actuator/health` | Health check | `200 OK` |
217153

218-
- `GET /players` - List all players
219-
- `GET /players/{id}` - Get player by ID
220-
- `GET /players/search/league/{league}` - Search players by league
221-
- `GET /players/squadnumber/{squadNumber}` - Get player by squad number
222-
- `POST /players` - Create new player
223-
- `PUT /players/{id}` - Update existing player
224-
- `DELETE /players/{id}` - Remove player
225-
- `GET /actuator/health` - Health check
154+
Error codes: `400 Bad Request` (validation failed) · `404 Not Found` (player not found) · `409 Conflict` (duplicate squad number on `POST`)
226155

227156
For complete endpoint documentation with request/response schemas, explore the [interactive Swagger UI](http://localhost:9000/swagger/index.html). You can also access the OpenAPI JSON specification at `http://localhost:9000/v3/api-docs`.
228157

@@ -270,39 +199,6 @@ Once the application is running, you can access:
270199
- **OpenAPI Spec**: `http://localhost:9000/v3/api-docs`
271200
- **Health Check**: `http://localhost:9001/actuator/health`
272201

273-
## Testing
274-
275-
Run the full test suite with coverage:
276-
277-
```bash
278-
./mvnw verify
279-
```
280-
281-
**View Coverage Report:**
282-
283-
```bash
284-
open target/site/jacoco/index.html
285-
```
286-
287-
**Test Structure:**
288-
289-
- **Unit Tests** - `@WebMvcTest`, `@DataJpaTest` for isolated layer testing (with `@AutoConfigureCache` for caching support)
290-
- **Test Database** - SQLite in-memory (jdbc:sqlite::memory:) for fast, isolated test execution
291-
- **Mocking** - Mockito with `@MockitoBean` for dependency mocking
292-
- **Assertions** - AssertJ fluent assertions
293-
- **Naming Convention** - `givenX_whenY_thenZ` BDD pattern:
294-
- `givenPlayersExist_whenGetAll_thenReturnsOkWithAllPlayers()`
295-
- `givenSquadNumberExists_whenPost_thenReturnsConflict()`
296-
- `givenPlayerExists_whenFindById_thenReturnsPlayer()`
297-
298-
**Coverage Targets:**
299-
300-
- Controllers: 100%
301-
- Services: 100%
302-
- Repositories: Custom query methods (interfaces excluded by JaCoCo design)
303-
304-
> 💡 **Note:** Dates are stored as ISO-8601 strings for SQLite compatibility. A JPA `AttributeConverter` handles LocalDate ↔ ISO-8601 string conversion transparently. Tests use SQLite in-memory database (jdbc:sqlite::memory:) - the converter works seamlessly with both file-based and in-memory SQLite.
305-
306202
## Containers
307203

308204
### Build and Start
@@ -335,44 +231,71 @@ docker compose down -v # Remove volumes
335231
docker compose up # Fresh start with seed data
336232
```
337233

234+
### Pull Docker images
235+
236+
Each release publishes multiple tags for flexibility:
237+
238+
```bash
239+
# By semantic version (recommended for production)
240+
docker pull ghcr.io/nanotaboada/java-samples-spring-boot:1.0.0
241+
242+
# By club name (memorable alternative)
243+
docker pull ghcr.io/nanotaboada/java-samples-spring-boot:arsenal
244+
245+
# Latest release
246+
docker pull ghcr.io/nanotaboada/java-samples-spring-boot:latest
247+
```
248+
338249
## Environment Variables
339250

340-
### Development (Local)
251+
### Development
341252

342-
Configuration in `src/main/resources/application.properties`:
253+
Configured in `src/main/resources/application.properties`:
343254

344255
```properties
345-
# Server Configuration
346256
server.port=9000
347257
management.server.port=9001
348-
349-
# Database Configuration (SQLite)
350258
spring.datasource.url=jdbc:sqlite:storage/players-sqlite3.db
351-
spring.datasource.driver-class-name=org.sqlite.JDBC
352-
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
353-
spring.jpa.hibernate.ddl-auto=none
354-
355-
# Caching
356-
spring.cache.type=simple
357-
358-
# OpenAPI Documentation
359-
springdoc.api-docs.path=/v3/api-docs
360259
springdoc.swagger-ui.path=/swagger/index.html
361260
```
362261

363-
### Testing (Local)
262+
### Testing
364263

365-
Configuration in `src/test/resources/application.properties`:
264+
Configured in `src/test/resources/application.properties`:
366265

367266
```properties
368-
# Test Database (SQLite in-memory)
369267
spring.datasource.url=jdbc:sqlite::memory:
370-
spring.datasource.driver-class-name=org.sqlite.JDBC
371-
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
372268
spring.jpa.hibernate.ddl-auto=create-drop
373269
```
374270

375-
> 💡 **Note:** Tests use SQLite in-memory database (jdbc:sqlite::memory:) for fast, isolated execution. The ISO-8601 date converter works identically with both file-based and in-memory SQLite.
271+
## Contributing
272+
273+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on:
274+
275+
- Code of Conduct
276+
- Development workflow and best practices
277+
- Commit message conventions (Conventional Commits)
278+
- Pull request process and requirements
279+
280+
**Key guidelines:**
281+
282+
- Follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages
283+
- Ensure all tests pass (`./mvnw verify`)
284+
- Always use Maven wrapper (`./mvnw`), never system Maven
285+
- Keep changes small and focused
286+
- Review `.github/copilot-instructions.md` for architectural patterns
287+
288+
**Testing:**
289+
290+
Run the test suite with JUnit 5 + JaCoCo:
291+
292+
```bash
293+
# Run tests with coverage report
294+
./mvnw verify
295+
296+
# View coverage report
297+
open target/site/jacoco/index.html
298+
```
376299

377300
## Command Summary
378301

@@ -390,112 +313,12 @@ spring.jpa.hibernate.ddl-auto=create-drop
390313
| `docker compose down` | Stop and remove containers |
391314
| `docker compose down -v` | Stop and remove containers with volumes |
392315
| `docker compose logs -f` | View container logs |
316+
| **AI Commands** | |
317+
| `/pre-commit` | Runs linting, tests, and quality checks before committing |
318+
| `/pre-release` | Runs pre-release validation workflow |
393319

394320
> 💡 **Note:** Always use the Maven wrapper (`./mvnw`) instead of system Maven to ensure consistent builds.
395321
396-
## Releases
397-
398-
This project uses **historic football clubs** as release codenames 🏆 (inspired by Ubuntu, Android, and macOS naming conventions).
399-
400-
### Release Naming Convention
401-
402-
Releases follow the pattern: `v{SEMVER}-{CLUB}` (e.g., `v1.0.0-arsenal`)
403-
404-
- **Semantic Version**: Standard versioning (MAJOR.MINOR.PATCH)
405-
- **Club Name**: Alphabetically ordered codename from the [historic club list](CHANGELOG.md)
406-
407-
### Create a Release
408-
409-
To create a new release, follow this workflow:
410-
411-
#### 1. Create a Release Branch
412-
413-
Branch protection prevents direct pushes to `master`, so all release prep goes through a PR:
414-
415-
```bash
416-
git checkout master && git pull
417-
git checkout -b release/v1.0.0-arsenal
418-
```
419-
420-
#### 2. Update CHANGELOG.md
421-
422-
Move items from `[Unreleased]` to a new release section in [CHANGELOG.md](CHANGELOG.md), then commit and push the branch:
423-
424-
```bash
425-
# Move items from [Unreleased] to new release section
426-
# Example: [1.0.0 - Arsenal] - 2026-XX-XX
427-
git add CHANGELOG.md
428-
git commit -m "docs(changelog): prepare release notes for v1.0.0-arsenal"
429-
git push origin release/v1.0.0-arsenal
430-
```
431-
432-
#### 3. Merge the Release PR
433-
434-
Open a pull request from `release/v1.0.0-arsenal` into `master` and merge it. The tag must be created **after** the merge so it points to the correct commit on `master`.
435-
436-
#### 4. Create and Push Tag
437-
438-
After the PR is merged, pull `master` and create the annotated tag:
439-
440-
```bash
441-
git checkout master && git pull
442-
git tag -a v1.0.0-arsenal -m "Release 1.0.0 - Arsenal"
443-
git push origin v1.0.0-arsenal
444-
```
445-
446-
#### 5. Automated CD Workflow
447-
448-
This triggers the CD workflow which automatically:
449-
450-
1. Validates the club name
451-
2. Builds and tests the project with Maven
452-
3. Publishes Docker images to GitHub Container Registry with three tags
453-
4. Creates a GitHub Release with auto-generated changelog from commits
454-
455-
#### Pre-Release Checklist
456-
457-
- [ ] Release branch created from `master`
458-
- [ ] `CHANGELOG.md` updated with release notes
459-
- [ ] Changes committed and pushed on the release branch
460-
- [ ] Release PR merged into `master`
461-
- [ ] Tag created with correct format: `vX.Y.Z-club`
462-
- [ ] Club name is valid (A-Z from the [historic club list](CHANGELOG.md))
463-
- [ ] Tag pushed to trigger CD workflow
464-
465-
### Pull Docker Images
466-
467-
Each release publishes multiple tags for flexibility:
468-
469-
```bash
470-
# By semantic version (recommended for production)
471-
docker pull ghcr.io/nanotaboada/java-samples-spring-boot:1.0.0
472-
473-
# By club name (memorable alternative)
474-
docker pull ghcr.io/nanotaboada/java-samples-spring-boot:arsenal
475-
476-
# Latest release
477-
docker pull ghcr.io/nanotaboada/java-samples-spring-boot:latest
478-
```
479-
480-
> 💡 See [CHANGELOG.md](CHANGELOG.md) for the complete club list (A-Z) and release history.
481-
482-
## Contributing
483-
484-
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on:
485-
486-
- Code of Conduct
487-
- Development workflow and best practices
488-
- Commit message conventions (Conventional Commits)
489-
- Pull request process and requirements
490-
491-
**Key guidelines:**
492-
493-
- Follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages
494-
- Ensure all tests pass (`./mvnw verify`)
495-
- Always use Maven wrapper (`./mvnw`), never system Maven
496-
- Keep changes small and focused
497-
- Review `.github/copilot-instructions.md` for architectural patterns
498-
499322
## Legal
500323

501324
This project is provided for educational and demonstration purposes and may be used in production at your own discretion. All trademarks, service marks, product names, company names, and logos referenced herein are the property of their respective owners and are used solely for identification or illustrative purposes.

0 commit comments

Comments
 (0)