Låt AI extrahera reglerna ur din kod och skapa instruktionsfiler som håller projektet konsekvent — oavsett vem som kodar eller vilken fil som öppnas.
En välskriven instruktionsfil är ett kontrakt: den berättar för AI exakt vad som gäller i detta projekt, för denna typ av fil. När Copilot genererar kod kommer den att följa dessa regler — precis som en erfaren kollega som läst den tekniska specifikationen.
Det viktiga är att reglerna är projektspecifika, inte generella. "Följ SOLID" är inte en bra regel i en instruktionsfil — det vet AI redan. "Returnera alltid Result<T>, aldrig null, aldrig exception" är en bra regel.
| Fil | applyTo | Täcker |
|---|---|---|
copilot-instructions.md |
Alla filer (automatisk) | Stack, namnkonventioner, globala förbud |
domain.instructions.md |
src/Domain/**/*.cs |
AggregateRoot-mönster, Value Objects, domänhändelser, Result-typ |
application.instructions.md |
src/Application/**/*.cs |
Command/Query-struktur, MediatR-handlers, validering |
api.instructions.md |
src/Api/**/*.cs |
Minimal API-mönster, HTTP-felhantering, versionshantering |
tests.instructions.md |
tests/**/*.cs |
xUnit-mönster, NSubstitute-användning, AAA-struktur, namnkonvention |
infrastructure.instructions.md |
src/Infrastructure/**/*.cs |
EF Core-konfiguration, migrationer, repository-implementation |
# Kör med Claude Sonnet 4.6 eller GPT-5.4 för bäst resultat
Du är en senior C#-arkitekt. Analysera dessa referensimplementationer:
#file:src/Domain/Common/AggregateRoot.cs
#file:src/Domain/Common/Result.cs
#file:src/Domain/Orders/Order.cs
#file:src/Domain/Orders/OrderItem.cs
#file:src/Domain/Orders/Events/OrderPlacedEvent.cs
#file:tests/Domain/OrderTests.cs
Generera en .instructions.md-fil med frontmatter:
---
applyTo: "src/Domain/**/*.cs"
---
KRAV på filens innehåll:
1. Extrahera BARA regler som explicit framgår av koden — inget generellt
2. Skriv varje regel som en imperativ mening ("Returnera alltid...", "Använd aldrig...")
3. Täck: basklassanvändning, namnkonventioner, felhanteringskontrakt,
händelsehantering, Value Object-mönster, factory-metoder
4. Max 35 regler, grupperade under beskrivande rubriker
5. Inkludera ett minimalt C#-kodexempel per rubrik som visar rätt mönster
Avsluta med en sektion "Förbjudna mönster" med 5-7 negativa regler.
---
applyTo: "src/Domain/**/*.cs"
---
# Domänlager — Instruktioner
## Aggregat
- Alla aggregat ärver från `AggregateRoot<TId>` i `MyApp.Domain.Common`
- Använd `Guid` som TId om inte domänkravet specificerar annat
- Konstruktorer är alltid `private`; exponera skapande via statisk `Create()`-metod
- Registrera domänhändelser med `AddDomainEvent()` — publicera aldrig direkt
```csharp
// Rätt mönster
public sealed class Order : AggregateRoot<OrderId>
{
private Order() { }
public static Result<Order> Create(CustomerId customerId, Address shippingAddress)
{
// validering
var order = new Order { Id = OrderId.New() };
order.AddDomainEvent(new OrderCreatedEvent(order.Id));
return Result<Order>.Success(order);
}
}
```
## Felhantering
- Returnera alltid `Result<T>` från public domänmetoder — aldrig `null`, aldrig exception
- Använd `DomainError` med en semantisk felkod (t.ex. `"Order.InvalidStatus"`)
- Kasta `InvalidOperationException` BARA vid programmeringsfel, aldrig vid affärsbegränsningar
## Value Objects
- Implementera som `sealed record` med privat konstruktor
- `Create()`-metoden validerar och returnerar `Result<T>`
- Exponera aldrig råvärdet som primitiv — använd den semantiska typen
```csharp
public sealed record EmailAddress
{
public string Value { get; }
private EmailAddress(string value) => Value = value;
public static Result<EmailAddress> Create(string? raw)
{
if (string.IsNullOrWhiteSpace(raw)) return Result<EmailAddress>.Failure(
new DomainError("Email.Empty", "E-postadress får inte vara tom"));
if (!raw.Contains('@')) return Result<EmailAddress>.Failure(
new DomainError("Email.InvalidFormat", "Ogiltig e-postadress"));
return Result<EmailAddress>.Success(new EmailAddress(raw.Trim().ToLowerInvariant()));
}
}
```
## Domänhändelser
- Namnge händelser i past tense: `OrderPlacedEvent`, `OrderCancelledEvent`
- Implementera som `sealed record` med `IDomainEvent`
- Inkludera alltid aggregatets Id och tidsstämpel
## Namnkonventioner
- Aggregat: singular substantiv i PascalCase (`Order`, `Customer`, `Shipment`)
- Commands: verb + substantiv + "Command" (`PlaceOrderCommand`)
- Events: verb i past tense + "Event" (`OrderPlacedEvent`)
- Value Objects: beskrivande substantiv (`EmailAddress`, `Money`, `Address`)
## Förbjudna mönster
- Använd ALDRIG `DbContext` eller infrastrukturbibliotek i domänlagret
- Kasta ALDRIG `ArgumentException` från domänmetoder — returnera `Result.Failure`
- Ange ALDRIG ett statefullt beroende (service etc.) direkt på ett aggregat
- Skapa ALDRIG aggregat med `new` utanför dess `Create()`-metod
- Exponera ALDRIG `List<T>` — använd alltid `IReadOnlyList<T>`
Instruktionsfiler är levande dokument. Uppdatera dem när:
# Bra commit-meddelanden för instruktionsfiler
git commit -m "chore(instructions): add rule for Result<T> on public domain methods"
git commit -m "chore(instructions): prohibit DbContext in domain layer"
git commit -m "chore(instructions): add Value Object pattern with code example"
git commit -m "chore(instructions): update test naming convention to MethodName_Scenario_Expected"
Lös övningarna självständigt. Det finns inget facit — lärandet sker i processen.
tests.instructions.md med applyTo: "tests/**/*.cs". Inkludera: namnkonvention, AAA-struktur, NSubstitute-regler och FluentAssertions-krav. Verifiera att Copilot följer filens regler när du genererar tester för en befintlig klass.
.instructions.md-filer med applyTo plus en copilot-instructions.md. Verifiera varje fil genom att: (a) ta bort instruktionsfilen, (b) generera en klass, (c) notera vad som är fel, (d) lägg tillbaka filen och generera igen. Dokumentera skillnaden.
.prompt.md-fil vars syfte är att uppdatera en befintlig instruktionsfil baserat på ny kod. Prompten ska ta en ny C#-klass som input och identifiera vilka regler i instruktionsfilen som behöver läggas till eller uppdateras. Testa den på tre olika nya klasser.
← Föregående: Arkitekturgrund Nästa: AI-driven Code Review →