modules/ai-guide/Write-AiGuide-Core.ps1

param(
    [string]   $ProjectName,
    [string]   $OrmMode,
    [string]   $DbProvider    = "MSSQL",
    [string]   $FrontendMode,
    [string[]] $Entities      = @("User", "Product"),
    [string]   $OutputPath,
    [bool]     $SkipTests     = $false,
    [bool]     $SkipCi        = $false,
    [bool]     $SkipFrontend  = $false,
    [bool]     $Observability = $false,
    [string]   $IdeConfig     = "VSCode",
    [bool]     $I18n          = $false
)

. (Join-Path (Split-Path $MyInvocation.MyCommand.Path) "..\core\Utils.ps1")

$guideDir = Join-Path $OutputPath "ai-guide"
function Write-Guide($fileName, $content) {
    Write-CoreFile (Join-Path $guideDir $fileName) $content
}

$nonAuthEntities = @($Entities | Where-Object { $_ -ne "User" })
$allEntitiesStr  = $Entities -join ", "

$ormShort = switch ($OrmMode) {
    "Dapper" { "Dapper (raw SQL, micro-ORM)" }
    "EFCore" { "EF Core 8 (Code-First, LINQ)" }
    "Hybrid" { "Hybrid - Yazma: Dapper | Okuma: EF Core" }
}

$dbNote = switch ($DbProvider) {
    "Postgres" { "PostgreSQL (Npgsql)" }
    "SQLite"   { "SQLite (dosya tabanli, lokal gelistirme)" }
    default    { "MS SQL Server" }
}

$dbConnectionNote = switch ($DbProvider) {
    "Postgres" { "Host=db;Port=5432;Database=${ProjectName}Db;Username=postgres;Password=postgres" }
    "SQLite"   { "Data Source=${ProjectName}.db" }
    default    { "Server=db;Database=${ProjectName}Db;User Id=sa;Password=YourStrong@Passw0rd;TrustServerCertificate=True" }
}

# ─── README.md ────────────────────────────────────────────
$feSection   = if ($SkipFrontend) { "Frontend: Yok (API-Only)" } else { "Frontend: $FrontendMode" }
$testSection = if ($SkipTests)    { "Test Katmani: Atlanmis (-SkipTests)" } else { "Test Katmani: xUnit + Moq + FluentAssertions" }
$ciSection   = if ($SkipCi)       { "CI/CD: Atlanmis (-SkipCi)" } else { "CI/CD: GitHub Actions (ci.yml + docker.yml)" }
$obsSection  = if ($Observability){ "Observability: Serilog + OpenTelemetry" } else { "Observability: Yok" }
$ideSection  = if ($IdeConfig -ne "None") { "IDE: $IdeConfig (launch.json + tasks.json hazir)" } else { "IDE: Yapilandirilmamis" }
$i18nSection = if ($I18n)         { "i18n: EN/TR (i18next)" } else { "i18n: Yok" }
$uiRow       = if (-not $SkipFrontend) { "| UI | http://localhost:3000 |`n" } else { "" }

Write-Guide "README.md" @"
# $ProjectName - AI Gelistirici Kilavuzu
 
Bu klasor, AI asistaniyla gelistirme yaparken uyulmasi gereken
kurallari, mimariyi ve yeni ozellik ekleme adimlarini aciklar.
 
---
 
## Proje Ozeti
 
| Alan | Deger |
|-------------------|--------------------------------------------|
| Proje | $ProjectName |
| ORM | $ormShort |
| Veritabani | $dbNote |
| $feSection | |
| Entityler | $allEntitiesStr |
| $testSection | |
| $ciSection | |
| $obsSection | |
| $ideSection | |
| $i18nSection | |
| Mimari | Clean Architecture |
| CQRS | MediatR 14 |
| Auth | JWT Bearer + BCrypt + Rol Tabanli Yetki |
| API Yanit | ApiResponse<T> wrapper (success/data/msg) |
| Sayfalama | PagedResult<T> + GET /paged endpoint |
| Soft Delete | IsDeleted + DeletedAt (fiziksel silme yok) |
| Unit of Work | IUnitOfWork (transaction yonetimi) |
 
---
 
## Klasor Yapisi
 
``````
ai-guide/
+-- README.md <- Bu dosya - baslangic noktasi
+-- architecture.md <- Katman sorumluluklari ve bagimlilik kurallari
+-- add-feature.md <- Yeni entity/ozellik ekleme adim adim rehber
+-- api-patterns.md <- ApiResponse, Pagination, Soft Delete, UoW ornekleri
+-- orm-guide.md <- ORM'e ozgu kod ornekleri
+-- rules.md <- Naming, validation, hata yonetimi kurallari
+-- devlog.md <- Mimari kararlar ve gelistirme gecmisi (AI icin baglam)
$(if (-not $SkipTests) { "+-- testing-guide.md <- Test yazma rehberi (Domain/Application/Integration)`n" })$(if (-not $SkipCi) { "+-- ci-cd.md <- GitHub Actions pipeline aciklamasi`n" })$(if ($Observability) { "+-- observability.md <- Serilog ve OpenTelemetry kullanim kilavuzu`n" })$(if (-not $SkipFrontend) { "+-- frontend-guide.md <- Frontend mimarisi ve React Query kullanim rehberi`n" })``````
 
---
 
## Hizli Baslangic
 
``````bash
docker-compose up --build
``````
 
| Servis | URL |
|---------|-----------------------------------------------|
| Swagger | http://localhost:8080/swagger |
| API | http://localhost:8080/api |
${uiRow}| DB | $dbConnectionNote |
 
Varsayilan kullanici: ``admin`` / ``Admin123!``
Varsayilan rol: ``Admin`` (JWT'de ``Role`` claim olarak gelir)
 
---
 
## Mevcut Entityler
 
$(foreach ($e in $Entities) { "- **$e** - CQRS handler, repository, controller, paged endpoint hazir`n" })
Yeni entity eklemek icin bkz. **add-feature.md**
 
---
 
## API Yanit Formati
 
Tum endpoint'ler ``ApiResponse<T>`` zarfiyla yanitlar:
 
``````json
{ "success": true, "message": null, "data": { ... } }
{ "success": false, "message": "Hata mesaji", "data": null }
``````
 
Sayfalama: ``GET /api/products/paged?page=1&size=20``
``````json
{ "success": true, "data": { "items": [...], "totalCount": 50, "page": 1, "size": 20 } }
``````
 
---
 
## En Onemli Kurallar (AI icin)
 
1. **Hicbir is mantigi WebApi katmaninda olmamali.** Controller sadece:
   ``HTTP istek -> _mediator.Send(...) -> Ok(ApiResponse<T>.Ok(sonuc))``
2. **Domain katmani dis bagimlilik almaz.** Application veya Persistence import etme.
3. **Validation: FluentValidation kullan.** Data Annotations kullanma.
4. **Controller'da try/catch yazma.** GlobalExceptionHandler tumu yakalar.
5. **Fiziksel silme yapma.** ``DeleteAsync`` soft delete uygular (``IsDeleted = true``).
6. **GetAllAsync yerine GetPagedAsync kullan** liste endpoint'lerinde.
7. **ORM: $OrmMode kurallarina uy.** Bkz. orm-guide.md
"@


# ─── architecture.md ──────────────────────────────────────
$ormArchNote = switch ($OrmMode) {
    "Dapper" { "Tum veri erisimi Dapper + raw SQL ile yapilir. EF Core ve AppDbContext YOKTUR." }
    "EFCore" { "Tum veri erisimi EF Core 8 ile yapilir. AppDbContext Code-First yonetilir." }
    "Hybrid" { "Yazma (Add/Update/Delete): Dapper | Okuma (GetAll/GetById/GetPaged): EF Core + AsNoTracking()" }
}

$dbContextSection = if ($OrmMode -ne "Dapper") { @"
 
## AppDbContext
 
``````
Persistence/
+-- Context/
    +-- AppDbContext.cs <- DbSet<Entity> + HasQueryFilter(soft delete) + HasData(seed)
``````
 
Yeni entity eklendiginde AppDbContext'e DbSet ve HasQueryFilter ekle:
``````csharp
public DbSet<Category> Categories => Set<Category>();
 
// OnModelCreating icinde:
builder.Entity<Category>().HasQueryFilter(e => !e.IsDeleted);
``````
"@
 } else { "" }

$migrationSection = if ($OrmMode -ne "Dapper") { @"
 
## EF Core Migration Akisi
 
Projede ``scripts/migrate.ps1`` (Windows) ve ``scripts/migrate.sh`` (Linux/Mac) hazir gelir:
 
``````powershell
# Yeni migration olustur
.\scripts\migrate.ps1 -MigrationName "AddOrderTable"
 
# Son migration'i geri al
.\scripts\migrate.ps1 -Revert
``````
 
Manuel calistirmak icin:
``````bash
dotnet ef migrations add <AciklamaciAd> \
  --project src/$ProjectName.Persistence \
  --startup-project src/$ProjectName.WebApi
 
dotnet ef database update \
  --project src/$ProjectName.Persistence \
  --startup-project src/$ProjectName.WebApi
``````
"@
 } else { "" }

Write-Guide "architecture.md" @"
# Mimari - Clean Architecture
 
## Katman Sorumluluklari
 
``````
$ProjectName.Domain
  Entities/ <- Sadece alan modeli - dis bagimlilik YASAK
                      BaseEntity: Id, CreatedAt, UpdatedAt, IsDeleted, DeletedAt
  Interfaces/ <- IRepository<T>, IUserRepository, IUnitOfWork imzalari
  Common/ <- PagedQuery, PagedResult<T>
 
$ProjectName.Application
  DTOs/ <- Veri transferi (C# record)
  Common/ <- ApiResponse<T> (Ok/Fail factory)
  Features/ <- CQRS: Commands/ ve Queries/ (MediatR handler'lar)
  Behaviors/ <- ValidationBehavior (pipeline - otomatik devreye girer)
  Interfaces/ <- ITokenService, IPasswordHasher
  Mappings/ <- AutoMapper profilleri (Entity <-> DTO)
 
$ProjectName.Infrastructure
  Auth/ <- JwtTokenService (Role claim dahil)
  Security/ <- BcryptPasswordHasher
 
$ProjectName.Persistence
  $(if ($OrmMode -ne "Dapper") { "Context/ <- AppDbContext (HasQueryFilter ile soft delete)" })
  Repositories/ <- IRepository<T> implementasyonlari (GetPagedAsync dahil)
  UnitOfWork/ <- UnitOfWork.cs (sadece EFCore/Hybrid modda)
  ServiceRegistration.cs
 
$ProjectName.WebApi
  Controllers/ <- SADECE HTTP + _mediator.Send() + ApiResponse<T>.Ok(...)
  Handlers/ <- GlobalExceptionHandler (IExceptionHandler - merkezi hata)
  Program.cs <- DI + Authorization policy + ExceptionHandler
``````
 
---
 
## Bagimlilik Kurali (Dependency Rule)
 
``````
WebApi --> Application, Infrastructure, Persistence
Persistence --> Domain, Application
Infrastructure --> Application
Application --> Domain
Domain --> (hicbir sey - saf)
``````
 
**Ust katman alt katmana referans verebilir. Alt katman ust katmana VEREMEZ.**
 
---
 
## HTTP Istek Yasam Dongusu
 
``````
HTTP Request
  -> GlobalExceptionHandler (try/catch BURADADIR - middleware)
  -> JWT Authentication (token + Role claim dogrulama)
  -> Authorization Policy (AdminOnly / UserOnly)
  -> Controller.Action()
  -> _mediator.Send(command/query)
  -> ValidationBehavior (FluentValidation - otomatik calisir)
  -> CommandHandler / QueryHandler
  -> IRepository (domain interface)
  -> Persistence Repository (gercek DB cagrisi)
  -> ApiResponse<T>.Ok(dto) (zarflama)
  -> HTTP 200
``````
 
---
 
## BaseEntity
 
Her entity ``BaseEntity``'den turetilir:
 
``````csharp
public abstract class BaseEntity {
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    public bool IsDeleted { get; set; } = false; // Soft Delete
    public DateTime? DeletedAt { get; set; } // Soft Delete tarihi
}
``````
 
---
 
## Soft Delete
 
``DeleteAsync`` fiziksel silme YAPMAZ:
 
``````csharp
public async Task DeleteAsync(int id) {
    var entity = await GetByIdAsync(id);
    if (entity != null) {
        entity.IsDeleted = true;
        entity.DeletedAt = DateTime.UtcNow;
        await _ctx.SaveChangesAsync();
    }
}
``````
 
EFCore/Hybrid modda global query filter silinmisleri otomatik gizler:
``````csharp
builder.Entity<Product>().HasQueryFilter(e => !e.IsDeleted);
// Artik GetAllAsync(), GetPagedAsync() sorgularinda IsDeleted=true kayitlar gelmez
``````
 
---
 
## IUnitOfWork
 
Coklu repository islemlerinde transaction icin:
 
``````csharp
public interface IUnitOfWork : IDisposable {
    Task<int> SaveChangesAsync(CancellationToken ct = default);
    Task BeginTransactionAsync();
    Task CommitTransactionAsync();
    Task RollbackTransactionAsync();
}
``````
 
Handler ornegi:
``````csharp
await _uow.BeginTransactionAsync();
try {
    await _productRepo.AddAsync(product);
    await _orderRepo.AddAsync(order);
    await _uow.CommitTransactionAsync();
} catch {
    await _uow.RollbackTransactionAsync();
    throw;
}
``````
 
---
 
## Rol Tabanli Yetkilendirme
 
JWT token ``Role`` claim iceriyor. Program.cs'de tanimli policy'ler:
 
``````csharp
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
options.AddPolicy("UserOnly", policy => policy.RequireRole("User", "Admin"));
``````
 
Controller kullanimi:
``````csharp
[Authorize(Policy = "AdminOnly")]
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id) { ... }
``````
 
---
 
## Veri Erisim Modu: $OrmMode
 
$ormArchNote
 
Veritabani: **$dbNote**
Connection string: ``$dbConnectionNote``
$dbContextSection
$migrationSection
"@


# ─── rules.md ─────────────────────────────────────────────
Write-Guide "rules.md" @"
# Yazim ve Gelistirme Kurallari
 
## 1. Naming (Isimlendirme)
- **Class/Method:** PascalCase (Orn: ``GetProductByIdQuery``)
- **Interface:** I ile baslayan PascalCase (Orn: ``IProductRepository``)
- **Variables:** camelCase (Orn: ``productName``)
- **DTOs:** Entity adindan sonra ``Dto`` (Orn: ``ProductDto``)
- **Commands:** ``Add{E}Command``, ``Update{E}Command``, ``Delete{E}Command``
- **Queries:** ``GetAll{E}sQuery``, ``GetPaged{E}sQuery``, ``Get{E}ByIdQuery``
 
## 2. Validation
- Tum validasyonlar **Application** katmaninda ``FluentValidation`` ile yapilir.
- Her Command icin bir ``{Command}Validator`` sinifi olmalidir.
- Domain katmaninda sadece basit self-check validasyonlari olabilir.
 
## 3. CQRS Kurallari
- **Commands:** Veriyi degistiren islemler. Handler icinde ``int`` (ID) veya ``Unit`` doner.
- **Queries:** Veriyi okuyan islemler. Handler icinde yalnizca DTO doner.
- Handler icinde yalnizca repository ve gerekli servisler enjekte edilmeli.
 
## 4. API Yanit Formati
- **Her controller action** ``ApiResponse<T>.Ok(data)`` ile sarmalanmalidir:
``````csharp
return Ok(ApiResponse<ProductDto>.Ok(dto));
return Ok(ApiResponse<object>.Fail("Urun bulunamadi."));
``````
- Hata durumunda ``GlobalExceptionHandler`` otomatik ``ApiResponse`` uretir.
 
## 5. Sayfalama
- Liste endpoint'lerinde daima paged endpoint kullan:
  ``GET /api/products/paged?page=1&size=20``
- ``GetPagedAsync(PagedQuery)`` tum repository'lerde mevcuttur.
- ``PagedResult<T>`` dondurmeli: ``Items``, ``TotalCount``, ``Page``, ``Size``.
 
## 6. Soft Delete
- Fiziksel silme (``DELETE FROM``) yapma. ``DeleteAsync`` soft delete uygular.
- Silinen kayitlara erisilmemesi icin EFCore global query filter kullan.
- Silinen kaydi geri getirmek gerekirse: ``IgnoreQueryFilters()`` ile sorgula.
 
## 7. Hata Yonetimi
- Is mantigi hatalari icin ozel exception firlat (Orn: ``NotFoundException``).
- ``GlobalExceptionHandler`` bu hatalari yakalar ve ProblemDetails formatinda yanitlar.
- Handler icinde ``try-catch`` kullanmaktan kacin.
- Controller'da ``try-catch`` YAZMAK YASAKTIR.
 
## 8. Yetkilendirme
- Hassas endpoint'lerde ``[Authorize(Policy = "AdminOnly")]`` kullan.
- Token'da ``Role`` claim mevcuttur: ``Admin`` veya ``User``.
- Yeni rol eklemek icin hem DB seed'ini hem JWT claim'ini guncelle.
"@


# ─── api-patterns.md ──────────────────────────────────────
$firstE = if ($nonAuthEntities.Count -gt 0) { $nonAuthEntities[0] } else { "Product" }
$firstPE = Get-Plural $firstE
$firstLowE = $firstE.ToLower()

Write-Guide "api-patterns.md" @"
# API Desenleri Kilavuzu
 
## ApiResponse<T> Wrapper
 
Tum API yanitlari bu zarfa sarmalanir:
 
``````csharp
// Application/Common/ApiResponse.cs
public class ApiResponse<T> {
    public bool Success { get; set; }
    public string? Message { get; set; }
    public T? Data { get; set; }
    public static ApiResponse<T> Ok(T data, string? msg = null) => new() { Success = true, Data = data, Message = msg };
    public static ApiResponse<T> Fail(string msg) => new() { Success = false, Message = msg };
}
``````
 
Controller kullanimi:
``````csharp
[HttpGet]
public async Task<IActionResult> GetAll() {
    var result = await _mediator.Send(new GetAll${firstE}sQuery());
    return Ok(ApiResponse<IEnumerable<${firstE}Dto>>.Ok(result));
}
 
[HttpPost]
public async Task<IActionResult> Add([FromBody] Add${firstE}Command cmd) {
    var id = await _mediator.Send(cmd);
    return Ok(ApiResponse<int>.Ok(id, "${firstE} basariyla eklendi."));
}
``````
 
---
 
## Sayfalama (Pagination)
 
### Domain Tipleri
 
``````csharp
// Domain/Common/PagedQuery.cs
public class PagedQuery {
    public int Page { get; set; } = 1;
    public int Size { get; set; } = 20;
    public int Skip => (Page - 1) * Size;
}
 
// Domain/Common/PagedResult.cs
public class PagedResult<T> {
    public IEnumerable<T> Items { get; set; } = [];
    public int TotalCount { get; set; }
    public int Page { get; set; }
    public int Size { get; set; }
    public int TotalPages => (int)Math.Ceiling((double)TotalCount / Size);
    public bool HasNextPage => Page < TotalPages;
}
``````
 
### CQRS Query Ornegi
 
``````csharp
// Features/${firstE}s/Queries/GetPaged${firstE}s/GetPaged${firstE}sQuery.cs
public record GetPaged${firstE}sQuery(int Page, int Size) : IRequest<PagedResult<${firstE}Dto>>;
 
// Handler:
public async Task<PagedResult<${firstE}Dto>> Handle(GetPaged${firstE}sQuery request, CancellationToken ct) {
    var query = new PagedQuery { Page = request.Page, Size = request.Size };
    var result = await _repo.GetPagedAsync(query);
    return new PagedResult<${firstE}Dto> {
        Items = _mapper.Map<IEnumerable<${firstE}Dto>>(result.Items),
        TotalCount = result.TotalCount,
        Page = result.Page,
        Size = result.Size,
    };
}
``````
 
### Controller Endpoint
 
``````csharp
[HttpGet("paged")]
public async Task<IActionResult> GetPaged([FromQuery] int page = 1, [FromQuery] int size = 20) {
    var result = await _mediator.Send(new GetPaged${firstE}sQuery(page, size));
    return Ok(ApiResponse<PagedResult<${firstE}Dto>>.Ok(result));
}
``````
 
### Ornek Yanit
 
``````json
GET /api/${firstLowE}s/paged?page=2&size=10
 
{
  "success": true,
  "message": null,
  "data": {
    "items": [ { "id": 11, "name": "...", "createdAt": "..." } ],
    "totalCount": 47,
    "page": 2,
    "size": 10,
    "totalPages": 5,
    "hasNextPage": true
  }
}
``````
 
---
 
## Soft Delete
 
``DeleteAsync`` cagrildiginda kayit fiziksel olarak silinmez:
 
``````csharp
// Silme
await _repo.DeleteAsync(id);
// Sonuc: IsDeleted=true, DeletedAt=2026-05-12T...
 
// Normal sorgular silinen kayitlari getirmez (global filter)
var all = await _repo.GetAllAsync(); // IsDeleted=true olanlari gormez
 
// Silinen kayitlara erismek gerekirse (sadece Admin operasyonlari):
var withDeleted = await _ctx.${firstPE}.IgnoreQueryFilters().ToListAsync();
``````
 
---
 
## Unit of Work
 
Birden fazla repository uzerinde atomik islem:
 
``````csharp
public class TransferCommandHandler : IRequestHandler<TransferCommand, Unit> {
    private readonly I${firstE}Repository _repo;
    private readonly IUnitOfWork _uow;
 
    public async Task<Unit> Handle(TransferCommand request, CancellationToken ct) {
        await _uow.BeginTransactionAsync();
        try {
            // Birden fazla degisiklik
            var item = await _repo.GetByIdAsync(request.Id);
            item!.Name = request.NewName;
            await _uow.SaveChangesAsync(ct);
            await _uow.CommitTransactionAsync();
            return Unit.Value;
        } catch {
            await _uow.RollbackTransactionAsync();
            throw;
        }
    }
}
``````
 
---
 
## GlobalExceptionHandler
 
Manuel try/catch yazma — handler otomatik devreye girer:
 
``````csharp
// WebApi/Handlers/GlobalExceptionHandler.cs
// ValidationException -> HTTP 400 + validation hatalar listesi
// UnauthorizedAccessException -> HTTP 401
// KeyNotFoundException -> HTTP 404
// Diger exception'lar -> HTTP 500
 
// Yanit formati (ProblemDetails):
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Validation failed",
  "status": 400,
  "errors": { "Name": ["Name bos olamaz."] }
}
``````
 
---
 
## Health Check
 
``````bash
GET /health
# 200 OK - { "status": "Healthy", "results": { "database": { "status": "Healthy" } } }
``````
"@


# ─── devlog.md ────────────────────────────────────────────
$devlogDate    = (Get-Date -Format "yyyy-MM-dd")
$featureFlags  = @()
if (-not $SkipTests)    { $featureFlags += "xUnit + Moq + FluentAssertions test altyapisi" }
if (-not $SkipCi)       { $featureFlags += "GitHub Actions CI/CD (ci.yml + docker.yml)" }
if ($Observability)     { $featureFlags += "Serilog + OpenTelemetry observability stack" }
if (-not $SkipFrontend) { $featureFlags += "$FrontendMode frontend (React Query, PrivateRoute, auth flow)" }
if ($I18n)              { $featureFlags += "i18n EN/TR dil destegi (i18next + LanguageSwitcher)" }
$featureFlagsStr = if ($featureFlags.Count -gt 0) { ($featureFlags | ForEach-Object { "- $_" }) -join "`n" } else { "- Ek ozellik secilmedi" }

$ormDecision = switch ($OrmMode) {
    "Dapper" { "Ham SQL kontrolu ve performans onceligi nedeniyle Dapper tercih edildi. EF Core bagimliligini minimize eder." }
    "EFCore" { "Kod-oncelikli migration, LINQ sorgu kolayligi ve global query filter (soft delete) icin EF Core 8 tercih edildi." }
    "Hybrid" { "Yazma islemleri Dapper ile (INSERT performansi), okuma islemleri EF Core ile (LINQ + global filter). En iyi iki dunya." }
}

$dbDecision = switch ($DbProvider) {
    "Postgres" { "PostgreSQL: Acik kaynak, JSON destegi ve gelismis sorgu planlayicisi nedeniyle tercih edildi." }
    "SQLite"   { "SQLite: Lokal gelistirme ve CI ortamlari icin ek sunucu gerektirmeden calisir." }
    default    { "MS SQL Server: Kurumsal ortam gereksinimleri ve mevcut altyapi ile uyum nedeniyle tercih edildi." }
}

Write-Guide "devlog.md" @"
# Dev Log - $ProjectName
 
Bu dosya, projedeki mimari kararlari, ozellik eklemelerini ve
degisikliklerin nedenlerini kronolojik olarak kaydeder.
 
AI asistan olarak bu dosyayi okuyarak:
- Gecmiste neden bu kararin alindigi
- Hangi alternatiflerin degerlendirildigi
- Mevcut yapiyla nasil tutarli kalinacagi
 
hakkinda baglamsal bilgi edinebilirsin.
 
---
 
## Yeni Giris Sablonu
 
Yeni bir ozellik veya karar eklendiginde asagidaki formati kullan:
 
``````
## [YYYY-AA-GG] <Kisa baslik>
**Neden:** <Motivasyon - problem ne idi, neden bu yapildi>
**Nasil:** <Yaklasim - hangi pattern/teknik kullanildi>
**Karar:** <Net karar ifadesi - baska bir AI okudugunda ne yapacagini bilmeli>
**Etkilenen:** <Degistirilen/eklenen dosyalar veya katmanlar>
``````
 
---
 
## [$devlogDate] Proje Olusturuldu - CleanArchitectureGenerator v1.4.0
 
**Neden:** $ProjectName projesi Clean Architecture prensipleriyle sifirdan kuruldu.
Bakimi kolay, test edilebilir ve buyuyebilir bir yapi hedeflendi.
 
**Nasil:** CleanArchitectureGenerator ile otomatik iskelet olusturuldu.
Tum katmanlar, bagimliliklar ve cross-cutting concerns basta tanimlanarak
manuel tekrar kodlamadan kacinildi.
 
**Karar:**
- ORM: $OrmMode — $ormDecision
- Veritabani: $dbNote — $dbDecision
- CQRS: MediatR ile komut/sorgu ayrimi; handler'lar ince, controller'lar saf HTTP
- Validasyon: FluentValidation pipeline behavior — controller'larda try/catch yok
- Hata yonetimi: GlobalExceptionHandler merkezi — handler'larda try/catch yok
- Auth: JWT Bearer + BCrypt + rol tabanli policy (AdminOnly / UserOnly)
- Silme: Soft delete zorunlu — fiziksel DELETE hic kullanilmiyor
- Sayfalama: Tum liste endpoint'leri /paged ile basliyor — GetAll sadece ic kullanim
 
**Ek ozellikler:**
$featureFlagsStr
 
**Etkilenen:** Tum proje altyapisi (Domain / Application / Infrastructure / Persistence / WebApi$(if (-not $SkipFrontend) { " / Frontend" }))
 
---
 
## Nasil Giris Eklenir?
 
1. Yeni bir entity, ozellik veya mimari karar aldiysan bu dosyaya ekle.
2. Tarih formatini koru: ``[YYYY-AA-GG]``
3. **Neden** kismini atlama — bu, AI icin en degerli kisimdir.
4. Kararlar kalici; eski girisler silinmez, uzerine yeni giris eklenir.
 
Ornek:
 
``````markdown
## [2026-06-01] Order entity eklendi
**Neden:** Satis modulu gereksinimi; urun-siparis iliskisi kurulmasi gerekiyordu.
**Nasil:** add-feature.md rehberi izlenerek 9 adimda eklendi.
  IOrderRepository -> OrderRepository -> AddOrderCommand -> OrdersController
**Karar:** Order-Product arasinda navigation property yerine ID referansi kullanildi.
  Performans: gereksiz Include() sorgularini engeller.
**Etkilenen:** Domain/Entities/Order.cs, Persistence/Repositories/OrderRepository.cs,
  Application/Features/Orders/**, WebApi/Controllers/OrdersController.cs,
  Persistence/Context/AppDbContext.cs (DbSet + HasQueryFilter + migration)
``````
"@