Kurumsal izin (leave) talep ve onay sistemi. CQRS ve Domain-Driven Design prensipleriyle yazılmış bir .NET 8 backend, JWT tabanlı rol yönetimi ve React ile geliştirilmiş bir arayüzden oluşuyor.
İzin talebi oluşturma, iki aşamalı onay akışı (Manager → HR) ve buna bağlı izin bakiyesi takibini uçtan uca modelliyor.
- CQRS: Yazma (command) ve okuma (query) tarafları ayrı modeller
üzerinden çalışıyor. Onay bekleyen taleplerin listelendiği ekran, yazma
modelinden bağımsız, denormalize bir MongoDB koleksiyonundan (
pending_approvals_view) okunuyor. - DDD: İş kuralları (bakiye kontrolü, tarih çakışması, onay durum makinesi) domain katmanında, aggregate sınırları içinde uygulanıyor.
- JWT tabanlı kimlik doğrulama: Employee / Manager / HR rolleri, her
rolün görebileceği ve yapabileceği işlemler
[Authorize(Roles = ...)]ile API seviyesinde kısıtlanıyor. Hiçbir endpoint istemciden gelen bir kullanıcı/manager id'sine güvenmiyor — kimlik her zaman token'daki claim'lerden okunuyor. - Domain event'leri ile read model senkronizasyonu: Bir izin talebi onaylandığında/reddedildiğinde/iptal edildiğinde, ilgili event handler'lar hem read model'i günceller hem de (HR onayında) çalışanın izin bakiyesini düşürür.
| Katman | Teknoloji |
|---|---|
| Backend | .NET 8, MediatR, FluentValidation |
| Kimlik doğrulama | JWT (Microsoft.AspNetCore.Authentication.JwtBearer), ASP.NET Core Identity'nin PasswordHasher'ı |
| Veritabanı | MongoDB (MongoDB.Driver) |
| Frontend | React (Vite), plain CSS |
| Test | xUnit, FluentAssertions |
LeaveTrack/
├── Domain/ # Framework'ten bağımsız iş kuralları
│ ├── Common/ # AggregateRoot, Entity, ValueObject, IDomainEvent
│ ├── LeaveRequests/ # LeaveRequest aggregate + durum makinesi + event'ler
│ ├── Employees/ # Employee aggregate, EmployeeRole, LeaveBalance
│ └── Exceptions/ # DomainException hiyerarşisi
├── Application/ # Use case orkestrasyonu (CQRS burada)
│ ├── Auth/ # Login command
│ ├── Employees/ # Kayıt (CreateEmployee) ve manager sorgusu
│ ├── LeaveRequests/ # Talep oluşturma, onay/red/iptal command'leri, pending query
│ └── Common/ # Repository/servis interface'leri, MediatR pipeline behavior
├── Infrastructure/ # Dış dünya bağlantıları
│ ├── Auth/ # JWT üretimi, şifre hash'leme
│ ├── Persistence/ # MongoDbContext, repository'ler, read model'ler
│ └── EventHandlers/ # Domain event'lerini read model'e/bakiyeye yansıtan handler'lar
├── API/ # ASP.NET Core — controller'lar, middleware, JWT yapılandırması
├── frontend/ # React — giriş/kayıt ekranı, rol bazlı paneller
└── Tests/ # Domain aggregate'i için xUnit testleri
- .NET 8 SDK
- Node.js (LTS)
- MongoDB (native kurulum veya Docker:
docker run -d -p 27017:27017 --name leavetrack-mongo mongo:7)
cd API
dotnet restore
dotnet user-secrets init
dotnet user-secrets set "Jwt:Secret" "<32+ karakterlik rastgele bir metin>"
dotnet runappsettings.json içinde Jwt:Secret kasıtlı olarak boş bırakıldı — gerçek
değer git'e hiç girmesin diye .NET User Secrets
mekanizmasıyla, proje klasörünün dışında bir yerde tutuluyor. dotnet user-secrets set komutunu çalıştırmadan API başlamaz, açık bir hata
mesajıyla ne yapman gerektiğini söyler.
Swagger arayüzü https://localhost:<port>/swagger adresinde açılır
(port her çalıştırmada değişebilir, konsol çıktısında görünür).
cd frontend
npm install
npm run devsrc/api/leaveRequestsApi.js dosyasındaki BASE_URL değerini backend'in
gerçek portuyla güncelleyin.
http://localhost:5173 adresinde açılır. Sistemde henüz hiç hesap yokken
ilk kayıt HR rolüyle yapılmalı (bootstrap istisnası) — sonrasında
Manager/HR hesapları yalnızca giriş yapmış bir HR kullanıcısı tarafından
(HR panelindeki "New staff account" ile) oluşturulabilir, Employee hesapları
ise her zaman serbestçe kayıt olabilir.
- "New account" sekmesinden rol olarak HR seçip ilk hesabı oluştur.
- HR olarak giriş yap, panelindeki "New staff account" ile bir Manager hesabı oluştur (bir departman seç).
- "New account" sekmesinden rol olarak Employee seç, aynı departmanı seç — dropdown'da az önce oluşturduğun manager'ı göreceksin.
Bu adımları her test döngüsünde tekrar tekrar tıklamak yerine,
scripts/seed-demo-data.ps1 (PowerShell) bu üç hesabı tek komutla
oluşturur:
.\scripts\seed-demo-data.ps1 -ApiUrl https://localhost:<port>/api| Metot | Yol | Yetki | Açıklama |
|---|---|---|---|
| POST | /api/auth/login |
— | Giriş yapar, JWT döner |
| POST | /api/employees |
— | Kayıt (yeni employee/manager/HR hesabı) |
| GET | /api/employees/managers?department=X |
— | Departmandaki manager'ları listeler |
| POST | /api/leave-requests |
Herhangi bir rol | İzin talebi oluşturur |
| GET | /api/leave-requests/pending/manager |
Manager | Manager'ın onay bekleyen talepleri |
| GET | /api/leave-requests/pending/hr |
Hr | HR'ın onay bekleyen talepleri |
| POST | /api/leave-requests/{id}/approve-by-manager |
Manager | İlk aşama onayı |
| POST | /api/leave-requests/{id}/approve-by-hr |
Hr | Son onay, bakiyeyi düşürür |
| POST | /api/leave-requests/{id}/reject |
Manager, Hr | Talebi reddeder |
| POST | /api/leave-requests/{id}/cancel |
Herhangi bir rol | Kendi talebini iptal eder |