|
1 | | -# GitHub Copilot Instructions |
| 1 | +# Copilot Instructions |
2 | 2 |
|
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) |
| 3 | +## Project Overview |
6 | 4 |
|
7 | | -## Quick Context |
| 5 | +REST API for managing football players built with Java 25 and Spring Boot 4. Demonstrates layered architecture (Controller → Service → Repository), Spring Data JPA with SQLite, comprehensive validation, caching, and Swagger documentation. |
8 | 6 |
|
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 |
| 7 | +## Quick Start |
13 | 8 |
|
14 | | -## Core Conventions |
15 | | - |
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 |
22 | | -- **Commit Messages**: Follow Conventional Commits with issue number suffix |
23 | | - - Format: `type(scope): description (#issue)` (max 80 chars) |
24 | | - - Example: `docs: optimize AI agent instructions for token efficiency (#259)` |
25 | | - - Types: `feat`, `fix`, `chore`, `docs`, `test`, `refactor` |
26 | | - |
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. |
| 9 | +```bash |
| 10 | +# Development |
| 11 | +./mvnw spring-boot:run # Run with hot reload (port 9000) |
| 12 | +./mvnw clean test # Run tests |
| 13 | +./mvnw clean test jacoco:report # Test with coverage |
54 | 14 |
|
55 | | -## Architecture at a Glance |
| 15 | +# Docker |
| 16 | +docker compose up # Start in container |
| 17 | +docker compose down -v # Reset database |
56 | 18 |
|
| 19 | +# Documentation |
| 20 | +http://localhost:9000/swagger/index.html # API docs |
| 21 | +http://localhost:9001/actuator/health # Health check |
57 | 22 | ``` |
58 | | -Controller → Service → Repository → JPA → Database |
59 | | - ↓ ↓ ↓ |
60 | | -Validation Cache Query Methods |
61 | | -``` |
62 | | - |
63 | | -- **Controllers**: REST endpoints with @RestController |
64 | | -- **Services**: Business logic with @Service + caching |
65 | | -- **Repositories**: JpaRepository with derived queries |
66 | | -- **DTOs**: ModelMapper for entity ↔ DTO transformations |
67 | | -- **Cache**: Spring Cache abstraction (1-hour TTL) |
68 | | - |
69 | | -## Copilot Should |
70 | | - |
71 | | -- Generate idiomatic Spring Boot code with proper annotations |
72 | | -- Use JPA repository patterns (derived queries, @Query) |
73 | | -- Follow REST conventions with ResponseEntity<T> |
74 | | -- Write tests with @SpringBootTest and MockMvc |
75 | | -- Apply Lombok annotations to reduce boilerplate |
76 | | -- Use ModelMapper for DTO transformations |
77 | | -- Implement proper exception handling with @ControllerAdvice |
78 | 23 |
|
79 | | -## Copilot Should Avoid |
| 24 | +## Stack |
| 25 | + |
| 26 | +- Java 25 (LTS, required) |
| 27 | +- Spring Boot 4.0.0 (Spring MVC) |
| 28 | +- Spring Data JPA + Hibernate |
| 29 | +- SQLite (file-based runtime, in-memory tests) |
| 30 | +- Maven 3 (use `./mvnw` wrapper) |
| 31 | +- Bean Validation (JSR-380) |
| 32 | +- Spring Cache (1-hour TTL) |
| 33 | +- JUnit 5 + AssertJ + MockMvc |
| 34 | +- JaCoCo (coverage) |
| 35 | +- SpringDoc OpenAPI 3 (Swagger) |
| 36 | +- Lombok (boilerplate reduction) |
| 37 | + |
| 38 | +## Project Patterns |
| 39 | + |
| 40 | +- **Architecture**: Layered (Controller → Service → Repository → JPA) |
| 41 | +- **Dependency Injection**: Constructor injection via Lombok `@RequiredArgsConstructor` |
| 42 | +- **Error Handling**: `@ControllerAdvice` for global exception handling |
| 43 | +- **Validation**: Bean Validation annotations in DTOs (`@NotNull`, `@Min`, etc.) |
| 44 | +- **Caching**: Spring `@Cacheable` on service layer (1-hour TTL) |
| 45 | +- **DTO Pattern**: ModelMapper for entity ↔ DTO transformations |
| 46 | +- **Repository**: Spring Data JPA with derived queries and custom JPQL |
| 47 | + |
| 48 | +## Code Conventions |
| 49 | + |
| 50 | +- **Naming**: camelCase (methods/variables), PascalCase (classes), UPPER_SNAKE_CASE (constants) |
| 51 | +- **Files**: Class name matches file name (e.g., `PlayersController.java`) |
| 52 | +- **Package Structure**: |
| 53 | + - `controllers/` - REST endpoints (`@RestController`) |
| 54 | + - `services/` - Business logic (`@Service`) |
| 55 | + - `repositories/` - Data access (`@Repository`, extends `JpaRepository`) |
| 56 | + - `models/` - Domain entities (`@Entity`) and DTOs |
| 57 | + - `converters/` - JPA attribute converters |
| 58 | +- **Annotations**: |
| 59 | + - Controllers: `@RestController`, `@RequestMapping`, `@Operation` (OpenAPI) |
| 60 | + - Services: `@Service`, `@Transactional`, `@Cacheable` |
| 61 | + - Repositories: `@Repository` (Spring Data JPA) |
| 62 | + - DTOs: `@NotNull`, `@Min`, `@Max` (Bean Validation) |
| 63 | + - Entities: `@Entity`, `@Table`, `@Id`, `@GeneratedValue` |
| 64 | +- **Lombok**: `@Data`, `@Builder`, `@AllArgsConstructor`, `@RequiredArgsConstructor` |
| 65 | +- **Logging**: SLF4J (never `System.out.println`) |
| 66 | + |
| 67 | +## Testing |
| 68 | + |
| 69 | +- **Structure**: `*Tests.java` in `src/test/java/` (mirrors main package structure) |
| 70 | +- **Naming Pattern**: `method_scenario_outcome` |
| 71 | + - `method`: Method under test (e.g., `post`, `findById`, `create`) |
| 72 | + - `scenario`: Context (e.g., `playerExists`, `invalidData`, `noMatches`) |
| 73 | + - `outcome`: Expected result (e.g., `returnsPlayer`, `returnsConflict`, `returnsEmpty`) |
| 74 | +- **Examples**: |
| 75 | + |
| 76 | + ```java |
| 77 | + // Controller |
| 78 | + void post_squadNumberExists_returnsConflict() |
| 79 | + |
| 80 | + // Service |
| 81 | + void create_noConflict_returnsPlayerDTO() |
| 82 | + |
| 83 | + // Repository |
| 84 | + void findById_playerExists_returnsPlayer() |
| 85 | + ``` |
| 86 | + |
| 87 | +- **JavaDoc**: BDD Given/When/Then structure in test comments |
| 88 | + |
| 89 | + ```java |
| 90 | + /** |
| 91 | + * Given a player with squad number 5 already exists in the database |
| 92 | + * When POST /players is called with a new player using squad number 5 |
| 93 | + * Then response status is 409 Conflict |
| 94 | + */ |
| 95 | + @Test |
| 96 | + void post_squadNumberExists_returnsConflict() { ... } |
| 97 | + ``` |
| 98 | + |
| 99 | +- **Annotations**: `@SpringBootTest`, `@AutoConfigureMockMvc`, `@Test` |
| 100 | +- **Assertions**: AssertJ (fluent, e.g., `assertThat(result).isNotNull()`) |
| 101 | +- **Mocking**: Mockito for service layer tests |
| 102 | +- **Database**: Tests use in-memory SQLite (auto-cleared after each test) |
| 103 | +- **Coverage**: Target high coverage (JaCoCo reports in `target/site/jacoco/`) |
| 104 | + |
| 105 | +## Avoid |
80 | 106 |
|
81 | 107 | - Field injection (use constructor injection) |
82 | | -- Using `new` for services (breaks DI) |
83 | | -- Missing @Transactional on service methods |
| 108 | +- Using `new` for Spring beans (breaks DI) |
| 109 | +- Missing `@Transactional` on service methods that modify data |
84 | 110 | - Exposing entities directly in controllers (use DTOs) |
85 | | -- System.out.println (use SLF4J logging) |
86 | | -- Hardcoded configuration (use @Value or application.yml) |
| 111 | +- `System.out.println` (use SLF4J logging) |
| 112 | +- Hardcoded configuration (use `@Value` or `application.properties`) |
| 113 | +- Ignoring exceptions (always handle or propagate) |
| 114 | +- Testing implementation details (test behavior, not internals) |
87 | 115 |
|
88 | | -## Quick Commands |
| 116 | +## Commit Messages |
89 | 117 |
|
90 | | -```bash |
91 | | -# Run with hot reload |
92 | | -./mvnw spring-boot:run |
| 118 | +Follow Conventional Commits format (enforced by commitlint in CI): |
93 | 119 |
|
94 | | -# Test with coverage |
95 | | -./mvnw clean test jacoco:report |
| 120 | +**Format**: `type(scope): description (#issue)` (max 80 chars) |
96 | 121 |
|
97 | | -# Docker |
98 | | -docker compose up |
| 122 | +**Types**: `feat`, `fix`, `docs`, `test`, `refactor`, `chore`, `ci`, `perf`, `style`, `build` |
99 | 123 |
|
100 | | -# Swagger: http://localhost:9000/swagger-ui/index.html |
101 | | -# Actuator: http://localhost:9001/actuator/health |
102 | | -``` |
103 | | - |
104 | | -## Need More Detail? |
| 124 | +**Examples**: |
105 | 125 |
|
106 | | -**For operational procedures**: Load `#file:AGENTS.md` |
107 | | -**For Docker expertise**: *(Planned)* `#file:SKILLS/docker-containerization/SKILL.md` |
108 | | -**For testing patterns**: *(Planned)* `#file:SKILLS/testing-patterns/SKILL.md` |
| 126 | +- `feat(api): add player stats endpoint (#42)` |
| 127 | +- `fix(service): resolve cache invalidation bug (#88)` |
| 128 | +- `test: adopt BDD Given-When-Then pattern across all tests (#266)` |
109 | 129 |
|
110 | 130 | --- |
111 | 131 |
|
112 | | -**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! |
| 132 | +For detailed workflows, troubleshooting, and CI/CD setup, load `#file:AGENTS.md`. |
0 commit comments