Departman ve İzin Sistemi
Departman Hiyerarşisi
Departmanlar self-referential (kendi kendine bağlı) bir ağaç yapısı oluşturur. Her departmanın parentId alanı boşsa o departman kök (root) demektir.
Okul (root)
├── Öğretmenler
│ ├── Matematik Öğretmenleri
│ └── Fen Öğretmenleri
└── Öğrenciler
├── 9. Sınıf
└── 10. Sınıf
Departments Tablosu
| Alan | Açıklama |
|---|---|
parentId |
Üst departman ID'si. null ise kök departman. |
isDefault |
Varsayılan departman mı? |
isLocked |
true ise sistem yönetici departmanı — silinmesi veya değiştirilmesi tehlikelidir |
color |
Arayüzde görüntüleme rengi |
Frontend'e Aktarım
Departmanlar tüm ağaç tek seferde gönderilmez. Sayfa açıldığında yalnızca kök departmanlar (parentId = null) yüklenir. Bir departmanın altı açılmak istendiğinde parentId parametresiyle o seviye istenir. Her departman kaydına hasChildren ve childrenCount alanları eklenir — bu sayede frontend ok/ikonu gösterebilir.
Alt Departman Çözümü
Sistemin birçok yerinde bir departmana işlem yapılırken tüm alt departmanlar da dahil edilir. Bu işlem için iki farklı implementasyon var:
src/utils/department.utils.js — getDepartmentAndChildrenIds()
BFS yaklaşımı. Bir kuyruk (departmentsToProcess) tutarak her adımda bir departmanın çocuklarını sorgular, yeni bulunanları kuyruğa ekler. Tekrar ziyareti önlemek için allDepartmentIds listesiyle kontrol yapılır.
// Örnek: "Öğrenciler" ve altındaki tüm sınıfları getir
const ids = await getDepartmentAndChildrenIds('dept_ogrenciler');
// → ['dept_ogrenciler', 'dept_9sinif', 'dept_10sinif']
Aynı mantık bazı modüllerin servis dosyalarında da yerel olarak tekrar yazılmıştır (wacademic, wreport, time-tracking). Temel davranış aynıdır.
İzin Sistemi
İzinler departman bazında atanır, kullanıcı bazında değil. Bir kullanıcının yetkisi, bağlı olduğu departmanın yetkilerinden gelir.
Veri Yapısı
permission → İzin tanımı (key + name)
↑
DepartmentPermission → Departman-izin bağlantısı
↑
Department → Departman
↑
User.departmentId → Kullanıcı
permission tablosunda sistem genelindeki tüm izin tanımları (permission.json dosyasından seed edilenler) saklanır. DepartmentPermissions ise hangi departmanın hangi izinlere sahip olduğunu tutar (departmentId + permissionId composite primary key).
Token'a Yükleme
Kullanıcı giriş yaptığında auth.service.js:
DepartmentPermissionstablosundan kullanıcının departmanına ait tüm izinler çekilir- JWT token içine
permissions: [...]array olarak yazılır - Token 1 gün geçerlidir
// Token payload'ı:
{
id: user.id,
isSuperAdmin: user.isSuperAdmin,
department: { id, name, color, parentId },
permissions: ['departman_list', 'user_add', ...],
...
}
Middleware Kontrolü
src/middlewares/authentication.js her korumalı route'da çalışır:
const authMiddleware = (permissions) => (req, res, next) => {
const { isSuperAdmin, permissions: userPerms } = decodeToken(token);
// isSuperAdmin ise tüm izin kontrolleri atlanır
if (!isSuperAdmin && permissions?.length > 0) {
const hasPermission = userPerms.some(p => permissions.includes(p));
if (!hasPermission) return res.status(403).json({ message: "Bu işlemi yapmaya yetkiniz yok..." });
}
req.user = decodeToken; // Tüm servis dosyalarına `req.user` üzerinden ulaşılır
next();
};
Route dosyalarında kullanımı:
router.get('/', authMiddleware(['departman_list']), controller.list);
router.post('/', authMiddleware(['departman_add']), controller.create);
isSuperAdmin Bayrağı
isSuperAdmin: true olan kullanıcı için middleware tüm izin kontrollerini atlar. Sistem genelindeki tüm kısıtlamalar geçersiz olur:
- Yetki kontrolleri
- Departmana özel görünürlük filtreleri
- Admin görünümleri (liderboard, rapor vb.)
Bu bayrak user tablosundaki isSuperAdmin alanından gelir ve login sırasında token'a yazılır.
İzin Güncelleme
Bir departmanın izinleri PUT /departments/:id/permissions endpoint'i üzerinden güncellenir. Yeni izin listesi gönderildiğinde:
- Mevcut tüm
DepartmentPermissionskayıtları silinir - Yeni liste toplu olarak eklenir
İzin değişikliği mevcut oturumları etkilemez — değişiklik yalnızca sonraki login'de token'a yansır.
Önemli Notlar
- Bir kullanıcının izinleri runtime'da veritabanından sorgulanmaz — token içindeki
permissionsarray'i kullanılır. Token süresi dolana kadar (1 gün) eski izinler geçerli kalabilir. - Alt departmanlar üst departmanın izinlerini otomatik olarak devralmaz. Her departmanın izinleri ayrı ayrı tanımlanmalıdır.
isLocked: trueolan departmanlar arayüzde silme/düzenleme butonlarından korunur ancak backend'de zorunlu bir kısıt yoktur — dikkatli olunmalıdır.