Factorizer/Cluster ERP WikiCluster ERP English
Ana sayfa / Katkı

Referans

Kodlama kuralları

Cluster ERP için projenin yazılı mühendislik kuralları; her biri onu uygulayan kod veya testle birlikte ya da kodla uygulanmadığı belirtilerek yeniden anlatılır.

Bu sayfa Cluster ERP için projenin yazılı mühendislik kurallarını sade sözcüklerle yeniden anlatır. Her kural, onu gerçekleştiren kodu ve onu uygulayan testi ya da kapıyı adlandırır. Depoda bir kuralı uygulayan hiçbir şey yoksa sayfa bunu söyler. En büyük kuralların gerekçeleri karar kayıtları bölümündedir; bu sayfa başvuru tablosudur.

Kapsam ve kaynak

Kurallar projenin yazılı mühendislik kurallarından gelir. Uygulama sütunu; tests/ içindeki testler, .github/workflows/ci.yml içindeki kapılar, pyproject.toml yapılandırması ve doğrulanan commit'teki atıf yapılan kaynak dosyalar okunarak çıkarıldı.

  • Tanımlandığı yer: projenin yazılı mühendislik kuralları.
  • Uygulandığı yer: tests/test_architecture_boundaries.py, tests/test_metadata_driven_rules.py, tests/test_static_quality.py, tests/test_e2e_db_isolation.py, tests/ içindeki diğer dosyalar ve .github/workflows/ci.yml.
  • Sayı: yedi grupta 34 kural; aşağıdaki tabloların satırları sayıldı.

Mimari ve iletişim

Bu kurallar modülleri birbirinden bağımsız tutar. Testlerin ayrıntısı mimari sınırlar sayfasındadır.

Kural Kodun yaptığı Uygulayan
Modüller birbirini asla import etmez. İzin verilen tek import yetki kapısı cluster_erp.modules.auth.guards'tır. Sınır testi src/cluster_erp/modules/ altındaki her Python dosyasını ayrıştırır ve başka bir modülün import'larını listeler. tests/test_architecture_boundaries.py:24, tests/test_architecture_boundaries.py:46-57
Modüller arası iletişim, dondurulmuş dataclass sözleşmeleriyle EventBus üzerinden yapılır. EventBus.emit bir olayı her aboneye dağıtır; EventBus.query bir sorgunun tek işleyicisini çağırır (src/cluster_erp/core/event_bus.py:83-102). Sözleşmeler @dataclass(frozen=True, kw_only=True) sınıflarıdır, örneğin PartyRoleSet (src/cluster_erp/core/contracts.py:47-55). Yukarıdaki import yasağı; aynı sorgu için ikinci işleyici DuplicateQueryHandlerError fırlatır (src/cluster_erp/core/event_bus.py:78-79)
Her modül ModuleBase'den türer ve onun yaşam döngüsünü izler. ModuleBase; initialize, register_routes, register_events, shutdown ve get_metadata bildirir (src/cluster_erp/core/module_base.py:61-74). Kayıt defteri ilk üçünü bu sırayla çağırır (src/cluster_erp/core/module_registry.py:49-52). tests/test_architecture_boundaries.py:60-72 her modülde bir module.py ve en az bir rota ister
Uygulama katmanı birden çok modül servisini düzenleyebilir. Bir modül değildir. server/routes/party_composite.py bir tarafı ve rol facet'lerini tek işlemde oluşturur (src/cluster_erp/server/routes/party_composite.py:1-10). Bir testle uygulanmaz. Sınır testi yalnız src/cluster_erp/modules/ klasörünü tarar (tests/test_architecture_boundaries.py:21).
Her alt modül iş mantığını AsyncSession alan bir serviste tutar. Rotalar servisi oluşturur ve Pydantic ile doğrular. Örnek: UiStateService (src/cluster_erp/modules/auth/ui_state/services.py:12-44) ve rotaları (src/cluster_erp/modules/auth/ui_state/routes.py:21-39). Koddan belirlenemedi. Katmanlamayı denetleyen test yok.
Şema Alembic göçlerinden gelir. Bir modül tabloları kendisi oluşturmaz. initialize yalnız modelleri import eder, örneğin src/cluster_erp/modules/records/module.py:36-37. Alembic her modülün models.py dosyasını import eder (migrations/env.py:76-85). CI tüm geçmişi uygular ve tek bir head ister (.github/workflows/ci.yml:113-117)
Yayımlanmış bir göç asla düzenlenmez. pyproject.toml göçleri "frozen historical records" olarak adlandırır ve onlar için yalnız satır uzunluğu kuralını gevşetir (pyproject.toml:134-136). Koddan belirlenemedi. Göçleri bir temel çizgiyle karşılaştıran test yok.

Veri, anahtarlar ve para

Bu kurallar değerlerin ve anahtarların nasıl saklandığını belirler. Her mekanizma platform bölümünde belgelenir.

Kural Kodun yaptığı Uygulayan
Para Decimal'dir; veritabanında Numeric, JSON'da metindir ve ROUND_HALF_EVEN ile yuvarlanır. Okuma şemaları Decimal alanları metne dönüştürür (src/cluster_erp/core/currencies.py:186-204). src/cluster_erp altında Mapped[float] bildiren dosya yoktur (grep -rn "Mapped\[float\]" ile arandı). ROUND_HALF_EVEN 32 dosyada geçer, ROUND_HALF_UP hiçbirinde geçmez (grep -rln ile sayıldı). tests/test_analytics_contributions.py:120-133, parasal bir analitik ölçü Numeric olmayan bir sütuna dayanırsa başarısız olur
Para birimi, ülke ve adres yapısı sabit değil, veritabanındaki referans verilerdir. Country, AddressLevel ve AddressLevelValue tablodur (src/cluster_erp/modules/parties/settings/models.py:12, src/cluster_erp/modules/parties/settings/models.py:52, src/cluster_erp/modules/parties/settings/models.py:83). assert_known_currency canlı referans verisi olmayan bir kodu reddeder (src/cluster_erp/core/currencies.py:30-40). Servislerdeki para birimi denetimi; genel kuralı kapsayan test yok
Birincil anahtarlar UUID olarak saklanan ULID'lerdir. BaseModel.id varsayılanı new_ulid'dir (src/cluster_erp/core/models.py:20-24, src/cluster_erp/core/ulid.py:8-14). BaseModel'den kalıtım; aşağıdaki tutarsızlığa bakın
Her kayıt denetim sütunları ve bir sürüm taşır. created_by, updated_by, deleted_at, deleted_by, deactivation_reason, deactivation_note ve version (src/cluster_erp/core/models.py:30-78). BaseModel'den kalıtım
İş anahtarları core_sequences'tan gelir: bir önek ve bir sayaç; bazıları her yıl sıfırlanır. next_code yıllık varlıklar için PREFIX-YEAR-00001, diğerleri için PREFIX-000001 döndürür (src/cluster_erp/core/sequence.py:154-171, src/cluster_erp/core/sequence.py:88-109). İşlevin kendisi dışında koddan belirlenemedi
Ürün, model ve versiyon kırılımı zorunludur. Yalnız ürüne geri düşme yoktur. ensure_product_breakdown, bir ürünün modeli veya versiyonu yoksa HTTP 422 fırlatır (src/cluster_erp/core/product_breakdown.py:112-118). Stok satırlarının anahtarı üçünü de içerir (src/cluster_erp/modules/inventory/stock/models.py:32-46). src/cluster_erp/modules altında 23 dosyada 49 servis çağrısı (grep -rn "ensure_product_breakdown(" ile sayıldı)
Müşteriler, tedarikçiler, kuruluşlar ve çalışanlar rol facet'leri olan tek bir taraftır. FacetMeta taraf kartında bir rol bildirir (src/cluster_erp/core/metadata.py:357-377). PartyRoleSet rol bayrağını ayarlar (src/cluster_erp/core/contracts.py:47-55, src/cluster_erp/modules/parties/module.py:130). tests/test_metadata_driven_rules.py:51-60 rehberli oluşturma rollerini denetler

Kayıtlar ve geçmiş

Bu kurallar her kaydı ve her değişikliği saklar. Ayrıntılar yumuşak silme ve kullanımdan kaldırma ve değişiklik geçmişi sayfalarındadır.

Kural Kodun yaptığı Uygulayan
Kayıtlar asla fiziksel olarak silinmez. Silmek, nedenle kullanımdan kaldırmaktır. deleted_at bir kaydı deleted_by, deactivation_reason ve deactivation_note ile kullanımdan kaldırılmış olarak işaretler (src/cluster_erp/core/models.py:49-72). bulk_soft_delete ORM üzerinden kullanımdan kaldırır (src/cluster_erp/core/bulk_operations.py:20-55). tests/test_live_row_uniqueness.py:1-15 benzersizliği yalnız canlı satırlarda tutar; böylece pasif bir değer yeniden kullanılabilir
Tek genel fiziksel silme saklama temizliğidir. purge_expired, saklama süresinden eski pasif satırları ve geçmişi kaldırır (src/cluster_erp/modules/records/retention/purge.py:1-6, src/cluster_erp/modules/records/retention/purge.py:33-45). Koddan belirlenemedi. Temizlik dışındaki DELETE ifadelerini tarayan test yok.
Sahibiyle birlikte toptan yenilenen bağımlı alt satırlar ORM üzerinden silinir; böylece geçmiş her kaldırmayı kaydeder. orm_delete_where (src/cluster_erp/core/bulk_operations.py:58-75), takvim şablon satırları ve istisna vardiyaları için kullanılır (src/cluster_erp/modules/calendars/services.py:186-190, src/cluster_erp/modules/calendars/services.py:596-600). Koddan belirlenemedi
Değişiklik geçmişi otomatiktir. Kod geçmiş satırını asla elle yazmaz. Tek bir before_flush dinleyicisi oluşturma, güncelleme, kullanımdan kaldırma, etkinleştirme ve silmeyi aktör ve alan farkıyla kaydeder (src/cluster_erp/core/change_history.py:318-351). tests/test_change_history_redaction.py ve tests/test_change_history_tables_live.py bir bölümünü kapsar

Web arayüzü

Web uygulaması ekranları metadata'dan çizer. Listeler, aksiyonlar ve ana ekran için davranış kuralları her modülde geçerlidir.

Kural Kodun yaptığı Uygulayan
Web uygulaması metadata ile yönetilir. Genel kodda tek bir modüle özgü kural yoktur. Genel motorlar /api/v1/_meta okur (src/cluster_erp/server/app.py:1519-1546). tests/test_architecture_boundaries.py:75-87 ve tests/test_metadata_driven_rules.py:85-112
Bir liste "yeni ekle"yi gezinme çubuğu düğmesi olarak değil, ilk satır olarak gösterir. Seçim basılı tutmadır. Aksiyonlar etiketli bir çipten açılır. Ekleme satırı listenin en üstünde kurulur (webapp/js/gen-list.js:703-710). bindLongPress 450 ms sonra devreye girer (webapp/js/ui.js:71). Aksiyon kartının başlığı etiketli çipi belirtir (webapp/js/action-sheet.js:1-9). web-client/_e2e_action_sheet.mjs gibi tarayıcı süitleri; pytest testi yok
Çoğaltılmış ana ekran düğmesi yalnız PC cihaz sınıfında vardır ve var olduğu yerde önde kalır, asla gizlenmez. tilesAllowed() çoklu ekranı pc sınıfıyla sınırlar ve syncDupHome düğmeyi başka yerde gizler (webapp/js/tiles.js:60-64, webapp/js/tiles.js:130-137); stil sayfası onu dock bandının üstünde tutar (webapp/css/tiles.css:5-12). web-client/_e2e_dup_home_tiles.mjs (PC) ve web-client/_e2e_mobile_app.mjs (telefon, tablet); pytest testi yok
Bir modül tek bir uygulamadır; sayfaları o uygulamanın sekmeleridir. Her modülün kendi module.py dosyası ve API'si vardır (tests/test_architecture_boundaries.py:60-72). web-client/_e2e_procurement_app.mjs:1-3 ve diğer uygulama süitleri
Kullanıcının yerleşimi sunucuda durur. Cihaz tercihleri tarayıcıda kalır. auth_user_ui_state kullanıcı ve anahtar başına bir satır tutar (src/cluster_erp/modules/auth/ui_state/models.py:13-35). Tema ve saat dilimi localStorage kullanır (webapp/js/prefs.js:5-6). Masaüstü istemci yerleşimini QSettings içinde tutar (src/cluster_erp/desktop/core/settings_store.py:10). tests/test_e2e_db_isolation.py:177-200 yerleşime dokunan tarayıcı süitlerinin arayüz durumu bekçisini kullanmasını ister
Cihaz deneyimleri ayrışır: sınıf yalnız genişlikten değil, hover ve işaretçiden gelir. PC_QUERY, PC_MIN_WIDTH ve PHONE_MAX_WIDTH (webapp/js/device-class.js:16-20). web-client/_e2e_mobile_home.mjs ve web-client/_e2e_touch_sweep.mjs tarayıcı süitleri

Diller ve metin

Görünen her metin bir dil dosyasından veya bir metadata etiketinden gelir. Dil listesini veri güdümlü diller kaydı açıklar.

Kural Kodun yaptığı Uygulayan
Kullanıcıya görünen sabit metin yoktur. Her yeni metin hem en.json hem tr.json içinde, doğru Türkçe karakterlerle bir anahtar alır. Web anahtarları webapp/i18n/ içinde, masaüstü anahtarları src/cluster_erp/desktop/i18n/ içindedir. Kısmen: tests/test_party_form_contract.py:104-109 bir hata anahtarını dört dosyanın hepsinde denetler; tests/test_metadata_driven_rules.py:77-82 ve tests/test_metadata_driven_rules.py:172-173 İngilizce ve Türkçe etiket ister
Yeni bir dil, yeni bir JSON dosyası ve bir bildirim satırıdır; kod değişikliği gerekmez. webapp/js/i18n.js languages.json dosyasını okur (webapp/js/i18n.js:1-7, webapp/js/i18n.js:32-44). Masaüstü istemci klasöründeki her *.json dosyasını listeler (src/cluster_erp/desktop/i18n/translator.py:92-99). web-client/_e2e_lang.mjs:1-6 beklentilerini bildirimden türetir
Geçerli dili olmayan bir metadata etiketi İngilizceye düşer. resolveLabel (webapp/js/meta.js:284-288) ve Translator.t (src/cluster_erp/desktop/i18n/translator.py:57-67). Koddan belirlenemedi

Masaüstü istemci

Masaüstü istemci metadata'yı web uygulamasıyla paylaşır. Kendi kuralları API çağrıları ve sinyallerle ilgilidir.

Kural Kodun yaptığı Uygulayan
API çağrıları bir QThread işçisinde eşzamanlı bir httpx istemcisi kullanır. ApiWorker ve ApiMixin (src/cluster_erp/desktop/core/api_worker.py:28, src/cluster_erp/desktop/core/api_worker.py:179). Koddan belirlenemedi
Değişiklik çağrıları varlıklarını adlandırır ve değişiklik sinyalini istemci yayar. Görünümler sinyali kendileri yaymaz. post, put ve delete bir EntityDescriptor alır (src/cluster_erp/desktop/core/api_client.py:223-268). Görünümler watch_entity ile abone olur (src/cluster_erp/desktop/core/signal_bus.py:55). Koddan belirlenemedi
Bilinen sağlam PySide6 sürümü gerektiği yerde sabitlenir. desktop eki PySide6>=6.7.0 ister (pyproject.toml:72-74); CI PySide6==6.8.3 kurar (.github/workflows/ci.yml:50). CI

Kod kalitesi

Bu kurallar CI'da ve test süitinde kapıdır. Yapılandırmayı lint ve tip denetimi sayfası listeler.

Kural Kodun yaptığı Uygulayan
mypy, Python 3.12 üzerinde, Pydantic eklentisiyle katı kipte çalışır. pyproject.toml:99-102 .github/workflows/ci.yml:52, tests/test_static_quality.py:38-46
Ruff E, F, W, I, N, UP, B, A ve SIM ailelerini 100 satır uzunluğuyla seçer. TCH bilerek dışarıda bırakılır. pyproject.toml:113-123 .github/workflows/ci.yml:51, tests/test_static_quality.py:26-35
Ürün kapalı kaynaklıdır. Üçüncü taraf lisansları uyumlu olmalıdır. pyproject.toml:10 lisansı bildirir; bağımlılık yorumları lisansları adlandırır, örneğin pyproject.toml:55-57. Koddan belirlenemedi. CI'da lisans denetimi çalışmaz.
Katkıda bulunanlar bir şey söylemeden veya değiştirmeden önce doğrular ve test edilmemiş işi test edilmiş gibi sunmaz. Süreç kuralı. Koddan belirlenemedi

Kısıtlar ve doğrulama

Yukarıdaki testler iki yerde çalışır. pytest tests/ klasörünü toplar (pyproject.toml:151-153) ve CI onu canlı testler kapalıyken çalıştırır (.github/workflows/ci.yml:99, .github/workflows/ci.yml:124). Tarayıcı kuralları yalnız CI'ın çalıştırmadığı e2e bataryasında çalışır (.github/workflows/ci.yml:21-22). Bkz. Python testleri ve e2e bataryası.

Tutarsızlıklar

İlgili sayfalar


c0d3217 numaralı commit ile 2026-11-14 tarihinde doğrulandı.

Doğrulanan commit c0d3217 · 2026-11-14