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.jsgetDepartmentAndChildrenIds()

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:

  1. DepartmentPermissions tablosundan kullanıcının departmanına ait tüm izinler çekilir
  2. JWT token içine permissions: [...] array olarak yazılır
  3. 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:

  1. Mevcut tüm DepartmentPermissions kayıtları silinir
  2. 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 permissions array'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: true olan departmanlar arayüzde silme/düzenleme butonlarından korunur ancak backend'de zorunlu bir kısıt yoktur — dikkatli olunmalıdır.

results matching ""

    No results matching ""