12 Ara 2024·6 dk okuma

PostgreSQL'de organizasyon şeması modelleme: adjacency list vs closure

PostgreSQL'de organizasyon şemalarını adjacency list ve closure tablolarını karşılaştırarak modelleyin; filtreleme, raporlama ve izin kontrolleri için net örneklerle.

PostgreSQL'de organizasyon şeması modelleme: adjacency list vs closure

Bir organizasyon şemasının desteklemesi gerekenler

Bir organizasyon şeması, kimin kime rapor verdiğinin ve ekiplerin nasıl departmanlara bağlandığının bir haritasıdır. PostgreSQL'de organizasyon şemalarını modellediğinizde yalnızca her kişiye manager_id kaydetmiyorsunuz. Gerçekte desteklemeniz gereken işler var: organizasyonu gezme, raporlama ve erişim kuralları.

Çoğu kullanıcı üç şeyin anında hissettirilmesini bekler: organizasyonu keşfetme, kişileri bulma ve sonuçları "benim alanım" ile filtreleme. Ayrıca güncellemelerin güvenli olmasını beklerler. Bir yönetici değiştiğinde, şema raporları veya izinleri bozmadan her yerde güncellenmelidir.

Pratikte iyi bir model birkaç tekrarlayan soruyu yanıtlamalıdır:

  • Bu kişinin komuta zinciri (yukarı CEO'ya kadar) nedir?
  • Bu yöneticinin altında kimler var (doğrudan raporlar ve tam alt ağaç)?
  • Panolar için insanlar ekipler ve departmanlar halinde nasıl gruplanır?
  • Yeniden organizasyonlar hatasız nasıl gerçekleşir?
  • Organizasyon yapısına dayanarak kim neyi görebilir?

Basit bir ağaçtan daha zordur çünkü organizasyonlar sık sık değişir. Ekipler departmanlar arasında taşınır, yöneticiler grupları değiştirir ve bazı görünümler yalnızca "insanlar insanlara rapor verir" şeklinde olmayabilir. Örneğin: bir kişi bir ekibe ait olabilir ve ekipler departmanlara bağlıdır. İzinler başka bir katman ekler: organizasyonun şekli bir diyagram değil güvenlik modelinizin parçası olur.

Bazı terimler tasarımları net tutar:

  • Düğüm (node): hiyerarşideki bir öğe (bir kişi, bir ekip veya bir departman).
  • Ebeveyn (parent): doğrudan üstündeki düğüm (bir yönetici veya bir takımı sahiplenen departman).
  • Ata (ancestor): her mesafedeki üst düğümler (yöneticinizin yöneticisi gibi).
  • Torun/alt (descendant): her mesafedeki alt düğümler (sizin altınızda herkes).

Örnek: Satış yeni bir VP'nin altına taşınırsa, iki şey hemen doğru kalmalıdır. Panolar hâlâ "tüm Satış"i filtrelemeli ve yeni VP'nin izinleri Satış'ı otomatik kapsamalıdır.

Bir tablo tasarımını seçmeden önce kararlaştırılacaklar

Bir şemaya karar vermeden önce uygulamanızın her gün hangi soruları yanıtlaması gerektiğini netleştirin. "Kim kime rapor veriyor?" sadece başlangıçtır. Birçok organizasyon şeması ayrıca bir departmana kimin liderlik ettiğini, kimin bir ekip için izin verebileceğini ve kimin bir raporu görebileceğini göstermesi gerekir.

Ekranlarınızın ve izin kontrollerinizin soracağı kesin soruları yazın. Soruları adlandıramıyorsanız, sorgulaması zor bir şema ile sonuçlanırsınız.

Her şeyi şekillendiren kararlar:

  • Hangi sorgular hızlı olmalı: doğrudan yönetici, CEO'ya kadar zincir, bir liderin altındaki tam alt ağaç mı yoksa "bu departmandaki herkes" mi?
  • Katı bir ağaç mı (bir yönetici) yoksa matris organizasyon mu (birden fazla yönetici veya lider)?
  • Departmanlar insanlar ile aynı hiyerarşinin düğümleri mi yoksa ayrı bir özellik mi (ör. her kişide department_id) ?
  • Birisi birden fazla ekibe ait olabilir mi (paylaşılan servisler, squad'lar)?
  • İzinler nasıl akar: ağacın aşağısına, yukarısına mı yoksa her ikisine mi?

Bu seçimler "doğru" verinin neye benzeyeceğini tanımlar. Eğer Alex hem Support hem de Onboarding'i yönetiyorsa, tek bir manager_id veya "takım başına bir lider" kuralı işe yaramayabilir. Bir join tablosuna (lider ile takım) veya "birincil takım + noktalı çizgi ekipleri" gibi net bir politikaya ihtiyacınız olabilir.

Departmanlar ayrı bir dallanma daha yaratır. Departmanlar düğümlerse, "Departman A içerir Takım B içerir Kişi C" gibi ifadeler kurabilirsiniz. Departmanlar ayrı ise department_id = X ile filtrelemek daha basittir ancak ekipler departmanları aşarsa bozulabilir.

Son olarak, izinleri açık bir dille tanımlayın. "Bir yönetici altında olan herkesin maaşını görebilir, fakat akranlarını göremez" aşağı doğru akan bir kuraldır. "Herkes kendi yönetim zincirini görebilir" yukarı doğru bir kuraldır. Bunu erken kararlaştırın çünkü hangi hiyerarşi modelinin doğal hissedeceğini ve hangisinin ileride pahalı sorgulara zorlayacağını değiştirir.

Adjacency list: yöneticiler ve ekipler için basit şema

En az hareketli parçayı istiyorsanız adjacency list klasik başlangıç noktasıdır. Her kişi doğrudan yöneticisine işaret eder ve ağaç bu işaretçileri takip ederek oluşturulur.

Minimal kurulum şöyle görünür:

create table departments (
  id bigserial primary key,
  name text not null unique
);

create table teams (
  id bigserial primary key,
  department_id bigint not null references departments(id),
  name text not null,
  unique (department_id, name)
);

create table employees (
  id bigserial primary key,
  full_name text not null,
  team_id bigint references teams(id),
  manager_id bigint references employees(id)
);

Ayrı tabloları atlayıp department_name ve team_name alanlarını employees üzerinde tutabilirsiniz. Bu başta daha hızlıdır ama temiz tutmak zorlaşır (yazım hataları, yeniden adlandırılan takımlar ve tutarsız raporlama). Ayrı tablolar filtrelemeyi ve izin kurallarını tutarlı ifade etmeyi kolaylaştırır.

Erken koruma önlemleri ekleyin. Kötü hiyerarşi verisini sonra düzeltmek acı verir. En azından self-management'i (manager_id <> id) engelleyin. Ayrıca bir yöneticinin aynı takımda veya departmanda olup olmayacağını, soft delete veya tarihçe tutup tutmayacağınızı karar verin (raporlama çizgileri için denetim gerekiyor mu?).

Adjacency list ile çoğu değişiklik basit yazmalardır: bir yöneticiyi değiştirmek employees.manager_id'yi günceller, bir takımı taşımak employees.team_id'yi günceller (çoğu zaman yönetici ile birlikte). Sorun, küçük bir yazmanın büyük aşağı yönlü etkileri olabilmesidir. Raporlama toplulaşmaları değişir ve "yönetici tüm raporları görebilir" kuralı artık yeni zinciri takip etmelidir.

Bu sadelik adjacency list'in en büyük gücüdür. Zayıf yanı ise sık sık "bu yöneticinin altındaki herkes" ile filtreleme yaptığınızda ortaya çıkar; çünkü genellikle her seferinde ağacı dolaşmak için recursive sorgulara güvenirsiniz.

Adjacency list: filtreleme ve raporlama için yaygın sorgular

Adjacency list ile birçok faydalı organizasyon sorusu recursive sorgulara dönüşür. PostgreSQL'de organizasyon şemalarını bu şekilde modellediğinizde, sürekli çalışacağınız desenler şunlardır.

Doğrudan raporlar (bir seviye)

En basit durum yöneticinin hemen altındaki ekip:

SELECT id, full_name, title
FROM employees
WHERE manager_id = $1
ORDER BY full_name;

Bu hızlı ve okunaklıdır, ama yalnızca bir seviye aşağı iner.

Komuta zinciri (yukarı doğru)

Birinin kime rapor verdiğini (yönetici, yöneticinin yöneticisi vb.) göstermek için recursive CTE kullanın:

WITH RECURSIVE chain AS (
  SELECT id, full_name, manager_id, 0 AS depth
  FROM employees
  WHERE id = $1

  UNION ALL

  SELECT e.id, e.full_name, e.manager_id, c.depth + 1
  FROM employees e
  JOIN chain c ON e.id = c.manager_id
)
SELECT *
FROM chain
ORDER BY depth;

Bu onaylar, tırmanma yolları ve yönetici kırıntıları için uygundur.

Tam alt ağaç (aşağı doğru)

Bir liderin altındaki herkes için (tüm seviyeler), rekürsiyonu tersine çevirin:

WITH RECURSIVE subtree AS (
  SELECT id, full_name, manager_id, department_id, 0 AS depth
  FROM employees
  WHERE id = $1

  UNION ALL

  SELECT e.id, e.full_name, e.manager_id, e.department_id, s.depth + 1
  FROM employees e
  JOIN subtree s ON e.manager_id = s.id
)
SELECT *
FROM subtree
ORDER BY depth, full_name;

Sık görülen bir rapor "lider Y altında departman X'teki herkes":

WITH RECURSIVE subtree AS (
  SELECT id, department_id
  FROM employees
  WHERE id = $1
  UNION ALL
  SELECT e.id, e.department_id
  FROM employees e
  JOIN subtree s ON e.manager_id = s.id
)
SELECT e.*
FROM employees e
JOIN subtree s ON s.id = e.id
WHERE e.department_id = $2;

Adjacency list sorguları izinler için risk oluşturabilir çünkü erişim kontrolleri genellikle tam yola (görüntüleyici bu kişinin ataşı mı?) bağlıdır. Bir uç nokta recursion'ı unutursa veya filtreleri yanlış yerde uygularsa satır sızıntısı olabilir. Ayrıca döngüler ve eksik yöneticiler gibi veri sorunlarına dikkat edin. Bir kötü kayıt recursion'ı bozabilir veya şaşırtıcı sonuçlar döndürebilir; bu yüzden izin sorgularında korumalar ve iyi kısıtlar olmalıdır.

Closure table: tüm hiyerarşiyi nasıl saklar

Organizasyon veri modelinizi oluşturun
Çalışanları, ekipleri ve org closure tablolarını PostgreSQL üzerinde görsel olarak modelleyin.
AppMaster'ı Deneyin

Closure table her bir ata-torun ilişkisini, yalnızca doğrudan yönetici bağlantısını değil, depolar. Ağacı adım adım dolaşmak yerine "Bu liderin altında kimler var?" diye sorar ve basit bir join ile tam cevabı alırsınız.

Genellikle iki tablo tutarsınız: birisi düğümler (insanlar veya ekipler), diğeri hiyerarşi yolları için.

-- nodes
employees (
  id bigserial primary key,
  name text not null,
  manager_id bigint null references employees(id)
)

-- closure
employee_closure (
  ancestor_id bigint not null references employees(id),
  descendant_id bigint not null references employees(id),
  depth int not null,
  primary key (ancestor_id, descendant_id)
)

Closure tablosu (Alice, Bob) gibi çiftleri saklar; bu "Alice Bob'un ataşıdır" demektir. Ayrıca ancestor_id = descendant_id ve depth = 0 olan bir satır saklanır. Bu kendi kendine ait satır ilk bakışta garip görünür ama birçok sorguyu temizleştirir.

depth iki düğümün ne kadar uzak olduğunu söyler: depth = 1 doğrudan yönetici, depth = 2 yöneticinin yöneticisi vb. Bu, doğrudan raporların dolaylı olanlardan farklı muamele edilmesi gerektiğinde önemlidir.

Temel fayda öngörülebilir, hızlı okumadır:

  • Tam alt ağaç aramaları hızlıdır (bir direktörün altındaki herkes).
  • Komuta zincirleri basittir (birinin üstündeki tüm yöneticiler).
  • depth ile doğrudan ve dolaylı ilişkileri ayırabilirsiniz.

Maliyet ise güncelleme sırasında gelir. Eğer Bob yöneticisini Alice'den Dana'ya değiştirirse, Bob ve Bob'un altındaki herkes için closure satırlarını yeniden kurmanız gerekir. Tipik yaklaşım: eski ata yollarını o alt ağaç için silmek, sonra Dana'nın ataları ile Bob'un alt ağındaki her düğümü birleştirip yeni yolları eklemektir.

Closure table: hızlı filtreleme için yaygın sorgular

Rol tabanlı bir portal başlatın
Görünümler otomatik olarak "benim organizasyonum" kapsamına göre gelen bir personel portalı sunun.
Portal Oluştur

Closure tablosu her ata-torun çiftini önceden (genellikle org_closure(ancestor_id, descendant_id, depth) olarak) saklar. Bu, org filtrelerini hızlı yapar çünkü çoğu soru tek join'e dönüşür.

Bir yöneticinin altındaki herkesin listesini almak için bir kez join yapın ve depth ile filtreleyin:

-- Torunlar (alt ağaçtaki herkes)
SELECT e.*
FROM employees e
JOIN org_closure c
  ON c.descendant_id = e.id
WHERE c.ancestor_id = :manager_id
  AND c.depth > 0;

-- Sadece doğrudan raporlar
SELECT e.*
FROM employees e
JOIN org_closure c
  ON c.descendant_id = e.id
WHERE c.ancestor_id = :manager_id
  AND c.depth = 1;

Komuta zinciri (bir çalışanın tüm ataları) için join'i tersine çevirin:

SELECT m.*
FROM employees m
JOIN org_closure c
  ON c.ancestor_id = m.id
WHERE c.descendant_id = :employee_id
  AND c.depth > 0
ORDER BY c.depth;

Filtreleme öngörülebilir olur. Örnek: "lider X'in altındaki herkes ama sadece departman Y'dekiler":

SELECT e.*
FROM employees e
JOIN org_closure c ON c.descendant_id = e.id
WHERE c.ancestor_id = :leader_id
  AND e.department_id = :department_id;

Hiyerarşi önceden hesaplandığı için sayımlar da basittir (recursion yok). Bu panolar ve izin kapsamlı toplamlar için faydalıdır ve sayfalama ile aramada ORDER BY, LIMIT/OFFSET ve filtreleri doğrudan uygulamayı kolaylaştırır.

Hangi model izinleri ve erişim kontrollerini nasıl etkiler

Yaygın bir kural basittir: bir yönetici altında olan herkes görülebilir (ve bazen düzenlenebilir). Seçtiğiniz şema, "kim kimin altında"nın ne sıklıkla hesaplandığı maliyetini değiştirir.

Adjacency list ile izin kontrolü genellikle recursion gerektirir. Bir kullanıcı 200 çalışan listeleyen bir sayfa açarsa, genellikle descendant kümesini recursive CTE ile oluşturup hedef satırları buna göre filtrelersiniz.

Closure table ile aynı kural genellikle basit bir varlık testi ile kontrol edilebilir: "Mevcut kullanıcı bu çalışanın atası mı?" Evet ise izin ver.

-- Closure tablosu izin kontrolü (kavramsal)
SELECT 1
FROM org_closure c
WHERE c.ancestor_id = :viewer_id
  AND c.descendant_id = :employee_id
LIMIT 1;

Bu sadelik, row-level security (RLS) gibi durumlarda önem kazanır; çünkü adjacency list ile politika genellikle recursion içerir ve ayarlaması zordur. Closure tablosu ile politika çoğunlukla basit bir EXISTS (...) kontrolüdür.

Köşe durumlar izin mantığının en çok bozulduğu yerlerdir:

  • Noktalı çizgi raporlaması: bir kişinin efektif olarak iki yöneticisi olması.
  • Asistanlar ve delege edenler: erişim hiyerarşiye bağlı olmayabilir; bu yüzden açık izinler saklayın (genellikle süresi olan).
  • Geçici erişim: zaman sınırlı izinler org yapısına gömülmemelidir.
  • Ekipler arası projeler: erişimi yönetici zinciriyle değil proje üyeliğiyle verin.

Eğer bunu AppMaster içinde kuruyorsanız, closure tablosu genellikle görsel veri modeline iyi uyum sağlar ve erişim kontrolünü web ve mobil uygulamalarda da basit tutar.

Takaslar: hız, karmaşıklık ve bakım

Her iki hiyerarşi modelini prototipleyin
Önce adjacency list deneyin, ihtiyaç duyunca daha hızlı okumalar için closure tablosu ekleyin.
Şimdi Prototip Oluştur

En büyük seçim neyi optimize edeceğinizdir: basit yazmalar ve küçük şema mı, yoksa "bu yöneticinin altındaki kim" sorusu için hızlı okumalar mı.

Adjacency list tabloları küçük ve güncellemeleri kolay tutar. Maliyet okuyalarda ortaya çıkar: tam alt ağaç genellikle recursion demektir. Bu, organizasyonunuz küçükse, kullanıcı arayüzünüz sadece birkaç seviye yüklüyorsa veya hiyerarşi tabanlı filtreler sınırlı sayıda yerde kullanılıyorsa kabul edilebilir.

Closure tabloları bu takası tersine çevirir. Okumalar hızlıdır çünkü "tüm torunlar" regular joinlerle cevaplanır. Yazmalar daha karmaşıktır çünkü bir taşınma veya reorganizasyon birden çok ilişki satırını eklemeyi/silmeyi gerektirebilir.

Gerçekte takas genellikle şöyle görünür:

  • Okuma performansı: adjacency recursion gerektirir; closure çoğunlukla join'lerdir ve organizasyon büyüdükçe hızlı kalır.
  • Yazma karmaşıklığı: adjacency tek parent_id günceller; closure tek bir taşınma için çok sayıda satır günceller.
  • Veri boyutu: adjacency kişi/ekip büyüklüğüyle büyür; closure ilişkilerle büyür (en kötü durumda derin bir ağaç için yaklaşık N kare büyüme).

Dizinleme her iki modelde de önemlidir ama hedef farklıdır:

  • Adjacency list: parent pointer (manager_id) üzerinde indeksleyin ve yaygın filtreler için (ör. "active" bayrağı) indeks ekleyin.
  • Closure table: (ancestor_id, descendant_id) üzerinde indeks ve yaygın sorgular için descendant_id üzerinde ayrı indeks oluşturun.

Basit bir kural: hiyerarşiyle nadiren filtreliyorsanız ve izin kontrolleri sadece "yönetici doğrudan raporları görür" ise adjacency list genellikle yeterlidir. Eğer sıkça "VP X altındaki herkes" raporları çalıştırıyor, departman ağaçlarına göre filtreliyor veya birçok ekranda hiyerarşi tabanlı izinleri uyguluyorsanız closure tabloları ek bakım maliyetini karşılayabilir.

Adjacency list'ten closure table'a adım adım geçiş

Day one'da modeller arasında seçim yapmak zorunda değilsiniz. Güvenli yol adjacency list (manager_id veya parent_id) tutmak ve yanına closure tablosu eklemektir, sonra okumaları zaman içinde taşırsınız. Bu, yeni hiyerarşinin gerçek sorgular ve izin kontrollerinde nasıl davrandığını doğrularken riski düşürür.

Bir closure tablosu (genellikle org_closure) oluşturup ancestor_id, descendant_id ve depth gibi sütunlar ekleyin. Mevcut employees veya teams tablonuzdan ayrı tutun ki backfill ve doğrulama yaparken mevcut özelliklere dokunmayın.

Pratik bir dağıtım:

  • Closure tablosunu ve indeksleri oluşturun; adjacency list'i hâlâ tek yetkili kaynak olarak bırakın.
  • Mevcut yönetici ilişkilerinden closure satırlarını backfill edin; kendi kendine atayı içeren satırları unutmayın (her düğüm depth 0 ile kendi atasıdır).
  • Lekeli kontroller yapın: birkaç yöneticiyi seçin ve her iki modelde aynı ast setinin göründüğünü doğrulayın.
  • Okuma yollarını önce değiştirin: raporlar, filtreler ve hiyerarşik izinler closure tablosundan okunsun.
  • Her yazmada closure'ı güncelleyin (re-parent, işe alım, takım taşıma). Stabil olduktan sonra recursion tabanlı sorguları emekliye ayırın.

Doğrulama yaparken, erişim kurallarını en çok bozan durumlara odaklanın: yönetici değişiklikleri, üst liderler ve yöneticisiz kullanıcılar.

AppMaster içinde inşa ediyorsanız, yeni olanları test ederken eski endpoint'leri çalışır tutabilir ve sonuçlar eşleşince geçiş yapabilirsiniz.

Organizasyon filtreleme veya izinleri bozan yaygın hatalar

Yönetici tabanlı onaylar ekleyin
Yeniden organizasyonlardan sonra bile komuta zincirini takip eden onay akışları kurun.
İş Akışı Oluştur

Organizasyon özelliklerini bozan en hızlı yol, hiyerarşinin tutarsız hale gelmesine izin vermektir. Veri satır satır iyi görünse bile küçük hatalar yanlış filtrelere, yavaş sayfalara veya izin sızıntısına neden olabilir.

Klasik bir problem döngü oluşturmaktır: A B'yi yönetir, sonra biri B'yi A'nın yöneticisi yapar (veya 3–4 kişilik daha uzun bir döngü). Recursive sorgular sonsuza kadar çalışabilir, çoğaltılmış satırlar döndürebilir veya zaman aşımına uğrayabilir. Closure tablosu olsa bile döngüler ata/torun satırlarını zehirleyebilir.

Diğer yaygın sorun closure kaymasının (closure drift) oluşmasıdır: birinin yöneticisini değiştirdiniz ama sadece doğrudan ilişkiyi güncellediniz ve alt ağaç için closure satırlarını yeniden oluşturmayı unuttunuz. Sonuç, "bu VP altındaki herkes" gibi filtrelerin eski ve yeni yapının karışımını döndürmesidir. Bireysel profil sayfaları hâlâ doğru göründüğü için tespit edilmesi zordur.

Organizasyon şemaları departmanlar ve raporlama çizgileri karıştırıldığında da karışır. Departman genellikle idari bir gruplaşmadır, raporlama çizgileri yöneticilerle ilgilidir. Bunları aynı ağaç olarak ele alırsanız "departman taşıması" beklenmedik şekilde erişimi değiştirebilir.

İzinler en sık sadece doğrudan yöneticiye bakan kontrollerle başarısız olur. viewer is manager of employee kontrolü uygularsanız tam zinciri gözardı edersiniz. Sonuç ya aşırı engelleme (üst atlama yöneticileri orgunu göremez) ya da aşırı paylaşma (birisi geçici doğrudan yönetici yapılarak erişim kazanır) olur.

Yavaş liste sayfaları genellikle her istekte recursive filtre çalıştırılmasından gelir (her gelen kutusu, her ticket listesi, her çalışan araması). Aynı filtre her yerde kullanılıyorsa ya önceden hesaplanmış yollar (closure tablosu) ya da izin verilen çalışan ID'lerinin önbelleğe alınmış bir kümesini istersiniz.

Birkaç pratik güvenlik önlemi:

  • Yönetici değişikliklerini kaydetmeden önce döngüleri engelleyin.
  • "Departman"ın ne anlama geldiğini karar verin ve bunu raporlamadan ayrı tutun.
  • Closure tablosu kullanıyorsanız yönetici değişikliklerinde torun satırlarını yeniden oluşturun.
  • İzin kurallarını yalnızca doğrudan yöneticiye bakacak şekilde değil tüm zinciri göz önünde bulunduracak biçimde yazın.
  • Liste sayfalarında kullanılan organizasyon kapsamlarını her seferinde yeniden hesaplamak yerine önceden hesaplayın.

AppMaster'da admin panelleri inşa ediyorsanız, "yönetici değiştir" iş akışını hassas bir süreç olarak görün: doğrulayın, ilgili hiyerarşi verilerini güncelleyin ve ancak sonra filtreleri ve erişimi etkilemesine izin verin.

Göndermeden önce hızlı kontroller

Organizasyon API'leri oluşturun
Organizasyon yapınızı elle endpoint yazmadan üretime hazır API'lere dönüştürün.
Arka Uç Üret

Organizasyon şemanızı "tamam" ilan etmeden önce, erişimi basit sözlerle açıklayabildiğinizden emin olun. Birisi "X çalışanını kim görebilir ve neden?" diye sorduğunda, bunu kanıtlayan tek bir kural ve tek bir sorgu (veya view) gösterebilmelisiniz.

Performans bir diğer gerçek kontrolüdür. Adjacency list ile "bu yönetici altındaki herkesi göster" recursive sorgudur ve hızı derinlik ve indekslemeye bağlıdır. Closure tablosu ile okumalar genellikle hızlıdır ama yazma yolunun her değişiklikten sonra tabloyu doğru tuttuğuna güvenmelisiniz.

Kısa bir gönderim öncesi kontrol listesi:

  • Bir çalışan seçin ve görünürlüğü baştan sona izleyin: hangi zincir erişim veriyor, hangi rol engelliyor.
  • Beklenen boyutta bir yönetici alt ağaç sorgusunu benchmark edin (ör. 5 seviye derinlik ve 50.000 çalışan).
  • Kötü yazmaları engelleyin: döngüleri, self-management'i ve yetim düğümleri kısıtlamalar ve işlem kontrolleriyle önleyin.
  • Yeniden organizasyon güvenliğini test edin: taşımalar, birleşmeler, yönetici değişiklikleri ve orta noktada bir şey başarısız olduğunda rollback.
  • HR, yönetici, takım lideri, destek gibi gerçekçi rollere izin testleri ekleyin; hem izin verilen hem reddedilen durumları doğrulayın.

Pratik bir doğrulama senaryosu: bir destek temsilcisi yalnızca atandığı departmandaki çalışanları görebilir, bir yönetici ise tam alt ağacını görebilir. Eğer PostgreSQL'de organizasyon şemalarını modelleyebiliyor ve her iki kuralı testlerle kanıtlayabiliyorsanız, yayına yakınsınız demektir.

AppMaster içinde inşa ediyorsanız, bu kontrolleri sadece veritabanı sorguları etrafında değil, org listeleri ve çalışan profilleri döndüren endpoint'lerde otomatik testler olarak tutun.

Örnek senaryo ve sonraki adımlar

Üç departmanlı bir şirket hayal edin: Satış, Destek ve Mühendislik. Her departmanın iki takımı var ve her takımın bir lideri var. Satış Lideri A ekibi için indirimleri onaylayabilir, Destek Lideri B departman için tüm ticket'ları görebilir ve Mühendislik VP'si Mühendislik altındaki her şeyi görebilir.

Sonra bir yeniden organizasyon olur: bir Destek takımı Satış altına taşınır ve Sales Direktörü ile iki takım lideri arasına yeni bir yönetici eklenir. Ertesi gün biri şu erişimi talep eder: "Jamie (Satış analisti) Satış departmanındaki tüm müşteri hesaplarını görsün ama Mühendislik'i görmesin."

Adjacency list ile modellediğinizde şema basittir, fakat uygulama işi sorgulara ve izin kontrollerine kayar. "Satış altındaki herkes" gibi filtreler genellikle recursion gerektirir. Onaylar eklendikçe ("yalnızca zincirdeki yöneticiler onaylayabilir" gibi) yeniden organizasyon sonrası kenar durumları önem kazanmaya başlar.

Closure tablosu ile yeniden organizasyonlar daha fazla yazma işi demektir (ata/torun satırlarını güncellemek), ama okuma tarafı basitleşir. Filtreler ve izinler genellikle basit join'lere dönüşür: "bu kullanıcı o çalışanın atası mı?" veya "bu takım bu departman alt ağında mı?" gibi.

Bu doğrudan ekranda kendini gösterir: insan seçiciler departmana göre sınırlandırılmış olur, onay yönlendirmeleri talep edenin üzerindeki en yakın yöneticiye gider, admin görünümleri departman panoları için kullanılır ve denetimler bir tarihte neden erişim olduğu açıklanabilir.

Sonraki adımlar:

  1. İzin kurallarını düz metinle yazın (kim neyi, neden görebilir).
  2. En yaygın kontrollerle eşleşen bir model seçin (hızlı okumalar mı yoksa daha basit yazmalar mı).
  3. Yeniden organizasyonları, erişim isteklerini ve onayları uçtan uca test eden bir dahili admin aracı oluşturun.

Eğer bu organizasyon farkındalıklı admin panellerini ve portalları hızlıca kurmak isterseniz, AppMaster (appmaster.io) pratik bir seçim olabilir: PostgreSQL destekli veriyi modellemenize, görsel İş Süreci ile onay mantığını uygulamanıza ve aynı backend'ten web ile native mobil uygulamalar sunmanıza imkan verir.

SSS

Organizasyon grafiği için adjacency list mi yoksa closure table mı kullanmalıyım?

Bir organizasyon küçükse, güncellemeler sıksa ve çoğu ekran sadece doğrudan raporları veya birkaç seviye gösteriyorsa adjacency list kullanın. "Bu liderin altındaki herkes"i sıkça sorguluyorsanız, departmana göre filtreler veya birçok sayfada hiyerarşi tabanlı izinler gerekiyorsa closure tablosu tercih edin; çünkü okumalar basit join'lere dönüşür ve büyüdükçe öngörülebilirdir.

PostgreSQL'de "kim kime rapor veriyor" bilgisini saklamanın en basit yolu nedir?

Başlangıçta employees(manager_id) ile başlayın ve doğrudan raporları basit bir WHERE manager_id = ? sorgusuyla alın. Tam soy ağacı veya tüm ataları isteyen özellikler için ancak gerektiğinde recursive sorgular ekleyin (onaylar, “benim organizasyonum” filtreleri veya üst atlama panoları gibi).

Döngüleri (A, B'yi yönetir; sonra B, A'yı yönetir) nasıl engellerim?

Kendini yönetmeyi manager_id <> id gibi bir check ile engelleyin ve güncellemeleri kaydetmeden önce atanın zaten çalışanın alt ağında olup olmadığını doğrulayın. En güvenli yol, bir yönetici değişikliği kaydetmeden önce soy-ata kontrolü yapmaktır; çünkü bir döngü recursion'ı bozabilir ve izin mantığını bozar.

Departmanlar insanlarla aynı hiyerarşinin düğümleri olarak mı olmalı?

İyi bir varsayılan, departmanları idari bir gruplaşma; raporlama hatlarını ise ayrı bir yönetici ağacı olarak tutmaktır. Bu, "departman taşıması"nın yanlışlıkla kimin rapor verdiğini değiştirmesini önler ve reporting filtrelerini, raporlama hatları departman sınırlarıyla eşleşmediğinde bile daha net tutar.

Birinin iki yöneticisinin olduğu matris organizasyonu nasıl modellemeliyim?

Çoğunlukla çalışanın birincil raporlama yöneticisini manager_id olarak tutar, noktalı çizgi (dotted-line) ilişkileri ise ayrı bir tablo veya ikincil yönetici alanı ile temsil edersiniz. Bu, temel hiyerarşi sorgularını bozmadan proje erişimi veya yetki devri gibi özel kuralları uygulamaya izin verir.

Birinin yöneticisi değiştiğinde closure tablosunda neyi güncellemeliyim?

Taşınan çalışanın alt ağının eski ata yollarını silin ve ardından yeni yöneticinin atalarını taşınan alt ağa birleştirerek yeni yolları ekleyin; depth değerlerini yeniden hesaplayın. Bunu bir işlem içinde yapın ki değişiklik yarım kalmasın ve closure tablosu tutarsız hale gelmesin.

Organizasyon sorguları için hangi indeksler en önemlidir?

Adjacency için employees(manager_id) dizinleyin; neredeyse tüm org sorguları oradan başlar. Closure tabloları için en önemli dizinler (ancestor_id, descendant_id) üzerinde birincil anahtar ve descendant_id üzerinde ayrı bir dizindir; bu, "bu satırı kim görebilir?" sorgularını hızlı yapar.

Bir yöneticinin kendi altındakileri güvenli şekilde görmesi nasıl uygulanır?

Closure tablosunda EXISTS desenini kullanmak yaygındır: izleyici hedef çalışanın atasıysa erişime izin verin. Bu, row-level security ile iyi çalışır çünkü veritabanı kuralı tutarlı biçimde uygulayabilir; her API endpoint'in aynı recursive mantığı hatırlamasına güvenmezsiniz.

Yeniden organizasyon geçmişi ve denetim izlerini nasıl ele almalıyım?

Geçmişi açıkça saklayın; genellikle yönetici değişikliklerini etkili tarihlerle kaydeden ayrı bir tablo kullanın. Bu şekilde "X tarihindeki raporlama ilişkisi" sorusunu doğru yanıtlayabilirsiniz; aksi halde geçmişi kaybedersiniz ve raporlar reorganizasyonlardan sonra tutarsız olur.

Adjacency list'ten closure table'a uygulamayı bozmadan nasıl geçerim?

Mevcut manager_id kaynağını koruyun, closure tablosunu yanına oluşturun ve mevcut ağa göre backfill yapın. Okuma yollarını önce taşıyın (filtreler, panolar, izin kontrolleri), ardından yazmaları her iki tarafa da yazacak şekilde güncelleyin; sonuçlar gerçek senaryolarda eşleşince recursion tabanlı sorguları emekliye ayırın.

Başlaması kolay
Harika bir şey yaratın

Ücretsiz planla AppMaster ile denemeler yapın.
Hazır olduğunuzda uygun aboneliği seçebilirsiniz.

Başlayın