Skip to content

Commit 1bc2d5a

Browse files
authored
Merge pull request #265 from nanotaboada/feat/books-to-players-refactor
feat(domain)!: refactor from Books to Players domain model (#248)
2 parents c4d23ff + 40745a2 commit 1bc2d5a

38 files changed

+2647
-1634
lines changed

.coderabbit.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ reviews:
7070
- Separate entities (@Entity) from DTOs
7171
- Verify proper Lombok annotations
7272
- Check JPA annotations for entities (@Table, @Column, @Id, etc.)
73-
- Ensure validation annotations on DTOs (@NotBlank, @ISBN, @URL)
74-
- Validate proper use of LocalDate converter for SQLite
73+
- Ensure validation annotations on DTOs (@NotBlank, @Past, @Positive, @URL)
74+
- Validate proper use of IsoDateConverter for SQLite (ISO-8601 TEXT format)
7575
7676
- path: "src/main/java/**/Application.java"
7777
instructions: |
@@ -84,13 +84,14 @@ reviews:
8484
- Test classes should use JUnit 5 (Jupiter)
8585
- Verify proper Spring test annotations (@WebMvcTest, @DataJpaTest, etc.)
8686
- Check use of @MockitoBean (Spring Boot 4.0 style)
87-
- Ensure test naming follows given_when_then pattern
87+
- Ensure test naming follows method_scenario_outcome pattern (concise)
88+
- Validate BDD semantics in JavaDoc comments (Given/When/Then)
8889
- Validate use of AssertJ for fluent assertions
8990
- Check @DisplayName for readable test descriptions
9091
- Ensure @AutoConfigureCache when testing cached operations
91-
- Verify test data uses fake factories (BookFakes, BookDTOFakes)
92+
- Verify test data uses fake factories (PlayerFakes, PlayerDTOFakes)
9293
93-
- path: "src/test/java/**/BookFakes.java"
94+
- path: "src/test/java/**/PlayerFakes.java"
9495
instructions: |
9596
- Verify test data factory pattern
9697
- Check consistency of test data generation

.github/copilot-instructions.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,34 @@
2424
- Example: `docs: optimize AI agent instructions for token efficiency (#259)`
2525
- Types: `feat`, `fix`, `chore`, `docs`, `test`, `refactor`
2626

27+
## Test Naming Convention
28+
29+
**Pattern**: `method_scenario_outcome`
30+
31+
- **method**: The method being tested (e.g., `post`, `findById`, `create`)
32+
- **scenario**: The context or condition (e.g., `playerExists`, `invalidData`, `noMatches`)
33+
- **outcome**: The expected result (e.g., `returnsPlayer`, `returnsConflict`, `returnsEmpty`)
34+
35+
**Examples**:
36+
```java
37+
// Controller: post_squadNumberExists_returnsConflict()
38+
// Service: create_noConflict_returnsPlayerDTO()
39+
// Repository: findById_playerExists_returnsPlayer()
40+
```
41+
42+
**JavaDoc**: Use proper BDD (Given/When/Then) structure in comments:
43+
```java
44+
/**
45+
* Given a player with squad number 5 already exists in the database
46+
* When POST /players is called with a new player using squad number 5
47+
* Then response status is 409 Conflict
48+
*/
49+
@Test
50+
void post_squadNumberExists_returnsConflict() { ... }
51+
```
52+
53+
**Benefits**: Concise method names for IDE test runners, full BDD context in JavaDoc for code readability.
54+
2755
## Architecture at a Glance
2856

2957
```

.vscode/java-formatter.xml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<profiles version="13">
3+
<profile kind="CodeFormatterProfile" name="Spring Boot 127 Column" version="13">
4+
<!-- Line wrapping -->
5+
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="127" />
6+
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="127" />
7+
8+
<!-- Indentation -->
9+
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space" />
10+
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4" />
11+
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4" />
12+
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations"
13+
value="false" />
14+
15+
<!-- Blank lines -->
16+
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0" />
17+
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1" />
18+
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1" />
19+
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1" />
20+
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1" />
21+
22+
<!-- Braces -->
23+
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration"
24+
value="end_of_line" />
25+
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration"
26+
value="end_of_line" />
27+
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line" />
28+
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration"
29+
value="end_of_line" />
30+
31+
<!-- Comments (preserve formatting) -->
32+
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true" />
33+
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false" />
34+
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false" />
35+
<setting
36+
id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments"
37+
value="true" />
38+
39+
<!-- New lines -->
40+
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter"
41+
value="do not insert" />
42+
<setting
43+
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable"
44+
value="insert" />
45+
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field"
46+
value="insert" />
47+
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method"
48+
value="insert" />
49+
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type"
50+
value="insert" />
51+
52+
<!-- Join wrapped lines -->
53+
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false" />
54+
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false" />
55+
</profile>
56+
</profiles>

.vscode/settings.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
{
2-
"editor.rulers": [80],
2+
"editor.rulers": [
3+
{
4+
"column": 127
5+
}
6+
],
7+
"editor.wordWrap": "off",
8+
"editor.wordWrapColumn": 127,
39
"editor.tabSize": 4,
410
"editor.insertSpaces": true,
511
"editor.detectIndentation": false,
@@ -8,6 +14,7 @@
814
"editor.defaultFormatter": "redhat.java",
915
"editor.inlayHints.enabled": "off"
1016
},
17+
"java.format.settings.url": ".vscode/java-formatter.xml",
1118
"java.configuration.updateBuildConfiguration": "automatic",
1219
"java.compile.nullAnalysis.mode": "automatic",
1320
"sonarlint.connectedMode.project": {

AGENTS.md

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ Maven wrapper (`./mvnw`) is included, so Maven installation is optional.
4545
open target/site/jacoco/index.html
4646

4747
# Run specific test class
48-
./mvnw test -Dtest=BooksControllerTest
48+
./mvnw test -Dtest=PlayersControllerTests
4949

5050
# Run specific test method
51-
./mvnw test -Dtest=BooksControllerTest#testGetAllBooks
51+
./mvnw test -Dtest=PlayersControllerTests#getAll_playersExist_returnsOkWithAllPlayers
5252

5353
# Run tests without rebuilding
5454
./mvnw surefire:test
@@ -99,25 +99,25 @@ java -jar target/java.samples.spring.boot-*.jar
9999

100100
### Database Management
101101

102-
This project uses **H2 in-memory database for tests** and **SQLite for runtime**.
102+
This project uses **SQLite in-memory database for tests** and **SQLite for runtime**.
103103

104104
**Runtime (SQLite)**:
105105

106106
```bash
107107
# Database auto-initializes on first startup
108-
# Pre-seeded database ships in storage/books-sqlite3.db
108+
# Pre-seeded database ships in storage/players-sqlite3.db
109109

110110
# To reset database to seed state
111-
rm storage/books-sqlite3.db
111+
rm storage/players-sqlite3.db
112112
# WARNING: spring.jpa.hibernate.ddl-auto=none disables schema generation
113113
# Deleting the DB will cause startup failure - restore from backup or manually reinitialize
114114

115-
# Database location: storage/books-sqlite3.db
115+
# Database location: storage/players-sqlite3.db
116116
```
117117

118-
**Tests (H2)**:
118+
**Tests (SQLite)**:
119119

120-
- In-memory database per test run
120+
- In-memory database per test run (jdbc:sqlite::memory:)
121121
- Automatically cleared after each test
122122
- Configuration in `src/test/resources/application.properties`
123123

@@ -181,34 +181,37 @@ src/main/java/ar/com/nanotaboada/java/samples/spring/boot/
181181
├── Application.java # @SpringBootApplication entry point
182182
183183
├── controllers/ # REST endpoints
184-
│ └── BooksController.java # @RestController, OpenAPI annotations
184+
│ └── PlayersController.java # @RestController, OpenAPI annotations
185185
186186
├── services/ # Business logic
187-
│ └── BooksService.java # @Service, @Cacheable
187+
│ └── PlayersService.java # @Service, @Cacheable
188188
189189
├── repositories/ # Data access
190-
│ └── BooksRepository.java # @Repository, Spring Data JPA
190+
│ └── PlayersRepository.java # @Repository, Spring Data JPA
191191
192-
└── models/ # Domain models
193-
├── Book.java # @Entity, JPA model
194-
├── BookDTO.java # Data Transfer Object, validation
195-
└── UnixTimestampConverter.java # JPA converter
192+
├── models/ # Domain models
193+
│ ├── Player.java # @Entity, JPA model
194+
│ └── PlayerDTO.java # Data Transfer Object, validation
195+
196+
└── converters/ # Infrastructure converters
197+
└── IsoDateConverter.java # JPA converter for ISO-8601 dates
196198
197199
src/test/java/ # Test classes
198-
├── BooksControllerTest.java
199-
├── BooksServiceTest.java
200-
└── BooksRepositoryTest.java
200+
├── PlayersControllerTests.java
201+
├── PlayersServiceTests.java
202+
└── PlayersRepositoryTests.java
201203
```
202204

203205
**Key patterns**:
204206

205207
- Spring Boot 4 with Spring MVC
206208
- Spring Data JPA for database operations
207-
- Custom validation annotations for ISBN and URL
209+
- Custom validation annotations for PlayerDTO
208210
- OpenAPI 3.0 annotations for Swagger docs
209211
- `@Cacheable` for in-memory caching
210212
- DTOs with Bean Validation (JSR-380)
211213
- Actuator for health monitoring and metrics
214+
- JPA derived queries and custom JPQL examples
212215
- Maven multi-module support ready
213216

214217
## API Endpoints
@@ -217,11 +220,13 @@ src/test/java/ # Test classes
217220

218221
| Method | Path | Description |
219222
|--------|------|-------------|
220-
| `GET` | `/books` | Get all books |
221-
| `GET` | `/books/{id}` | Get book by ID |
222-
| `POST` | `/books` | Create new book |
223-
| `PUT` | `/books/{id}` | Update book |
224-
| `DELETE` | `/books/{id}` | Delete book |
223+
| `GET` | `/players` | Get all players |
224+
| `GET` | `/players/{id}` | Get player by ID |
225+
| `GET` | `/players/search/league/{league}` | Search players by league |
226+
| `GET` | `/players/search/squadnumber/{squadNumber}` | Get player by squad number |
227+
| `POST` | `/players` | Create new player |
228+
| `PUT` | `/players/{id}` | Update player |
229+
| `DELETE` | `/players/{id}` | Delete player |
225230
| `GET` | `/actuator/health` | Health check |
226231
| `GET` | `/swagger-ui.html` | API documentation |
227232

@@ -265,7 +270,7 @@ java --version # Should be 25.x
265270
pkill -f "spring-boot:run"
266271

267272
# Reset database
268-
rm storage/books.db
273+
rm storage/players-sqlite3.db
269274
```
270275

271276
### Test failures
@@ -275,7 +280,7 @@ rm storage/books.db
275280
./mvnw test -X
276281

277282
# Run single test for debugging
278-
./mvnw test -Dtest=BooksControllerTest#testGetAllBooks -X
283+
./mvnw test -Dtest=PlayersControllerTests#getAll_playersExist_returnsOkWithAllPlayers -X
279284
```
280285

281286
### Maven wrapper issues
@@ -309,40 +314,53 @@ Open <http://localhost:8080/swagger-ui.html> - Interactive documentation with "T
309314
# Health check
310315
curl http://localhost:8080/actuator/health
311316

312-
# Get all books
313-
curl http://localhost:8080/books
317+
# Get all players
318+
curl http://localhost:8080/players
319+
320+
# Get player by ID
321+
curl http://localhost:8080/players/1
322+
323+
# Search players by league (Premier League)
324+
curl http://localhost:8080/players/search/league/Premier
314325

315-
# Get book by ID
316-
curl http://localhost:8080/books/1
326+
# Get player by squad number (Messi #10)
327+
curl http://localhost:8080/players/search/squadnumber/10
317328

318-
# Create book
319-
curl -X POST http://localhost:8080/books \
329+
# Create player
330+
curl -X POST http://localhost:8080/players \
320331
-H "Content-Type: application/json" \
321332
-d '{
322-
"isbn": "9780132350884",
323-
"title": "Clean Code",
324-
"author": "Robert C. Martin",
325-
"published": 1217548800,
326-
"pages": 464,
327-
"description": "A Handbook of Agile Software Craftsmanship",
328-
"website": "https://www.pearson.com/en-us/subject-catalog/p/clean-code-a-handbook-of-agile-software-craftsmanship/P200000009044"
333+
"firstName": "Leandro",
334+
"middleName": "Daniel",
335+
"lastName": "Paredes",
336+
"dateOfBirth": "1994-06-29",
337+
"squadNumber": 5,
338+
"position": "Defensive Midfield",
339+
"abbrPosition": "DM",
340+
"team": "AS Roma",
341+
"league": "Serie A",
342+
"starting11": false
329343
}'
330344

331-
# Update book
332-
curl -X PUT http://localhost:8080/books/1 \
345+
# Update player
346+
curl -X PUT http://localhost:8080/players/1 \
333347
-H "Content-Type: application/json" \
334348
-d '{
335-
"isbn": "9780132350884",
336-
"title": "Clean Code - Updated",
337-
"author": "Robert C. Martin",
338-
"published": 1217548800,
339-
"pages": 464,
340-
"description": "Updated description",
341-
"website": "https://www.pearson.com/example"
349+
"id": 1,
350+
"firstName": "Emiliano",
351+
"middleName": null,
352+
"lastName": "Martínez",
353+
"dateOfBirth": "1992-09-02",
354+
"squadNumber": 23,
355+
"position": "Goalkeeper",
356+
"abbrPosition": "GK",
357+
"team": "Aston Villa FC",
358+
"league": "Premier League",
359+
"starting11": true
342360
}'
343361

344-
# Delete book
345-
curl -X DELETE http://localhost:8080/books/1
362+
# Delete player
363+
curl -X DELETE http://localhost:8080/players/21
346364
```
347365

348366
## Important Notes
@@ -353,8 +371,10 @@ curl -X DELETE http://localhost:8080/books/1
353371
- **Java version**: Must use JDK 25 for consistency with CI/CD
354372
- **Maven wrapper**: Always use `./mvnw` instead of `mvn` for consistency
355373
- **Database**: SQLite is for demo/development only - not production-ready
356-
- **H2 for tests**: Tests use in-memory H2, runtime uses SQLite
374+
- **SQLite for tests**: Tests use in-memory SQLite (jdbc:sqlite::memory:), runtime uses file-based SQLite
357375
- **OpenAPI annotations**: Required for all new endpoints (Swagger docs)
358376
- **Caching**: Uses Spring's `@Cacheable` - clears on updates/deletes
359-
- **Validation**: Custom ISBN and URL validators in BookDTO
360-
- **Unix timestamps**: Published dates stored as Unix timestamps (seconds since epoch)
377+
- **Validation**: Bean Validation (JSR-380) annotations in PlayerDTO
378+
- **ISO-8601 dates**: Dates stored as ISO-8601 strings for SQLite compatibility
379+
- **Search methods**: Demonstrates JPA derived queries (findBySquadNumber) and custom JPQL (findByLeagueContainingIgnoreCase)
380+
- **Squad numbers**: Jersey numbers (natural key) separate from database IDs

0 commit comments

Comments
 (0)