Template
✨ Adds project guidelines and conventions for Github Copilot
Introduces detailed instructions for ASP.NET API, C#, Docker, MSBuild, testing, and library creation. These guidelines aim to standardize development practices and improve code quality across the project.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
# Project Guidelines
|
||||
|
||||
## Behaviour
|
||||
|
||||
- **Tone**: direct and concise — minimise prose, maximise actionable output.
|
||||
- **Research first, act second** — always consult official documentation, codebase context, and project conventions **before** proposing or implementing changes. Never guess, assume API shapes, or rely on trial-and-error. If documentation is unclear or unavailable, say so and ask for guidance.
|
||||
- On ambiguous requests, **ask for clarification** — prefer offering interactive options over waiting for a new prompt.
|
||||
- Briefly explain every suggestion: what it does, why, and how it fits the architecture.
|
||||
- Work in parallel whenever possible.
|
||||
- **Prefer subagents** for multi-step read-only operations (searches, file reads, doc fetches) to conserve main conversation context.
|
||||
- When goals conflict (e.g., performance vs readability), **favour performance** unless readability is significantly harmed.
|
||||
- **Persist learnings** — when you discover a pattern, resolve a non-obvious issue, or make a decision worth remembering, save it to memory. Use repo memory for project-specific facts and user memory for general preferences. Keep memory up to date when instructions or project conventions change.
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
description: "Use when writing API endpoints, routing, middleware, request/response handling, OpenAPI configuration, or HTTP pipeline setup in ASP.NET. Covers Minimal API conventions, error handling, and endpoint organisation."
|
||||
---
|
||||
# ASP.NET API Conventions
|
||||
|
||||
## Routing
|
||||
|
||||
- All endpoints live under `/api/v{apiVersion}/{resource}`.
|
||||
- Default to `/api/v1` for projects without explicit API versioning.
|
||||
|
||||
## Endpoints
|
||||
|
||||
- Prefer **Minimal APIs**; use Controllers only when the added structure is justified.
|
||||
- Group related endpoints using `MapGroup()` with a shared prefix and tag.
|
||||
- Use **typed results** (`TypedResults.Ok()`, `TypedResults.NotFound()`) over untyped `Results` for OpenAPI metadata inference.
|
||||
- Return **`ProblemDetails`** (RFC 9457) for all error responses — configure via `AddProblemDetails()`.
|
||||
|
||||
## Request Handling
|
||||
|
||||
- Bind request data with **`[AsParameters]`** for complex parameter sets.
|
||||
- Validate input at the endpoint boundary — use **filters** or **`IValidatableObject`** to fail fast.
|
||||
- Use **`CancellationToken`** on all async endpoints.
|
||||
|
||||
## Endpoint Organisation
|
||||
|
||||
- One file per resource or feature area (e.g., `UserEndpoints.cs`, `OrderEndpoints.cs`).
|
||||
- Register via extension methods on `IEndpointRouteBuilder`: `MapUserEndpoints()`.
|
||||
- Keep endpoint lambdas thin — delegate business logic to injected services.
|
||||
|
||||
## OpenAPI
|
||||
|
||||
- Annotate endpoints with `.WithTags()` for grouping in the generated spec.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
description: "Use when writing or modifying C# source code. Covers non-obvious defaults not caught by analyzers."
|
||||
applyTo: "**/*.cs"
|
||||
---
|
||||
# C# Conventions
|
||||
|
||||
Code style is enforced by `.editorconfig`, `.globalconfig`, and StyleCop analyzers — do not restate their rules.
|
||||
|
||||
## Non-Obvious Defaults
|
||||
|
||||
- XML doc comments required on public API in `src/` (suppressed in `tests/` and `samples/`).
|
||||
- Avoid `null!` (null-forgiving operator) — fix the nullability flow instead of suppressing the warning.
|
||||
|
||||
## Patterns
|
||||
|
||||
- Prefer **records** for DTOs, value objects, and other immutable data carriers.
|
||||
- Use `LoggerMessage`-generated `partial` methods on a `partial class` — never log inline (e.g., `logger.LogInformation(…)`).
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
description: "Use when editing Dockerfile, compose files, or Docker-related configuration. Covers guardrails for the multi-stage build and runtime image selection."
|
||||
applyTo: "docker/**,compose*.yaml"
|
||||
---
|
||||
# Docker Conventions
|
||||
|
||||
`docker/Dockerfile` is a multi-stage pipeline — stage names and purposes are visible in the file itself.
|
||||
|
||||
## Guardrails
|
||||
|
||||
- **Build context** is always the repo root, not `docker/`.
|
||||
- **`COPY --link`** is used intentionally for layer cache — do not replace with plain `COPY`.
|
||||
- **Cache mounts** (`--mount=type=cache,target=/root/.nuget/packages`) must stay on restore, build, test, and publish steps.
|
||||
- **Stage dependency chain** must be preserved (e.g., `build` → `restore`, `test` → `build`, `publish` → `test`).
|
||||
- New stages should follow the existing pattern: `FROM <parent> AS <name>`.
|
||||
|
||||
## Build Args
|
||||
|
||||
- `RUNTIME_BASE`: `web` (ASP.NET), `app` (console), or `self-contained`
|
||||
- `CONFIGURATION`: `Release` (default) or `Debug`
|
||||
- `PUBLISHED_PROJECT`: Project name to publish (without path or extension)
|
||||
- `DATABASE_PROJECT`: EF Core project for migration bundles
|
||||
- `DBCONTEXT`: Optional DbContext name for migrations
|
||||
|
||||
## Image Selection
|
||||
|
||||
| Use Case | `RUNTIME_BASE` | Base Image |
|
||||
|----------|----------------|------------|
|
||||
| ASP.NET web apps | `web` | `aspnet:*-alpine-composite-extra` |
|
||||
| Console / worker | `app` | `runtime:*-alpine-extra` |
|
||||
| Self-contained | `self-contained` | `runtime-deps:*-alpine-extra` |
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
description: "Use when editing MSBuild files (.csproj, .props, .targets). Covers central package management, artifacts layout, and property inheritance."
|
||||
applyTo: "**/*.{csproj,props,targets}"
|
||||
---
|
||||
# MSBuild Conventions
|
||||
|
||||
## Central Package Management
|
||||
|
||||
All package versions are declared in `Directory.Packages.props` at the repo root. In `.csproj` files:
|
||||
|
||||
```xml
|
||||
<!-- Correct -->
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
|
||||
<!-- Wrong — never specify Version -->
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
```
|
||||
|
||||
To add or update a version, edit `Directory.Packages.props`:
|
||||
|
||||
```xml
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
```
|
||||
|
||||
## Properties Set Centrally (Do Not Override)
|
||||
|
||||
These are configured in the root `Directory.Build.props` — do **not** set them in individual projects:
|
||||
|
||||
`LangVersion`, `Nullable`, `ImplicitUsings`.
|
||||
|
||||
## InternalsVisibleTo
|
||||
|
||||
Handled automatically via `<InternalsVisibleToSuffix>` in the root props. Default suffixes are `.Tests` and `Tests`. To add custom visibility:
|
||||
|
||||
<parameter name="newString">```xml
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="MyProject.IntegrationTests" />
|
||||
</ItemGroup>
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
description: "Use when creating or modifying test projects under the tests/ folder. Covers naming conventions and structural guardrails."
|
||||
applyTo: "tests/**"
|
||||
---
|
||||
# Test Project Conventions
|
||||
|
||||
Build configuration is handled by `tests/Directory.Build.props` — do not restate its settings.
|
||||
|
||||
## Framework
|
||||
|
||||
- **Testing**: TUnit.
|
||||
- **Mocking**: NSubstitute (analyzers auto-added when referenced).
|
||||
|
||||
## Naming
|
||||
|
||||
- Test project: `<ProjectUnderTest>.Tests` (matches InternalsVisibleTo default).
|
||||
- Test classes: `<ClassUnderTest>Tests`.
|
||||
- Test methods: descriptive names — `MethodName_Condition_ExpectedResult` or similar.
|
||||
|
||||
## Structure
|
||||
|
||||
- Follow **Arrange / Act / Assert**.
|
||||
- Always propose a set of basic tests for new or changed code.
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
name: docker-build
|
||||
description: "Build, test, publish, or pack .NET projects using the multi-stage Docker pipeline. Use when: building Docker images, running containerized tests, creating migration bundles, publishing to containers, or troubleshooting Dockerfile stages."
|
||||
argument-hint: "Describe what you want to build or publish (e.g., 'publish WebApplication1 as web app')"
|
||||
---
|
||||
# Docker Build Skill
|
||||
|
||||
## When to Use
|
||||
|
||||
- Build and run a .NET project in Docker
|
||||
- Run tests inside a container
|
||||
- Create a NuGet package via Docker
|
||||
- Create an EF Core migration bundle
|
||||
- Troubleshoot multi-stage Docker build issues
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Desktop or Docker Engine running
|
||||
- Repository root as build context
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Build and run a web application
|
||||
|
||||
```shell
|
||||
docker compose -f docker/compose.sample.yaml build sample-api \
|
||||
--build-arg PUBLISHED_PROJECT=<ProjectName>
|
||||
docker compose -f docker/compose.sample.yaml up sample-api
|
||||
```
|
||||
|
||||
### Build self-contained application
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile \
|
||||
--target final \
|
||||
--build-arg RUNTIME_BASE=self-contained \
|
||||
--build-arg PUBLISHED_PROJECT=<ProjectName> \
|
||||
-t myapp .
|
||||
```
|
||||
|
||||
### Run tests in container
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile --target test .
|
||||
```
|
||||
|
||||
### Lint OpenAPI documents
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile --target openapi-lint .
|
||||
```
|
||||
|
||||
### Pack NuGet packages
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile --target pack --output artifacts/nuget .
|
||||
```
|
||||
|
||||
### Create EF Core migration bundle
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile --target migrations \
|
||||
--build-arg PUBLISHED_PROJECT=<StartupProject> \
|
||||
--build-arg DATABASE_PROJECT=<EFProject> \
|
||||
--build-arg DBCONTEXT=<OptionalContextName> \
|
||||
-t migrations .
|
||||
```
|
||||
|
||||
## Stage Reference
|
||||
|
||||
See [Dockerfile](../../docker/Dockerfile) for the full multi-stage pipeline. Key stages and their targets:
|
||||
|
||||
| `--target` | Produces |
|
||||
|------------|----------|
|
||||
| `test` | Runs `dotnet test` — exits non-zero on failure |
|
||||
| `openapi-lint` | Spectral lint on generated OpenAPI JSON |
|
||||
| `publish` | Published app in `/app/publish` |
|
||||
| `pack` | NuGet `.nupkg` files in `/app/publish` |
|
||||
| `migration-bundle` | Standalone EF migration binary |
|
||||
| `final` | Production runtime image |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Restore failures**: Check `nuget.config` package sources and ensure `packages.lock.json` files are committed.
|
||||
- **GitVersion errors**: The `gitversion` stage needs `.git/` — ensure the build context includes it.
|
||||
- **Missing OpenAPI docs**: The `openapi-lint` stage only runs Spectral if `*.json` files exist in `artifacts/OpenApi/`.
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: new-library
|
||||
description: 'Scaffold a new reusable .NET library with correct naming, multi-targeting, and structure. Use when: creating a new library project, adding a reusable package, setting up a shared library under src/.'
|
||||
argument-hint: 'Brief description of the library purpose (e.g., "hashing utilities", "EF Core auditing")'
|
||||
---
|
||||
|
||||
# New Library
|
||||
|
||||
## When to Use
|
||||
|
||||
- Creating a new reusable, packable library under `src/`
|
||||
- Adding a shared component meant for NuGet distribution
|
||||
|
||||
## Naming Convention
|
||||
|
||||
Libraries use a `{Domain}.{Feature}` pattern. The `Kritikos.` root namespace prefix is applied automatically by `Directory.Build.props`.
|
||||
|
||||
| Domain prefix | When to use | Example |
|
||||
|---|---|---|
|
||||
| `AspNetCore.{Feature}` | Depends on `Microsoft.AspNetCore.App` | `AspNetCore.ProblemDetails` |
|
||||
| `Extensions.{Feature}` | Framework-agnostic, depends only on `Microsoft.Extensions.*` | `Extensions.Hashing` |
|
||||
| `EntityFrameworkCore.{Feature}` | Depends on EF Core | `EntityFrameworkCore.Auditing` |
|
||||
| *(no prefix)* | Pure .NET with no framework dependency | `Primitives` |
|
||||
|
||||
**Always propose 2–4 name options** to the user and allow a custom choice.
|
||||
|
||||
## Multi-Targeting
|
||||
|
||||
Target **both current LTS versions** plus optionally **one STS version** if newer than the latest LTS:
|
||||
|
||||
| Scenario | Targets | Rationale |
|
||||
|---|---|---|
|
||||
| .NET 10 is current LTS | `net8.0;net10.0` | Skip .NET 9 (STS, superseded) |
|
||||
| .NET 11 (STS) ships | `net8.0;net10.0;net11.0` | 11 > 10, include it |
|
||||
| .NET 12 (LTS) ships | `net10.0;net12.0` | .NET 8 drops; 11 superseded |
|
||||
|
||||
Libraries with **no framework dependency** (no domain prefix) should also target `netstandard2.0`/`netstandard2.1` when APIs and dependencies allow. Framework-dependent libraries skip .NET Standard.
|
||||
|
||||
## Procedure
|
||||
|
||||
1. Ask the user for the library's purpose.
|
||||
2. Propose name options using the naming table above.
|
||||
3. Determine the correct multi-targeting based on current LTS/STS and framework dependencies.
|
||||
4. Create the project under `src/{LibraryName}/`.
|
||||
5. Do **not** specify `Version` on `PackageReference` — add versions in `Directory.Packages.props`.
|
||||
6. Create a matching test project under `tests/{LibraryName}.Tests/`.
|
||||
7. Add both projects to `Solution.slnx`.
|
||||
8. Verify the build compiles cleanly.
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: new-web-api-project
|
||||
description: 'Scaffold a new ASP.NET web project (API or worker service) with correct structure, launch settings, and Docker integration. Use when: creating a new web API, adding an ASP.NET project, setting up a new web service under src/.'
|
||||
argument-hint: 'Brief description of the web project (e.g., "REST API for user management", "background worker for email processing")'
|
||||
---
|
||||
|
||||
# New Web Project
|
||||
|
||||
## When to Use
|
||||
|
||||
- Creating a new ASP.NET web API or worker service under `src/`
|
||||
- Adding a web project that will be deployed via Docker
|
||||
|
||||
## Procedure
|
||||
|
||||
1. Ask the user for the project's purpose and type (API or worker).
|
||||
2. Create the project under `src/{ProjectName}/` using the appropriate SDK (`Microsoft.NET.Sdk.Web` or `Microsoft.NET.Sdk.Worker`).
|
||||
4. **Single target framework** — web projects target only the current LTS (no multi-targeting).
|
||||
5. Create `Properties/launchSettings.json` with `http` and `https` profiles:
|
||||
- Pick ports that **do not conflict** with existing projects — check all `src/*/Properties/launchSettings.json` files first.
|
||||
- Set `launchBrowser: false`.
|
||||
- Set `ASPNETCORE_ENVIRONMENT: Development`.
|
||||
6. For APIs: use **Minimal APIs** with OpenAPI support (`Microsoft.AspNetCore.OpenApi`). The OpenAPI document generation and Spectral linting are handled automatically by the build infrastructure.
|
||||
7. Create a matching test project under `tests/{ProjectName}.Tests/`.
|
||||
8. Add both projects to `Solution.slnx`.
|
||||
9. Add a compose service entry to `compose.yaml` (or create one from `docker/compose.sample.yaml`):
|
||||
- Set `RUNTIME_BASE: web` for APIs, `RUNTIME_BASE: app` for workers.
|
||||
- Set `PUBLISHED_PROJECT` to the project name.
|
||||
- Build context is the repo root with `dockerfile: docker/Dockerfile`.
|
||||
10. Verify the build compiles cleanly.
|
||||
|
||||
## Launch Settings Template
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:{HTTP_PORT}",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:{HTTPS_PORT};http://localhost:{HTTP_PORT}",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user