Skip to main content
Controller’lar incedir (thin): iş mantığı taşımazlar, yalnızca isteği bir MediatR komut/query’sine çevirip _mediator.Send(...) çağırırlar. Tüm validasyon, yetkilendirme ve iş kuralları Application katmanındaki pipeline behavior’lar ve handler’lar tarafından işlenir.

Base controller’lar

İki ortak taban sınıf vardır (src/DiyanetCleanArchitecture.API/SeedWork/Controllers/): Her ikisi de [ApiController] + [EnableCors(...)] taşır ama auth attribute’u kasten içermez.
Auth attribute’u yalnızca derived controller’da, tek satırda yazılır. Base’e [Authorize(Schemes=Personel)] + derived’a [Authorize(Schemes=Personel, Roles=...)] koymak, ASP.NET’in policy merge davranışı yüzünden 403’e yol açar (combined policy beklenen claim’leri göremez). Doğru kullanım:

Üç rota grubu

api/website/public/* hem website hem backoffice origin’ine açıktır — admin panelindeki form dropdown’ları (il/ilçe lookup gibi) public veriye erişebilsin diye. Named policy’ler Program.cs’te tanımlıdır:
  • AuthPolicies.PersonelAuthenticatedPersonelScheme + RequireAuthenticatedUser()
  • AuthPolicies.VatandasAuthenticatedVatandasScheme + RequireAuthenticatedUser()
  • AuthPolicies.AnyKeycloakAuthenticated → her iki scheme + RequireAuthenticatedUser()
Bare [Authorize(Schemes=X)] boş-requirement’lı bir policy üretir ve AuthorizationMiddleware’de 403’e düşebilir. Bu yüzden “sadece authenticated olsun yeter” senaryolarında named policy (RequireAuthenticatedUser()) kullanılır. DynamicPermissionPolicyProvider bu policy’leri ActiveAccountRequirement ile augment eder — yani Pending/Banned/Suspended kullanıcılar geçemez (gerekirse action’a [AllowPendingAccount] eklenir).

Gerçek örnek: MeController (Admin)

src/DiyanetCleanArchitecture.API/Controllers/Admin/MeController.cs:
GET /api/admin/me → tam profil (frontend login sonrası bir kez çağırır). GET /api/admin/me/status → sadece hesap durumu; full /me 403 alırsa frontend “Onay bekliyor” ekranı için bunu okur.

Controller listesi

Admin (api/admin/*)Users, Citizens, Roles, Announcements, Centers, Faqs, Locations, BagisBasvurular (+ BagisBasvuruPlanlari), EtkinlikBasvurular (+ EtkinlikBasvuruPlanlari), AdminNotifications, AdminSupportTickets, LegalDocuments, Me. Website auth (api/website/*)Me, Users, BagisBasvurular, EtkinlikBasvurular, LegalDocuments. Website public (api/website/public/*)Announcements, Centers, Faqs, Locations, Enums, BagisBasvuruPlanlari, EtkinlikBasvuruPlanlari. GenelAuthController (api/auth — login/refresh/logout/OTP/TOTP/OAuth), SiteSettingsController.

ResponseWrapper zarfı

Başarılı yanıtlar ResponseWrapper<TResponse> ile sarılır:
Controller, result.IsSuccess üzerinden Ok(result) veya BadRequest(result) döner.

Hata yanıtları — RFC 7807 ProblemDetails

Exception’lar Hellang.Middleware.ProblemDetails ile yakalanıp application/problem+json olarak döndürülür (SeedWork/ProblemDetails/ProblemDetailsOptionsConfiguration.cs): Her yanıta traceId extension’ı eklenir (Activity.Current?.Id ?? ctx.TraceIdentifier) — destek/log korelasyonu için tek bağlantı noktasıdır.
IncludeExceptionDetails her ortamda false olarak ayarlıdır (dev dahil). Stack trace, dosya yolları, iç class isimleri yanıta eklenmez — bilgi sızıntısını önler. Tam exception zaten Serilog’a yazılır; geliştirici client’tan gelen traceId ile log’da arar (“client’a minimal, log’a tam”).
Örnek 422 yanıtı:

Sonraki adımlar

API genel bakış

Pipeline sırası ve servis kayıtları.

OpenAPI / Swagger

NSwag, security scheme’ler, client üretimi.

Frontend SPA'lar

axios interceptor RFC 7807 hatalarını nasıl işler.

Keycloak

Çift realm, scheme’ler, claim’ler.