Skip to content

Commit 8e9c942

Browse files
committed
chore: add GitHub Copilot instructions file
Add comprehensive .github/copilot-instructions.md with detailed guidance for AI assistance including: - Project overview and architectural patterns - Coding conventions and technology stack details - Common patterns for ASP.NET Core development - Domain knowledge with football position abbreviations - Error handling patterns and data flow examples - Clear guidelines for Copilot focus areas Closes #271
1 parent 42ad95f commit 8e9c942

File tree

1 file changed

+260
-0
lines changed

1 file changed

+260
-0
lines changed

.github/copilot-instructions.md

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# GitHub Copilot Instructions
2+
3+
These instructions guide GitHub Copilot on how to assist meaningfully within this repository.
4+
5+
## 🎯 Project Overview
6+
7+
This project is a proof-of-concept Web API built using:
8+
- **.NET 8 (LTS)**
9+
- **ASP.NET Core**
10+
- **EF Core** with a **SQLite** database for simplicity
11+
- **Docker Compose** for basic containerization
12+
13+
### Key Characteristics
14+
- **Purpose**: Learning-focused PoC demonstrating modern ASP.NET Core patterns
15+
- **Complexity**: Simple CRUD operations with a single `Player` entity
16+
- **Focus**: Clean architecture, best practices, and maintainable code
17+
- **Database**: SQLite for development; PostgreSQL may be introduced later
18+
19+
## ✅ Coding Conventions
20+
21+
Follow standard C# conventions:
22+
- Use `PascalCase` for class names, methods, and public properties
23+
- Use `camelCase` for local variables and private fields
24+
- Use `async/await` consistently for asynchronous code
25+
- Prefer `var` for local variable declarations where the type is obvious
26+
- Nullable reference types are **enabled**
27+
- Use `CSharpier` formatting standards (opinionated)
28+
29+
## 🏗️ Architectural Patterns
30+
31+
This project follows a **layered architecture** with clear separation of concerns:
32+
33+
### Layer Structure
34+
- **Controllers** (`/Controllers`) - Handle HTTP requests and responses
35+
- **Services** (`/Services`) - Contain business logic and orchestration
36+
- **Repositories** (`/Repositories`) - Abstract data access layer
37+
- **Models** (`/Models`) - Domain entities and DTOs
38+
- `Player` - Core domain entity
39+
- `PlayerRequestModel` - Input validation model
40+
- `PlayerResponseModel` - API response model
41+
- **Validators** (`/Validators`) - FluentValidation rules
42+
- **Mappings** (`/Mappings`) - AutoMapper configurations
43+
- **Data** (`/Data`) - EF Core DbContext and database concerns
44+
45+
### Design Principles
46+
- **Dependency Injection** for all services and repositories
47+
- **Repository Pattern** for data access abstraction
48+
- **Service Layer** for business logic encapsulation
49+
- **AutoMapper** for clean object transformations
50+
- **FluentValidation** for robust input validation
51+
- **Async/Await** throughout the application stack
52+
53+
## ✅ Copilot Should Focus On
54+
55+
- Generating idiomatic ASP.NET Core controller actions
56+
- Writing EF Core queries using LINQ
57+
- Following async programming practices
58+
- Producing unit tests using **xUnit**
59+
- Suggesting dependency-injected services
60+
- Adhering to RESTful naming and HTTP status codes
61+
- Using `ILogger<T>` for logging
62+
- Working with Docker-friendly patterns
63+
- Implementing proper error handling and validation
64+
- Using appropriate HTTP status codes (200, 201, 400, 404, 409, etc.)
65+
- Following the existing caching patterns with `IMemoryCache`
66+
67+
## 🚫 Copilot Should Avoid
68+
69+
- Generating raw SQL unless explicitly required
70+
- Using EF Core synchronous APIs (e.g., `FirstOrDefault` over `FirstOrDefaultAsync`)
71+
- Suggesting static service or repository classes
72+
- Including XML comments or doc stubs unless requested
73+
- Suggesting patterns that conflict with DI (e.g., `new Service()` instead of constructor injection)
74+
- Using `ConfigureAwait(false)` in ASP.NET Core contexts
75+
- Implementing complex inheritance hierarchies when composition is simpler
76+
- Adding unnecessary middleware or filters without clear purpose
77+
78+
## 🧪 Testing
79+
80+
- Use **xUnit**
81+
- Use **Moq** for mocking
82+
- Prefer testing **service logic** and **controller behavior**
83+
- Place unit tests under `test/` following structure already present (e.g., `Unit/PlayerServiceTests.cs`)
84+
- **Test Data**: Use faker patterns for consistent test data generation
85+
- **Assertions**: FluentAssertions for readable test assertions
86+
87+
## ⚡ Performance & Best Practices
88+
89+
- Use `AsNoTracking()` for read-only EF Core queries
90+
- Implement caching patterns with `IMemoryCache` for frequently accessed data
91+
- Use `DbContextPool` for better performance (already configured)
92+
- Follow async/await patterns consistently
93+
- Validate input using **FluentValidation** before processing
94+
- Use AutoMapper for object transformations
95+
- Implement proper logging with structured logging patterns
96+
97+
## 🔧 Tooling & Environment
98+
99+
- Format code with **CSharpier**
100+
- SQLite is used in development; **PostgreSQL** may be introduced in production later
101+
- Code runs in a **Docker Compose** environment
102+
- .NET 8 SDK is required
103+
- All configurations live in `appsettings.*.json` files
104+
105+
## 🏷️ Technology Stack Deep Dive
106+
107+
### Entity Framework Core
108+
- **DbContext**: `PlayerDbContext` with SQLite provider
109+
- **Migrations**: Used for schema management and data seeding
110+
- **Pooling**: `AddDbContextPool` for better performance
111+
- **Query Optimization**: `AsNoTracking()` for read-only operations
112+
- **Async Operations**: All database calls use async/await
113+
114+
### AutoMapper
115+
- **Profile**: `PlayerMappingProfile` handles all object mappings
116+
- **Bidirectional**: Maps between request/response models and entities
117+
- **Integration**: Registered in DI container
118+
119+
### FluentValidation
120+
- **Validators**: `PlayerRequestModelValidator` for input validation
121+
- **Integration**: Automatic validation in controllers before processing
122+
- **Error Messages**: Descriptive validation messages
123+
124+
### Caching Strategy
125+
- **IMemoryCache**: Service-level caching for read operations
126+
- **Cache Keys**: Consistent naming with `nameof()` pattern
127+
- **Invalidation**: Cache cleared on data modifications
128+
- **TTL**: Sliding expiration (10 min) + absolute expiration (1 hour)
129+
130+
### Logging with Serilog
131+
- **Structured Logging**: Consistent log message templates
132+
- **Log Levels**: Appropriate use of Information, Warning, Error
133+
- **Context**: Include relevant data in log messages
134+
- **Configuration**: File and console sinks configured
135+
136+
## 🧩 Folder Conventions
137+
138+
- `Controllers` for Web API endpoints
139+
- `Services` for business logic
140+
- `Repositories` for data access
141+
- `Models` for domain and DTO objects
142+
- `Mappings` for AutoMapper profiles
143+
- `Validators` for FluentValidation rules
144+
- `Utilities` for shared helper logic
145+
146+
## 🧘 General Philosophy
147+
148+
Keep things **simple, clear, and idiomatic**. This is a learning-focused PoC — clarity and maintainability win over overengineering.
149+
150+
## 📋 Common Patterns in This Codebase
151+
152+
### Repository Pattern
153+
```csharp
154+
// Generic repository base class
155+
public class Repository<T> : IRepository<T> where T : class
156+
{
157+
protected readonly DbSet<T> _dbSet;
158+
// Standard CRUD operations with async/await
159+
}
160+
161+
// Specific repository with custom queries
162+
public class PlayerRepository : Repository<Player>, IPlayerRepository
163+
{
164+
public async Task<Player?> FindBySquadNumberAsync(int squadNumber) =>
165+
await _dbSet.FirstOrDefaultAsync(p => p.SquadNumber == squadNumber);
166+
}
167+
```
168+
169+
### Service Layer Pattern
170+
```csharp
171+
public class PlayerService : IPlayerService
172+
{
173+
// Dependencies injected via constructor
174+
// Business logic with caching
175+
// AutoMapper for transformations
176+
// Logging for observability
177+
}
178+
```
179+
180+
### Controller Pattern
181+
```csharp
182+
[ApiController]
183+
[Route("players")]
184+
public class PlayerController : ControllerBase
185+
{
186+
// Minimal controllers - delegate to services
187+
// Proper HTTP status codes
188+
// FluentValidation integration
189+
// Structured logging
190+
}
191+
```
192+
193+
## 🎯 Domain Knowledge
194+
195+
### Player Entity Context
196+
- **Squad Numbers**: Must be unique (1-99 typically)
197+
- **Positions**: Football/Soccer positions with 2-character abbreviations (GK, RB, LB, CB, DM, CM, RW, AM, CF, SS, LW)
198+
- **Starting11**: Boolean indicating if player is in starting lineup
199+
- **Team/League**: String fields for team and league information
200+
201+
### Business Rules
202+
- Squad numbers cannot be duplicated
203+
- All operations should be logged for traceability
204+
- Cache invalidation on data modifications
205+
- Async operations throughout the stack
206+
207+
## 🚨 Error Handling Patterns
208+
209+
```csharp
210+
// Controller level - return appropriate HTTP status codes
211+
if (await playerService.RetrieveBySquadNumberAsync(squadNumber) != null)
212+
{
213+
return TypedResults.Conflict($"Squad number {squadNumber} already exists");
214+
}
215+
216+
// Service level - structured logging
217+
logger.LogWarning("Player with squad number {SquadNumber} not found", squadNumber);
218+
219+
// Repository level - null handling
220+
var player = await _dbSet.FirstOrDefaultAsync(p => p.Id == id);
221+
return player; // Let caller handle null
222+
```
223+
224+
## 🔄 Data Flow Patterns
225+
226+
1. **Request Flow**: Controller → Validation → Service → Repository → Database
227+
2. **Response Flow**: Database → Repository → Service → AutoMapper → Controller → Client
228+
3. **Caching**: Service layer implements `IMemoryCache` for read operations
229+
4. **Logging**: Structured logging at each layer for observability
230+
231+
## 🎯 When to Use Different Approaches
232+
233+
### Choose EF Core When:
234+
- Simple CRUD operations (current use case)
235+
- Rapid development needed
236+
- Strong typing and compile-time checking preferred
237+
- Schema migrations are important
238+
239+
### Consider Raw SQL/Dapper When:
240+
- Complex queries with performance requirements
241+
- Need fine-grained control over SQL
242+
- Working with existing stored procedures
243+
- Micro-service with minimal ORM overhead
244+
245+
## 🌐 API Design Guidelines
246+
247+
- Use proper HTTP verbs (GET, POST, PUT, DELETE)
248+
- Return appropriate status codes (200, 201, 400, 404, 409, 500)
249+
- Implement consistent error response formats
250+
- Use route parameters for resource identification
251+
- Apply validation before processing requests
252+
253+
## 🚀 Future Evolution Considerations
254+
255+
- **Database Migration**: SQLite → PostgreSQL transition path
256+
- **Authentication**: JWT Bearer token implementation ready
257+
- **API Versioning**: URL-based versioning strategy
258+
- **OpenAPI**: Comprehensive Swagger documentation
259+
- **Monitoring**: Health checks and metrics endpoints
260+
- **Containerization**: Docker multi-stage builds optimized

0 commit comments

Comments
 (0)