Skip to content

Commit 7657bc9

Browse files
authored
Merge pull request #341 from nanotaboada/feature/custom-instructions-for-copilot
chore: enhance copilot instructions with architecture details
2 parents 3b255e4 + dde65a0 commit 7657bc9

1 file changed

Lines changed: 93 additions & 63 deletions

File tree

.github/copilot-instructions.md

Lines changed: 93 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,110 +2,128 @@
22

33
These instructions guide GitHub Copilot on how to assist meaningfully within this repository.
44

5-
## 🎯 Project Overview
5+
## 🔭 Project Overview
66

7-
This project is a proof-of-concept Web API built using:
7+
This project is a proof-of-concept RESTful Web API built using:
88
- **.NET 8 (LTS)**
9-
- **ASP.NET Core**
10-
- **EF Core** with a **SQLite** database for simplicity
11-
- **Docker Compose** for basic containerization
9+
- **ASP.NET Core 8.0**
10+
- **EF Core 9.0** with **SQLite 3** database
11+
- **Docker Compose** for containerization
1212

1313
### Key Characteristics
1414
- **Purpose**: Learning-focused PoC demonstrating modern ASP.NET Core patterns
1515
- **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
16+
- **Focus**: Layered architecture, best practices, and maintainable code
17+
- **Database**: SQLite (dev); PostgreSQL planned for later
18+
- **Pattern**: Repository Pattern + Service Layer + AutoMapper + FluentValidation
1819

19-
## Coding Conventions
20+
## 📐 Coding Conventions
2021

2122
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)
23+
- **PascalCase**: Class names, methods, public properties
24+
- **camelCase**: Local variables, private fields
25+
- **Primary constructors**: Used throughout (controllers, services, repositories, middleware)
26+
- **async/await**: All I/O operations are asynchronous
27+
- **var**: Preferred for local variables when type is obvious
28+
- **Nullable reference types**: Enabled project-wide
29+
- **CSharpier**: Code formatter (opinionated style)
30+
- **XML docs**: Enabled for API documentation (NoWarn 1591 suppresses warnings)
2831

2932
## 🏗️ Architectural Patterns
3033

3134
This project follows a **layered architecture** with clear separation of concerns:
3235

3336
### 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+
- **Controllers** (`/Controllers`) - Handle HTTP requests/responses, route to services
38+
- **Services** (`/Services`) - Business logic, caching, orchestration
39+
- **Repositories** (`/Repositories`) - Data access abstraction (generic base + specific)
3740
- **Models** (`/Models`) - Domain entities and DTOs
3841
- `Player` - Core domain entity
39-
- `PlayerRequestModel` - Input validation model
40-
- `PlayerResponseModel` - API response model
42+
- `PlayerRequestModel` - Input validation model (used by FluentValidation)
43+
- `PlayerResponseModel` - API response model (mapped by AutoMapper)
4144
- **Validators** (`/Validators`) - FluentValidation rules
42-
- **Mappings** (`/Mappings`) - AutoMapper configurations
43-
- **Data** (`/Data`) - EF Core DbContext and database concerns
45+
- **Mappings** (`/Mappings`) - AutoMapper profiles
46+
- **Data** (`/Data`) - EF Core DbContext and database configuration
47+
- **Middlewares** (`/Middlewares`) - Custom middleware (exception handling)
48+
- **Extensions** (`/Extensions`) - Service registration and middleware extension methods
49+
- **Configurations** (`/Configurations`) - Swagger and rate limiter configurations
4450

4551
### 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+
- **Dependency Injection**: All services, repositories, validators registered in DI container
53+
- **Repository Pattern**: Generic base `Repository<T>` + specific `PlayerRepository` with custom queries
54+
- **Service Layer**: Business logic, caching, and orchestration (separated from controllers)
55+
- **AutoMapper**: Request/Response model transformations (bidirectional mapping)
56+
- **FluentValidation**: Input validation (structure/format in validators, business rules in services)
57+
- **Async/Await**: All I/O operations use async patterns (database, cache)
58+
- **Extension Methods**: Service registration grouped in `ServiceCollectionExtensions` by concern
59+
- **Global Exception Handling**: `ExceptionMiddleware` with RFC 7807 Problem Details format
5260

5361
## ✅ Copilot Should Focus On
5462

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
63+
- Generating idiomatic ASP.NET Core controller actions with minimal logic
64+
- Writing EF Core queries using LINQ with `AsNoTracking()` for read operations
65+
- Following async programming practices consistently
66+
- Producing unit tests using **xUnit** with **Moq** and **FluentAssertions**
67+
- Suggesting dependency-injected services using primary constructors
6068
- 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.)
69+
- Using `ILogger<T>` for structured logging with meaningful context
70+
- Working with Docker-friendly patterns (volume persistence, health checks)
71+
- Implementing proper error handling with RFC 7807 Problem Details
72+
- Using appropriate HTTP status codes (200, 201, 400, 404, 409, 500)
6573
- Following the existing caching patterns with `IMemoryCache`
74+
- Using extension methods to organize service registration by domain area
75+
- Implementing validation with FluentValidation for structure, service layer for business rules
6676

6777
## 🚫 Copilot Should Avoid
6878

6979
- Generating raw SQL unless explicitly required
7080
- Using EF Core synchronous APIs (e.g., `FirstOrDefault` over `FirstOrDefaultAsync`)
7181
- Suggesting static service or repository classes
72-
- Including XML comments or doc stubs unless requested
82+
- Including verbose XML comments or doc stubs unless requested
7383
- Suggesting patterns that conflict with DI (e.g., `new Service()` instead of constructor injection)
74-
- Using `ConfigureAwait(false)` in ASP.NET Core contexts
84+
- Using `ConfigureAwait(false)` in ASP.NET Core contexts (not needed)
7585
- Implementing complex inheritance hierarchies when composition is simpler
7686
- Adding unnecessary middleware or filters without clear purpose
87+
- Creating controller logic that belongs in services (fat controllers)
88+
- Mixing async and sync code patterns inconsistently
7789

7890
## 🧪 Testing
7991

8092
- Use **xUnit** with `[Fact]` and `[Theory]` attributes
81-
- Use **Moq** for mocking
93+
- Use **Moq** for mocking dependencies
94+
- Use **FluentAssertions** for readable test assertions
8295
- Prefer testing **service logic** and **controller behavior**
8396
- Place unit tests under `test/` following structure already present (e.g., `Unit/PlayerServiceTests.cs`)
8497
- **Test Naming**: Follow `Given_When_Then` pattern (e.g., `GivenCreateAsync_WhenRepositoryAddAsync_ThenAddsPlayerToRepositoryAndRemovesCache`)
8598
- **Test Structure**: Use Arrange, Act, Assert comments to organize test code
8699
- **Test Attributes**: Add `[Trait("Category", "Unit")]` to all unit tests
87-
- **Test Data**: Use faker patterns for consistent test data generation
88-
- **Assertions**: FluentAssertions for readable test assertions
100+
- **Test Data**: Use faker patterns for consistent test data generation (see `PlayerFakes` utility)
101+
- **Mocking Setup**: Use `PlayerMocks.InitServiceMocks()` pattern for consistent mock initialization
102+
- **Verify Calls**: Always verify repository/service interactions with `Times.Once` or appropriate multiplicity
89103

90104
## ⚡ Performance & Best Practices
91105

92-
- Use `AsNoTracking()` for read-only EF Core queries
106+
- Use `AsNoTracking()` for read-only EF Core queries (already implemented in Repository base class)
93107
- Implement caching patterns with `IMemoryCache` for frequently accessed data
94-
- Use `DbContextPool` for better performance (already configured)
95-
- Follow async/await patterns consistently
108+
- Cache TTL: Sliding expiration (10 min) + absolute expiration (1 hour)
109+
- Cache invalidation: Remove cache on data modifications
110+
- Use `AddDbContextPool<T>()` for better performance (already configured)
111+
- Follow async/await patterns consistently throughout the stack
96112
- Validate input using **FluentValidation** before processing
97-
- Use AutoMapper for object transformations
98-
- Implement proper logging with structured logging patterns
113+
- Use AutoMapper for object transformations (avoid manual mapping)
114+
- Implement proper logging with structured logging patterns using Serilog
115+
- Use primary constructors for DI to reduce boilerplate
116+
- Group service registration in extension methods by domain area (see `ServiceCollectionExtensions`)
99117

100-
## 🔧 Tooling & Environment
118+
## 🛠 Tooling & Environment
101119

102120
- Format code with **CSharpier**
103121
- SQLite is used in development; **PostgreSQL** may be introduced in production later
104122
- Code runs in a **Docker Compose** environment
105123
- .NET 8 SDK is required
106124
- All configurations live in `appsettings.*.json` files
107125

108-
## 🏷️ Technology Stack Deep Dive
126+
## 📚 Technology Stack Deep Dive
109127

110128
### Entity Framework Core
111129
- **DbContext**: `PlayerDbContext` with SQLite provider
@@ -117,26 +135,27 @@ This project follows a **layered architecture** with clear separation of concern
117135
### AutoMapper
118136
- **Profile**: `PlayerMappingProfile` handles all object mappings
119137
- **Bidirectional**: Maps between request/response models and entities
120-
- **Integration**: Registered in DI container
138+
- **Integration**: Registered in DI container via `AddMappings()` extension
121139

122140
### FluentValidation
123141
- **Validators**: `PlayerRequestModelValidator` for input validation
124142
- **Integration**: Automatic validation in controllers before processing
125-
- **Error Messages**: Descriptive validation messages
143+
- **Error Messages**: Descriptive validation messages with property names
126144

127145
### Caching Strategy
128146
- **IMemoryCache**: Service-level caching for read operations
129-
- **Cache Keys**: Consistent naming with `nameof()` pattern
130-
- **Invalidation**: Cache cleared on data modifications
147+
- **Cache Keys**: Consistent naming with `nameof()` pattern (e.g., `nameof(RetrieveAsync)`)
148+
- **Invalidation**: Cache cleared on data modifications via `Remove(CacheKey)`
131149
- **TTL**: Sliding expiration (10 min) + absolute expiration (1 hour)
132150

133151
### Logging with Serilog
134-
- **Structured Logging**: Consistent log message templates
152+
- **Structured Logging**: Consistent log message templates with `{@Property}` for object serialization
135153
- **Log Levels**: Appropriate use of Information, Warning, Error
136-
- **Context**: Include relevant data in log messages
137-
- **Configuration**: File and console sinks configured
154+
- **Context**: Include relevant data in log messages (e.g., player IDs, squad numbers)
155+
- **Configuration**: File and console sinks configured in `appsettings.json`
156+
- **Output**: Logs to `logs/log-<date>.log` and console with custom templates
138157

139-
## 🧩 Folder Conventions
158+
## 🗂 Folder Conventions
140159

141160
- `Controllers` for Web API endpoints
142161
- `Services` for business logic
@@ -150,7 +169,7 @@ This project follows a **layered architecture** with clear separation of concern
150169

151170
Keep things **simple, clear, and idiomatic**. This is a learning-focused PoC — clarity and maintainability win over overengineering.
152171

153-
## 📋 Common Patterns in This Codebase
172+
## 🧭 Common Patterns in This Codebase
154173

155174
### Repository Pattern
156175
```csharp
@@ -173,7 +192,7 @@ public class PlayerRepository : Repository<Player>, IPlayerRepository
173192
```csharp
174193
public class PlayerService : IPlayerService
175194
{
176-
// Dependencies injected via constructor
195+
// Dependencies injected via primary constructor
177196
// Business logic with caching
178197
// AutoMapper for transformations
179198
// Logging for observability
@@ -193,7 +212,19 @@ public class PlayerController : ControllerBase
193212
}
194213
```
195214

196-
## 🎯 Domain Knowledge
215+
### Exception Middleware Pattern
216+
```csharp
217+
// Global exception handling with RFC 7807 Problem Details
218+
public class ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger, IHostEnvironment environment)
219+
{
220+
// Maps exceptions to appropriate HTTP status codes
221+
// Returns standardized problem details JSON
222+
// Includes stack traces in development only
223+
}
224+
```
225+
226+
227+
## 💡 Domain Knowledge
197228

198229
### Player Entity Context
199230
- **Squad Numbers**: Must be unique (1-99 typically)
@@ -231,7 +262,7 @@ return player; // Let caller handle null
231262
3. **Caching**: Service layer implements `IMemoryCache` for read operations
232263
4. **Logging**: Structured logging at each layer for observability
233264

234-
## 🎯 When to Use Different Approaches
265+
## 🤔 When to Use Different Approaches
235266

236267
### Choose EF Core When:
237268
- Simple CRUD operations (current use case)
@@ -253,7 +284,7 @@ return player; // Let caller handle null
253284
- Use route parameters for resource identification
254285
- Apply validation before processing requests
255286

256-
## 🛠️ Essential Commands & Workflows
287+
## ️ Essential Commands & Workflows
257288

258289
### Build & Run
259290
```bash
@@ -337,7 +368,7 @@ docker compose down -v
337368
- Default: 60 requests per 60 seconds (fixed window)
338369
- Queue limit: 0 (immediate rejection when limit reached)
339370

340-
## 🚨 Common Issues & Workarounds
371+
## 🔧 Common Issues & Workarounds
341372

342373
### Database Path Issues
343374
- **Development**: `storage/players-sqlite3.db` (source, copied to `bin/Debug/net8.0/storage/` during build)
@@ -381,6 +412,5 @@ See open issues on GitHub for planned enhancements:
381412
- **PostgreSQL Support** ([#249](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/249)) - Add PostgreSQL to Docker Compose setup
382413
- **.NET Aspire Integration** ([#256](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/256)) - Evaluate Aspire for dev-time orchestration and observability
383414
- **JWT Authentication** ([#105](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/105)) - Implement Client Credentials Flow for protected routes
384-
- **Global Exception Handling** ([#184](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/184)) - Add middleware with RFC 7807 Problem Details
385415
- **Optimistic Concurrency** ([#65](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/65)) - Handle conflicts with application-managed tokens
386416
- **Database Normalization** ([#125](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/125)) - Extract Position, Team, League into separate tables

0 commit comments

Comments
 (0)