|
1 | | -# Copilot Instructions for java.samples.spring.boot |
| 1 | +# GitHub Copilot Instructions |
2 | 2 |
|
3 | | -## Project Overview |
| 3 | +> **⚡ Token Efficiency Note**: This is a minimal pointer file (~500 tokens, auto-loaded by Copilot). |
| 4 | +> For complete operational details, reference: `#file:AGENTS.md` (~2,500 tokens, loaded on-demand) |
| 5 | +> For specialized knowledge, use: `#file:SKILLS/<skill-name>/SKILL.md` (loaded on-demand when needed) |
4 | 6 |
|
5 | | -This is a RESTful Web Service proof-of-concept built with **Spring Boot 4** targeting **JDK 25 (LTS)**. The application demonstrates a clean, layered architecture implementing a CRUD API for managing books. It uses a **SQLite database** for runtime persistence (with a pre-seeded database in Docker) and **H2 in-memory** for fast test execution. |
| 7 | +## 🎯 Quick Context |
6 | 8 |
|
7 | | -**Key URLs:** |
| 9 | +**Project**: Spring Boot REST API demonstrating modern Java patterns |
| 10 | +**Stack**: Java 25 (LTS) • Spring Boot 4 • JPA/Hibernate • SQLite • Maven • Docker |
| 11 | +**Pattern**: Controller → Service → Repository → JPA (layered architecture) |
| 12 | +**Philosophy**: Learning-focused PoC emphasizing Spring Boot best practices |
8 | 13 |
|
9 | | -- API Server: `http://localhost:9000` |
10 | | -- Swagger/OpenAPI Docs: `http://localhost:9000/swagger/index.html` |
11 | | -- Actuator Health: `http://localhost:9001/actuator/health` |
| 14 | +## 📐 Core Conventions |
12 | 15 |
|
13 | | -## Tech Stack |
| 16 | +- **Naming**: camelCase (methods/variables), PascalCase (classes) |
| 17 | +- **Annotations**: Use Spring stereotypes (@RestController, @Service, @Repository) |
| 18 | +- **Lombok**: Reduce boilerplate (@Data, @Builder, @AllArgsConstructor) |
| 19 | +- **Dependency Injection**: Constructor injection (Lombok @RequiredArgsConstructor) |
| 20 | +- **Testing**: JUnit 5 + AssertJ for fluent assertions |
| 21 | +- **Build**: Use `./mvnw` wrapper, NOT system Maven |
14 | 22 |
|
15 | | -### Core Framework & Runtime |
16 | | - |
17 | | -- **Java**: JDK 25 (LTS) - use modern Java features where appropriate |
18 | | -- **Spring Boot**: 4.0.0 with modular starter dependencies (WebMVC, Data JPA, Validation, Cache, Actuator) |
19 | | -- **Build Tool**: Maven 3.9+ (use `./mvnw` wrapper, NOT system Maven) |
20 | | -- **Database**: SQLite (runtime) with Xerial JDBC driver; H2 in-memory (test scope only) |
21 | | - |
22 | | -### Key Dependencies |
23 | | - |
24 | | -- **Lombok** 1.18.42: Auto-generate boilerplate code (getters, setters, constructors) |
25 | | -- **ModelMapper** 3.2.6: Entity-to-DTO mapping |
26 | | -- **SpringDoc OpenAPI** 2.8.14: API documentation (Swagger UI) |
27 | | -- **JaCoCo** 0.8.14: Code coverage reporting |
28 | | -- **AssertJ** 3.27.6: Fluent test assertions |
29 | | -- **SQLite JDBC** 3.47.1.0: SQLite database driver (Xerial) |
30 | | -- **Hibernate Community Dialects**: Provides `SQLiteDialect` for JPA/Hibernate |
31 | | - |
32 | | -### Testing |
33 | | - |
34 | | -- **JUnit 5** (Jupiter): Test framework |
35 | | -- **Mockito**: Mocking framework |
36 | | -- **Spring Boot Test**: `@WebMvcTest`, `@DataJpaTest`, `@AutoConfigureCache`, etc. |
37 | | -- **AssertJ**: Preferred assertion library (use over standard JUnit assertions) |
38 | | - |
39 | | -### DevOps & CI/CD |
40 | | - |
41 | | -- **Docker**: Multi-stage build with Eclipse Temurin Alpine images and pre-seeded SQLite database |
42 | | -- **Docker Compose**: Local containerized deployment with persistent storage volume |
43 | | -- **GitHub Actions**: CI pipeline with coverage reporting (Codecov, Codacy) |
44 | | - |
45 | | -## Project Structure |
| 23 | +## 🏗️ Architecture at a Glance |
46 | 24 |
|
47 | 25 | ``` |
48 | | -src/main/java/ar/com/nanotaboada/java/samples/spring/boot/ |
49 | | -├── Application.java # Main entry point, @SpringBootApplication |
50 | | -├── controllers/ # REST endpoints (@RestController) |
51 | | -│ └── BooksController.java |
52 | | -├── services/ # Business logic (@Service, caching) |
53 | | -│ └── BooksService.java |
54 | | -├── repositories/ # Data access (@Repository, Spring Data JPA) |
55 | | -│ └── BooksRepository.java |
56 | | -└── models/ # Domain entities & DTOs |
57 | | - ├── Book.java # JPA entity |
58 | | - ├── BookDTO.java # Data Transfer Object with validation |
59 | | - └── UnixTimestampConverter.java # JPA converter for LocalDate ↔ Unix timestamp |
60 | | -
|
61 | | -src/test/java/.../test/ |
62 | | -├── controllers/ # Controller tests (@WebMvcTest) |
63 | | -├── services/ # Service layer tests |
64 | | -├── repositories/ # Repository tests (@DataJpaTest) |
65 | | -├── BookFakes.java # Test data factory for Book entities |
66 | | -└── BookDTOFakes.java # Test data factory for BookDTO |
67 | | -
|
68 | | -src/main/resources/ |
69 | | -├── application.properties # Application configuration (SQLite) |
70 | | -└── logback-spring.xml # Logging configuration |
71 | | -
|
72 | | -src/test/resources/ |
73 | | -└── application.properties # Test configuration (H2 in-memory) |
74 | | -
|
75 | | -scripts/ |
76 | | -├── entrypoint.sh # Docker entrypoint (copies seed DB on first run) |
77 | | -└── healthcheck.sh # Docker health check using Actuator |
78 | | -
|
79 | | -storage/ |
80 | | -└── books-sqlite3.db # Pre-seeded SQLite database with sample books |
| 26 | +Controller → Service → Repository → JPA → Database |
| 27 | + ↓ ↓ ↓ |
| 28 | +Validation Cache Query Methods |
81 | 29 | ``` |
82 | 30 |
|
83 | | -**Package Naming Convention**: `ar.com.nanotaboada.java.samples.spring.boot.<layer>` |
84 | | -**Test Package Convention**: Add `.test` before layer name (e.g., `...samples.spring.boot.test.controllers`) |
85 | | - |
86 | | -## Coding Guidelines |
87 | | - |
88 | | -### Architecture & Design Patterns |
89 | | - |
90 | | -- **Layered Architecture**: Controller → Service → Repository → Entity |
91 | | -- **DTOs**: Use `BookDTO` for API requests/responses; `Book` entity is internal |
92 | | -- **Dependency Injection**: Use constructor injection (Lombok `@RequiredArgsConstructor` or explicit constructors) |
93 | | -- **Caching**: Service layer uses Spring Cache annotations (`@Cacheable`, `@CachePut`, `@CacheEvict`) |
94 | | -- **Validation**: Use Jakarta Bean Validation annotations on DTOs (`@NotBlank`, `@ISBN`, `@URL`, etc.) |
95 | | - |
96 | | -### Java Style |
| 31 | +- **Controllers**: REST endpoints with @RestController |
| 32 | +- **Services**: Business logic with @Service + caching |
| 33 | +- **Repositories**: JpaRepository with derived queries |
| 34 | +- **DTOs**: ModelMapper for entity ↔ DTO transformations |
| 35 | +- **Cache**: Spring Cache abstraction (1-hour TTL) |
97 | 36 |
|
98 | | -- **Lombok**: Prefer `@Data`, `@RequiredArgsConstructor`, `@NoArgsConstructor`, `@AllArgsConstructor` over manual code |
99 | | -- **Streams**: Use Java Streams API for collection processing (see `BooksService.retrieveAll()`) |
100 | | -- **Modern Java**: Leverage JDK 25 features (records, pattern matching, sealed classes, etc.) where beneficial |
101 | | -- **Comments**: Section dividers used in controllers/services (e.g., `/* HTTP POST */`) |
| 37 | +## ✅ Copilot Should |
102 | 38 |
|
103 | | -### Testing Conventions |
| 39 | +- Generate idiomatic Spring Boot code with proper annotations |
| 40 | +- Use JPA repository patterns (derived queries, @Query) |
| 41 | +- Follow REST conventions with ResponseEntity<T> |
| 42 | +- Write tests with @SpringBootTest and MockMvc |
| 43 | +- Apply Lombok annotations to reduce boilerplate |
| 44 | +- Use ModelMapper for DTO transformations |
| 45 | +- Implement proper exception handling with @ControllerAdvice |
104 | 46 |
|
105 | | -- **Test Class Naming**: `<ClassName>Tests` (plural, e.g., `BooksControllerTests`) |
106 | | -- **Test Method Naming**: `given<Condition>_when<Action>_then<Expected>` (BDD style) |
107 | | -- **Assertions**: Use AssertJ fluent assertions (`assertThat(...).isEqualTo(...)`) |
108 | | -- **Mocking**: Use `@MockitoBean` for Spring beans (new in Spring Boot 4.0), verify interactions with `verify()` |
109 | | -- **Test Data**: Use fake data factories (`BookFakes`, `BookDTOFakes`) for consistent test data |
110 | | -- **Display Names**: Use `@DisplayName` for readable test descriptions |
111 | | -- **Caching in Tests**: Add `@AutoConfigureCache` to slice tests (`@WebMvcTest`, `@DataJpaTest`) when caching is needed |
| 47 | +## 🚫 Copilot Should Avoid |
112 | 48 |
|
113 | | -### Coverage Exclusions |
| 49 | +- Field injection (use constructor injection) |
| 50 | +- Using `new` for services (breaks DI) |
| 51 | +- Missing @Transactional on service methods |
| 52 | +- Exposing entities directly in controllers (use DTOs) |
| 53 | +- System.out.println (use SLF4J logging) |
| 54 | +- Hardcoded configuration (use @Value or application.yml) |
114 | 55 |
|
115 | | -JaCoCo excludes from coverage (see `pom.xml` and `codecov.yml`): |
116 | | - |
117 | | -- `Application.java` (main class) |
118 | | -- `models/**` package (POJOs with Lombok) |
119 | | -- Test files and resources |
120 | | - |
121 | | -## Build & Run Commands |
122 | | - |
123 | | -### Maven Commands (ALWAYS use wrapper) |
| 56 | +## ⚡ Quick Commands |
124 | 57 |
|
125 | 58 | ```bash |
126 | | -# Clean and compile |
127 | | -./mvnw clean compile |
128 | | - |
129 | | -# Run tests |
130 | | -./mvnw test |
131 | | - |
132 | | -# Run tests with coverage |
133 | | -./mvnw verify |
134 | | - |
135 | | -# Package application |
136 | | -./mvnw package |
137 | | - |
138 | | -# Run application locally |
| 59 | +# Run with hot reload |
139 | 60 | ./mvnw spring-boot:run |
140 | 61 |
|
141 | | -# Skip tests during build (use sparingly) |
142 | | -./mvnw package -DskipTests |
143 | | -``` |
144 | | - |
145 | | -**Critical Requirements**: |
146 | | - |
147 | | -- **ALWAYS use `./mvnw` wrapper** (Unix/macOS) or `mvnw.cmd` (Windows), NOT `mvn` |
148 | | -- **JDK 25 is REQUIRED**: The project targets JDK 25 (LTS) |
149 | | -- **JAVA_HOME must be set**: Maven wrapper requires JAVA_HOME pointing to JDK 25 installation |
150 | | - |
151 | | -### Docker Commands |
152 | | - |
153 | | -```bash |
154 | | -# Build image |
155 | | -docker compose build |
| 62 | +# Test with coverage |
| 63 | +./mvnw clean test jacoco:report |
156 | 64 |
|
157 | | -# Start application container |
| 65 | +# Docker |
158 | 66 | docker compose up |
159 | 67 |
|
160 | | -# Start in detached mode |
161 | | -docker compose up -d |
162 | | - |
163 | | -# Stop and remove containers |
164 | | -docker compose down |
165 | | - |
166 | | -# View logs |
167 | | -docker compose logs -f |
168 | | -``` |
169 | | - |
170 | | -**Exposed Ports**: |
171 | | - |
172 | | -- `9000`: Main API server |
173 | | -- `9001`: Actuator management endpoints |
174 | | - |
175 | | -**Persistent Storage**: |
176 | | - |
177 | | -The Docker container uses a "hold" pattern for the pre-seeded SQLite database: |
178 | | - |
179 | | -1. Build stage copies `storage/books-sqlite3.db` to `/app/hold/` in the image |
180 | | -2. On first container run, `entrypoint.sh` copies the database to `/storage/` volume |
181 | | -3. Subsequent runs use the existing database from the volume |
182 | | -4. To reset: `docker compose down -v` removes volumes, next `up` restores seed data |
183 | | - |
184 | | -## Common Tasks & Patterns |
185 | | - |
186 | | -### Adding a New REST Endpoint |
187 | | - |
188 | | -1. Add method to `BooksController` with appropriate HTTP mapping (`@GetMapping`, `@PostMapping`, etc.) |
189 | | -2. Annotate with `@Operation` and `@ApiResponses` for OpenAPI documentation |
190 | | -3. Implement business logic in `BooksService` |
191 | | -4. Add/update repository method if needed |
192 | | -5. Write controller tests using `@WebMvcTest` and `MockMvc` |
193 | | -6. Write service tests with mocked repository |
194 | | - |
195 | | -### Adding a New Entity/Resource |
196 | | - |
197 | | -1. Create JPA entity in `models/` with `@Entity`, `@Table`, Lombok annotations |
198 | | -2. Create corresponding DTO with validation annotations |
199 | | -3. Create repository interface extending `CrudRepository<Entity, ID>` |
200 | | -4. Create service class with `@Service` and caching annotations |
201 | | -5. Create controller with `@RestController` and OpenAPI annotations |
202 | | -6. Create test data factories (e.g., `EntityFakes.java`) |
203 | | -7. Write comprehensive tests for all layers |
204 | | - |
205 | | -### Updating Dependencies |
206 | | - |
207 | | -- Dependencies are managed by Dependabot (daily checks) |
208 | | -- Spring Boot dependencies are grouped and ignored for individual updates |
209 | | -- Manually update versions in `pom.xml` `<properties>` section if needed |
210 | | - |
211 | | -### Running Coverage Reports |
212 | | - |
213 | | -```bash |
214 | | -./mvnw clean verify |
215 | | -# Report available at: target/site/jacoco/index.html |
| 68 | +# Swagger: http://localhost:9000/swagger-ui/index.html |
| 69 | +# Actuator: http://localhost:9001/actuator/health |
216 | 70 | ``` |
217 | 71 |
|
218 | | -## Troubleshooting |
219 | | - |
220 | | -### Build Failures |
221 | | - |
222 | | -- **Lombok not working**: Ensure annotation processor is enabled in IDE and `maven-compiler-plugin` includes Lombok path |
223 | | -- **Tests failing**: Tests use H2 in-memory database via `src/test/resources/application.properties` |
224 | | -- **Port already in use**: Change `server.port` in `application.properties` or kill process using ports 9000/9001 |
225 | | -- **JAVA_HOME not set**: Run `export JAVA_HOME=$(/usr/libexec/java_home -v 25)` on macOS or set to JDK 25 path on other systems |
226 | | -- **CacheManager errors in tests**: Add `@AutoConfigureCache` annotation to slice tests (`@WebMvcTest`, `@DataJpaTest`) |
227 | | -- **SQLite file not found**: Ensure `storage/books-sqlite3.db` exists for local development |
228 | | - |
229 | | -### Docker Issues |
230 | | - |
231 | | -- **Container health check failing**: Verify Actuator is accessible at `http://localhost:9001/actuator/health` |
232 | | -- **Build context too large**: Ensure `.dockerignore` excludes `target/` and `.git/` |
233 | | -- **Database not persisting**: Check that `java-samples-spring-boot_storage` volume exists (`docker volume ls`) |
234 | | -- **Stale seed data**: Run `docker compose down -v` to remove volumes and restore fresh seed data on next `up` |
235 | | - |
236 | | -### Common Pitfalls |
237 | | - |
238 | | -- **Don't use system Maven**: Always use `./mvnw` wrapper |
239 | | -- **Don't modify `Application.java` coverage**: It's excluded by design |
240 | | -- **Don't test Lombok-generated code**: Focus on business logic |
241 | | -- **Repository interfaces**: Custom query methods may not show in coverage (JaCoCo limitation) |
242 | | -- **Spring Boot 4.0 modular packages**: Test annotations like `@WebMvcTest`, `@DataJpaTest`, and `@AutoConfigureCache` are now in modular packages (e.g., `org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest`) |
243 | | - |
244 | | -### SQLite Configuration Notes |
245 | | - |
246 | | -- **Date storage**: LocalDate fields are stored as Unix timestamps (INTEGER) for robustness - no parsing issues |
247 | | -- **Converter**: `UnixTimestampConverter` handles LocalDate ↔ epoch seconds conversion via JPA `@Convert` |
248 | | -- **DDL auto**: Use `ddl-auto=none` since the database is pre-seeded (SQLite has limited ALTER TABLE support) |
249 | | -- **Tests use H2**: The converter works seamlessly with both H2 and SQLite databases |
250 | | - |
251 | | -## CI/CD Pipeline |
252 | | - |
253 | | -### GitHub Actions Workflow (`.github/workflows/maven.yml`) |
254 | | - |
255 | | -1. **Verify Job**: Compile, test, generate coverage with `mvn verify` |
256 | | -2. **Coverage Job**: Upload JaCoCo reports to Codecov and Codacy |
257 | | -3. **Container Job**: Build and push Docker image to GitHub Container Registry (on `master` push only) |
258 | | - |
259 | | -**Required Secrets**: |
260 | | - |
261 | | -- `CODECOV_TOKEN`: Codecov integration token |
262 | | -- `CODACY_PROJECT_TOKEN`: Codacy integration token |
263 | | -- `GITHUB_TOKEN`: Automatically provided for GHCR push |
264 | | - |
265 | | -## Contributing |
266 | | - |
267 | | -Follow [Conventional Commits](https://www.conventionalcommits.org/): |
268 | | - |
269 | | -- `feat:` for new features |
270 | | -- `fix:` for bug fixes |
271 | | -- `chore:` for maintenance tasks |
272 | | - |
273 | | -**Commit Style**: Keep commits logical and atomic. Squash checkpoint commits before PR. |
274 | | - |
275 | | -**PR Requirements**: |
| 72 | +## 📚 Need More Detail? |
276 | 73 |
|
277 | | -- All tests must pass |
278 | | -- Coverage should not decrease significantly |
279 | | -- Follow existing code style and patterns |
280 | | -- Update API documentation if endpoints change |
| 74 | +**For operational procedures**: Load `#file:AGENTS.md` |
| 75 | +**For Docker expertise**: *(Planned)* `#file:SKILLS/docker-containerization/SKILL.md` |
| 76 | +**For testing patterns**: *(Planned)* `#file:SKILLS/testing-patterns/SKILL.md` |
281 | 77 |
|
282 | | -## Additional Resources |
| 78 | +--- |
283 | 79 |
|
284 | | -- **Code of Conduct**: See `CODE_OF_CONDUCT.md` |
285 | | -- **Detailed Contributing Guide**: See `CONTRIBUTING.md` |
286 | | -- **Project Philosophy**: Small, incremental changes over large rewrites (per Linus Torvalds quote in CONTRIBUTING.md) |
| 80 | +💡 **Why this structure?** Copilot auto-loads this file on every chat (~500 tokens). Loading `AGENTS.md` or `SKILLS/` explicitly gives you deep context only when needed, saving 80% of your token budget! |
0 commit comments