Şema dosyalarını bir yıldız haritası olarak çizen, tarayıcıda çalışan açık kaynak görselleştirici.
An open-source, in-browser viewer that draws database schemas as a star map.
sqlSchema, veritabanı şema dosyalarını tarayıcıda okur ve bir gökyüzü haritası olarak çizer:
- Her tablo bir yıldızdır.
- Her ilişki iki yıldız arasında bir çizgidir.
- Her şema bir gökyüzü bölgesi, her veritabanı bir galaksidir.
Yaklaştıkça yıldızlar kolon listeli tablo kartlarına dönüşür ve ilişkiler karga ayağı (crow's foot) notasyonuyla okunur.
draw.io kadar elle uğraştırmaz, veri modelleme aracı kadar ağır değildir. Amaç, şemaya ilk kez bakan birinin "hangi tablo neye bağlı?" sorusunun cevabını birkaç saniyede görmesi.
- Öne çıkanlar
- Hızlı başlangıç
- Haritayı okumak
- Birden fazla dosya ve migration
- Desteklenen veritabanları
- MongoDB
- EF Core (kod öncelikli)
- Adlandırma profili
- Tasarım denetimi
- Belge ve diyagram olarak dışa aktarmak
- KVKK haritası
- Örnekler
- Şemayı dışa aktarmak
- Dil
- Proje yapısı ve geliştirme
- Sınırlar
- Katkı, güvenlik, lisans
- Saf HTML, CSS ve JavaScript. Bağımlılık yok, derleme adımı yok; klasörü açmanız yeterli.
- Gizlilik: dosyalar tarayıcıdan çıkmaz, hiçbir sunucuya gönderilmez.
- Sekiz veritabanı: Oracle, SQL Server, MySQL, MariaDB, PostgreSQL, SQLite, Cassandra ve MongoDB.
- Kod öncelikli projeler: EF Core model özeti (
ModelSnapshot.cs) ve migration geçmişi SQL'e çevirmeden okunur; DBA betikleriyle birlikte açılabilir. - Tek dosya, birden fazla dosya ya da bütün bir klasör: bölünmüş dökümler, migration klasörleri (Flyway, golang-migrate, Prisma, Diesel), çok veritabanlı projeler.
- Karga ayağı notasyonu: kardinalite
NOT NULL,UNIQUEve PK bilgisinden çıkarılır. - Tahmini ilişkiler: FK tanımlı olmayan eski sistemlerde, Cassandra'da ve MongoDB'de bağlantılar kolon adlarından bulunur.
- Adlandırma profili: şemada hangi adlandırma kalıplarının ne oranda kullanıldığını ve baskın kalıba uymayan tabloları gösterir.
- Tasarım denetimi: PK'siz tablo, metin tarih, indekssiz FK gibi hataları neden ve öneriyle listeler.
- Şema farkı ve zaman çizelgesi: iki sürümü karşılaştırır, migration'ları sırayla oynatır.
- Ölçek: 2 900 tablo ve 4 300 FK içeren bir Oracle dökümü, ayrıştırma, yerleşim ve arayüz dahil yaklaşık 0,8 saniyede açılır; bir karenin çizimi 10 ms'nin altında kalır.
- Türkçe ve İngilizce arayüz.
- Depoyu indirin ya da klonlayın.
index.htmldosyasını tarayıcıda açın.- Şema dosyalarınızı ya da klasörü sayfaya sürükleyin. Alternatifler: Dosya aç (birden fazla dosya seçilebilir), Klasör, Yapıştır, Örnekler.
Örnek dosyaları ve sürüklenen klasörleri tarayıcı yalnızca sayfa bir sunucu üzerinden açıldığında okuyabilir. Bunun için proje klasöründe şu komutu çalıştırıp http://localhost:8000 adresine gidin:
python -m http.server 8000
index.htmldoğrudan dosyadan (file://) açıldığında da uygulama çalışır. Klasörleri sürüklemek yerine Klasör düğmesiyle seçin. Gömülü küçük örnek her durumda açılır.
| Hareket | Sonuç |
|---|---|
| Tekerlek / iki parmak | Yakınlaştır |
| Sürükle | Kaydır |
| Tık | Tabloyu seç, ayrıntı panelini aç |
| Çift tık | Tabloya yaklaş, kolonları göster |
/ |
Tablo ya da kolon ara |
F |
Tümünü sığdır |
C |
Kolon ayrıntılarını gizle / göster |
L |
Tablo listesini aç / kapat |
↑ / ↓, Enter |
Paneldeki ilişkiler arasında dolaş, seçilen tabloya git |
Alt + ← / → |
Gezinme geçmişinde geri / ileri |
, / . |
Zaman çizelgesinde önceki / sonraki sürüm |
Esc |
Yolu ya da odak modunu kapat / seçimi bırak |
Yakınlaştırma düzeyine göre üç görünüm vardır:
| Görünüm | Ne görünür |
|---|---|
| Galaksi | Veritabanları, şemalar ve şemalar arası ilişki demetleri (çizgi üstündeki sayı = ilişki adedi) |
| Takımyıldız | Tablolar yıldız olur: boyut = bağlantı sayısı, renk = şema. Seçili tablonun çizgilerinde karga ayağı ve kolon adı yazar. |
| Yakın plan | Tablolar kart olur; çizgiler doğrudan FK ve PK kolon satırlarına bağlanır. |
Görünüm menüsünde tablo listesi, kolon ayrıntıları, tahmini ilişkiler, sözlük bağlantıları, ızgara ve takımyıldız gruplaması seçenekleri var. Kolon ayrıntıları kapatılınca (kısayolu C) yakın planda kartlar yalnızca tablo adını gösterir ve çizgiler kartın başlığına bağlanır. Böylece yalnızca tablolar ve ilişkileri kalır. Ayrıntı paneli kolonları göstermeye devam eder. Seçim tarayıcıda hatırlanır.
Ayrıntı panelinde kolonlar, açıklamalar, tanımın geçtiği dosya ve satır ile her ilişkinin Türkçe okunuşu yer alır: "Her INVOICE kaydı mutlaka bir BILLING_ACCOUNT kaydına bağlı. Bir BILLING_ACCOUNT kaydının sıfır ya da çok INVOICE kaydı olabilir."
Odak modu, seçili tablonun yalnızca 1 ya da 2 adım uzaklıktaki komşularını bırakır, gerisini söndürür.
İlişki izlemek. Paneldeki bir ilişkiye tıklamak (ya da ↓ ile seçip Enter) o tabloya gider. Panelin üstündeki iz gezilen tabloları sırasıyla gösterir (ABONE › IS_EMRI › CIHAZ); izdeki bir ada, ‹ › düğmelerine ya da Alt + ← / → tuşlarına basarak geri ve ileri gidilir. Böylece fareye dokunmadan şema baştan sona gezilebilir.
Tablo listesi. Bütün tabloları şema ve takımyıldız başlıkları altında listeler (Görünüm → Tablo listesi ya da L; varsayılan kapalı):
- Sıra: tablolar ya SQL dosyasında tanımlandıkları sırayla (Dosya sırası) ya da ada göre (A → Z) dizilir.
- Gezinme:
↑/↓ile tablodan tabloya geçilir; seçim, panel ve harita birlikte ilerler. Arama kutusundan↓ile listeye inilir. - Süzme: listenin üstündeki kutu yalnızca listeyi süzer, haritayı değiştirmez.
- İşaretler: her satırda kolon sayısı; PK'si olmayan, ara (M:N), sözlük ve dış tablolar küçük etiketlerle işaretlenir.
- Liste ve lejant aynı kenarı paylaşır; biri açılınca öteki kapanır. Seçim tarayıcıda hatırlanır.
Alt diyagram. Büyük bir şemada yalnızca ilgilendiğiniz tabloları ayrı bir haritada görmek için:
- Seçim: haritada
Ctrl/Cmd+ tık, paneldeki Seçime ekle düğmesi ya da tablo listesindeCtrl/Cmd+ tık. Listedeki takımyıldız başlığındaki + bütün takımyıldızı (ör. bir modül dosyasını) ekler. Seçilen tablolar haritada vurgulu bir halkayla işaretlenir. - Açma: üstte beliren çubukta Alt diyagramı aç. Komşularıyla işaretliyse seçilen tablolara doğrudan bağlı tablolar da gelir.
- Alt diyagramda: yalnızca bu tablolar ve aralarındaki ilişkiler kendi yerleşimiyle çizilir; panel, arama, tablo listesi ve adlandırma profili de yalnızca bu tablolara bakar.
- Dönüş: Tümüne dön ya da
Esc. Tam harita aynı konumlarla geri gelir. - Bağlantı:
?sub=BILLING_ACCOUNT,INVOICE&near=1bu alt diyagramı doğrudan açar. - Kayıtlı görünümler: alt diyagramdayken Kaydet ile ad verilir. Görünümler tarayıcıda, açılan dosya kümesine göre saklanır; aynı dosyalar yeniden açılınca Görünüm → Kayıtlı görünümler altında durur. Dışa aktar bunları
.sqlschema.jsondosyasına yazar, İçe aktar geri okur. Dosya yalnızca görünümü (tablo adlarını) taşır, şemayı içermez; ekip içinde paylaşmak için uygundur.
Etki analizi. "Bu tabloyu değiştirirsem ya da bir satırını silersem ne etkilenir?" Paneldeki Etki analizi düğmesiyle açılır:
- Etkilenenler: tabloya bağlanan bütün tablolar derece derece listelenir (1. derece doğrudan bağlananlar, 2. derece onlara bağlananlar …). Haritada etkilenmeyenler söner, etkilenenler dereceye göre renkli halkayla işaretlenir.
- Silmede ne olur: her bağlantının yanında yazar: birlikte silinir (
ON DELETE CASCADE), boşaltılır (SET NULL), silmeyi engeller (eylemsiz FK), denetlenmez (@ref, tahmini ya da devre dışı FK: veritabanı korumaz, yetim satır kalabilir). - Birlikte silinenler: bir satır silinince CASCADE zinciriyle giden tablolar ayrıca gösterilir.
- Kolon düzeyi: analiz açıkken paneldeki bir kolona tıklamak yalnızca o kolona bağlananları bırakır (ör. PK'nin tipini değiştirmeden önce).
- Paylaşım: Markdown indir sonucu değişiklik öncesi ekiple paylaşmak için dosyaya yazar. Kip seçimi izler; başka bir tabloya geçince analiz onun için yenilenir.
Esckapatır.
Yol bulma. "Bu iki tablo nasıl bağlanıyor?" Paneldeki Yol bul düğmesine basıp hedef tabloya tıklayın (ya da arayın); iki tablo seçiliyken seçim çubuğundaki Yolu göster de olur:
- Haritada: yalnızca yoldaki tablolar ve bağlantılar parlak kalır, kamera yolu ekrana sığdırır.
- Panelde: yol adım adım yazılır:
TICKET_NOTE.TROUBLE_TICKET_ID → TROUBLE_TICKET.TROUBLE_TICKET_ID(FK bu yönde),CUSTOMER.CUSTOMER_ID ← CUSTOMER_ORDER.CUSTOMER_ID(öbür tablo buna başvuruyor). Aynı iki tablo arasında birden fazla bağlantı varsa (fatura ve teslimat adresi) hepsi yazılır. - Seçenekler: en kısa yol her zaman aranan değildir (notu yazan kullanıcı üzerinden siparişe gitmek gibi). Kısadan uzuna beş yol listelenir; ‹ › ile ya da listeden seçilir.
- Neden geçilmez: sözlük tabloları ve
CREATED_BYgibi denetim kolonları her şeyi birbirine bağlar; yoldan sayılmaz, yalnızca uç olabilirler. Tanımlı ilişkiyle yol yoksa tahmini ilişkiler de kullanılır ve bu yazılır. - JOIN SQL'i üretilmez; yol yalnızca hangi tablo ve kolonlardan geçildiğini gösterir.
Esckapatır;?path=PAYMENT_ALLOCATION,ADDRESSbağlantısı yolu açar.
Çizginin bir ucundaki işaret, o uçtaki tablodan kaç kayıt olabileceğini söyler. Tabloya yakın işaret üst sınırdır, dıştaki alt sınırdır.
| İşaret | Anlamı | Şemadan nasıl çıkarılıyor |
|---|---|---|
──‖ |
tam olarak bir | FK kolonu NOT NULL; gömülü belgenin sahibi |
──○┼ |
sıfır ya da bir | FK kolonu NULL olabilir, ya da FK aynı zamanda PK/UNIQUE (1:1) |
──○< |
sıfır ya da çok | FK'yi taşıyan tablonun varsayılanı; ObjectId dizileri |
──┼< |
bir ya da çok | DDL ile zorlanamaz (trigger ya da uygulama kuralı gerekir), bu yüzden haritada çıkmaz |
| Çizgi | Anlamı |
|---|---|
| Düz | Tanımlı yabancı anahtar ya da Mongoose ref |
| Uzun kesikli | Kolon açıklamasındaki @ref etiketiyle tanımlı ilişki (aşağıya bakın) |
| Kesikli | Tahmini ilişki (aşağıya bakın); Görünüm menüsünden kapatılabilir |
| Noktalı | Devre dışı FK (DISABLE, RELY DISABLE NOVALIDATE, T-SQL NOCHECK) |
| Kesik-noktalı | MongoDB gömülü belge: alt belge sahibinin içinde yaşar |
| Yıldız | Anlamı |
|---|---|
| Dolu yıldız | Tablo; büyüklük = bağlantı sayısı, renk = şema |
| Halka | Ara tablo (M:N): PK'si iki FK'den oluşur ya da saf bağlantı tablosudur |
| Küçük, soluk yıldız | Uydu: MongoDB gömülü alt belgesi, sahibinin yanında durur |
| Kesikli halka | Bir FK'nin başvurduğu ama dosyalarda tanımı olmayan tablo |
Kartlarda PK birincil anahtarı, FK yabancı anahtarı, CK Cassandra sıralama (clustering) anahtarını gösterir. Soluk kolon adı, kolonun NULL olabileceği anlamına gelir.
Takımyıldızlar. Küçük şemalar tek bir takımyıldızdır. Büyük şemalar, tablo adı öneklerine (CUSTOMER_*, INVOICE_*) ve bağlantılara göre takımyıldızlara bölünür. Her yıldız, takımyıldızındaki parlaklık sırasına göre Bayer usulü bir ad alır (α Billing, β Billing). Yerleşim deterministiktir: aynı dosyalar her açılışta aynı haritayı verir.
Tahmini ilişkiler. Şu iki durumda kesikli çizgiyle çizilir:
- FK tanımlı değil ama kolon adı başka bir tablonun PK'siyle aynı:
CDR.SUBSCRIPTION_ID→SUBSCRIPTION.SUBSCRIPTION_ID. X_ID/xIdkolonu, PK'siIDya da_idolan X tablosunu gösteriyor:orders.customerId→customers._id.
Tipler uyuşmuyorsa ya da birden fazla aday varsa çizilmez.
Açıklamadan ilişki: @ref. Bazı ilişkiler FK ile tanımlanamaz. En sık örnek, genel bir sözlük tablosunun (SOZLUK: ID, TIP_ID, AD) yalnızca bir tipine bağlanan kolonlardır. Veritabanı "yalnızca TIP_ID = 7 olan satırlar" diye bir kısıt koyamaz. Bu ilişkiler kolon açıklamasına yazılan bir etiketle haritaya eklenir:
COMMENT ON COLUMN ABONE.DURUM_ID IS 'Abone durumu. @ref SOZLUK.ID (TIP_ID = 7)';
COMMENT ON COLUMN SESSION_LOG.USERID IS 'The user ID. @ref USERS';| Yazım | Anlamı |
|---|---|
@ref TABLO |
Hedefin birincil anahtarına |
@ref TABLO.KOLON |
Hedefin belli bir kolonuna (TABLO.KOLON yoksa ŞEMA.TABLO sayılır) |
@ref ŞEMA.TABLO.KOLON |
Şemayla birlikte |
… (KOŞUL) |
Parantez içi koşul çizginin ve panelin üstüne yazılır |
- Nereden okunur: etiket açıklamanın herhangi bir yerinde olabilir. Oracle ve PostgreSQL
COMMENT ON COLUMN, MySQL satır içiCOMMENT '…'ve SQL Serversp_addextendedpropertyaçıklamaları okunur. - Haritada: bu ilişkiler tahmin değil, DBA'nın beyanıdır; uzun kesikli çizgiyle ve panelde "açıklamadan" etiketiyle gösterilir.
- FK ile birlikte: kolonda zaten bir FK varsa yalnızca koşul ona eklenir.
- Hata: bulunamayan bir hedef ayrıştırma raporunda uyarı olarak listelenir.
Sigorta örneğinde durum kolonları genel kod tablosuna (KOD_TABLO) bu yolla bağlanır.
Sözlük tabloları. Genel kod tablosuna yüzlerce kolon bağlandığında çizgiler haritayı boğar ve sözlük dev bir merkez olur. Bu yüzden en az iki koşullu ilişkinin hedefi olan tablo sözlük sayılır:
- Haritada: ona giden çizgiler çizilmez. Kartta kolonun tipi yerine
→ KOD_TABLOrozeti görünür. Çizgi yalnızca sözlük ya da bağlanan tablo seçilince ya da üzerine gelinince çizilir. - Yerleşimde: sözlük ilişkileri tabloları birbirine çekmez; sözlük şemanın ortasına oturup öbürlerini sıkıştırmaz.
- Panelde: sözlük seçilince Sözlük kullanımı bölümü hangi koşulun hangi kolonlarca kullanıldığını listeler (
KOD_TIP = 'POLICE_DURUM'→POLICE.POLICE_DURUM). - Elle seçim: paneldeki Sözlük olarak göster / Sözlük değil düğmesi otomatik kararı değiştirir; seçim tarayıcıda hatırlanır.
- Çizgi olarak: Görünüm → Sözlük bağlantılarını çiz ile çizgiler her zaman çizilir.
Sözlük ağırlıklı örneğinde 30'dan fazla kolon tek bir SOZLUK tablosuna bağlıdır.
Kod değerleri. Kodların anlamı her zaman ayrı bir tabloda durmaz; çoğu zaman doğrudan kolon açıklamasına yazılır:
COMMENT ON COLUMN MUSTERI.MUSTERI_TIP IS 'G = Gerçek kişi, T = Tüzel kişi';
COMMENT ON COLUMN HASAR_IHBAR.IHBAR_KANAL IS 'İhbarın geldiği kanal: ACN = Acente, CAG = Çağrı merkezi, WEB = İnternet şubesi';- Tanınan yazımlar:
1 = Aktif, 2 = Pasif·A: Aktif; P: Pasif·E-Evet / H-Hayır·Durum (1=Aktif, 2=Pasif)·0 => kapalı, 1 => açık. - Yanlış yakalamaya karşı: en az iki çift, aynı ayraç ve kod gibi görünen kısa kodlar aranır. "Not: eski alan, Kaynak: SAP" ya da "Sürüm 2 = yeni biçim" liste sayılmaz.
- Panelde: değerler kolonun altında kutucuk olarak görünür; açıklamanın listede olmayan kısmı ("İhbarın geldiği kanal") ayrı yazılır.
- Kartta: kolon adının yanında küçük bir
≡işareti. - Aramada: değerlerin anlamı da aranır. "iptal" yazınca
4 = İptaldeğerini tutan kolon bulunur; büyük/küçük harf ve Türkçe karakter farkı yok sayılır.
İzin verilen değerler başka yerlerde de tanımlı olabilir; hepsi aynı kutucuklarla gösterilir ve kaynağı yanına yazılır:
| Kaynak | Örnek |
|---|---|
CHECK kısıtı |
CHECK (MUSTERI_TIP IN ('G', 'T')) · SQL Server: CHECK (([Gender]='F' OR [Gender]='M')) |
ENUM tipi |
MySQL status enum('active','passive') |
MongoDB enum |
$jsonSchema ve Mongoose alanlarındaki enum: ['tr', 'en'] |
Değerler kısıttan ya da tipten geliyor, anlamları açıklamada yazılıyorsa ikisi birleşir: CHECK (MUSTERI_TIP IN ('G','T')) ile 'G = Gerçek kişi, T = Tüzel kişi' açıklaması G Gerçek kişi · T Tüzel kişi olarak görünür. Aralık (BETWEEN), karşılaştırma (> 0) ve birden fazla kolonlu koşullar değer listesi sayılmaz.
Sözlük verisi. Dosyalarda sözlük tablosunun INSERT satırları da varsa, @ref SOZLUK.ID (TIP_ID = 7) ile bağlı kolonun altında o tipin değerleri görünür (1 Aktif · 2 Pasif …; kaynak: "sözlükten: SOZLUK · TIP_ID = 7"):
- Kod ve anlam: kod bağlantının hedef kolonundan, anlam
AD,ACIKLAMA,NAMEgibi bir kolondan alınır. - Koşul: yalnızca
KOLON = değereşitlikleri (ANDile birden fazla) uygulanır. - Koşulsuz sözlük bağlantısı: değer gösterilmez, çünkü sözlüğün hangi tipinin geçerli olduğu bilinemez. Sözlük olmayan küçük tablolara giden düz FK'lerde tablonun bütün satırları değer olur.
- Sınır: yalnızca düz
INSERT … VALUESokunur,INSERT … SELECTokunmaz. Büyük veri dökümlerinde tablo başına ilk 2 000 satır alınır.INSERT'ler yine çizime girmez, raporda sayılır. - Öncelik: kolonun kendi
CHECKya da açıklama listesi önceliklidir; orada anlamı yazılmamış kodların anlamı sözlükten tamamlanır.
Dosyalar tek bir modelde birleşir; ad çözümleme en sonda yapılır. Bu yüzden şu durumlar sorun çıkarmaz:
- Bir dosyadaki FK'nin başka bir dosyadaki tabloyu göstermesi.
constraints.sqldosyasının alfabetik sıradaddl.sql'den önce gelmesi.
Sağ alttaki N dosya bağlantısı dosya listesini açar. Burada:
- Dosyaları tek tek çizime katabilir ya da çıkarabilirsiniz.
- Her dosyanın lehçesini ve kaç tablo içerdiğini görürsünüz.
- "Ayrı veritabanı" seçeneğini açabilirsiniz.
Dosya başına takımyıldız. Bir şemanın tabloları birden fazla dosyadan geliyorsa, her dosyanın tabloları kendi takımyıldızında toplanır. Ekipler modülleri çoğunlukla dosyalara ayırdığı için harita da bu ayrımı korur.
- Ayrı dururlar: farklı dosyaların takımyıldızları, aralarında ilişki olsa da birbirinden açıkça uzak durur.
- Sınır ve ad: her takımyıldız ince bir daireyle sınırlanır ve adı sınırın üstüne yazılır.
- Ad: dosya yolundan gelir; aynı adlı dosyalar klasörleriyle ayrılır (
POLICE/tablolar,HASAR/tablolar).
Migration klasörlerinde dosya bir modülü değil bir sürümü gösterir; orada ve MongoDB'de tablolar ad öneki ve ilişkiye göre gruplanır. Görünüm → Takımyıldızlar ile seçim elle değiştirilebilir: Otomatik, Dosyaya göre ya da Ad ve ilişkiye göre.
Okuma sırası migration araçlarının kurallarını izler:
| Araç | Dosyalar | Davranış |
|---|---|---|
| Flyway | V1__init.sql, V1_1__x.sql, V2__y.sql |
Sürüm numarasına göre (V10, V2'den sonra). R__*.sql en sonda, U*__ geri alma betikleri atlanır. |
| golang-migrate, dbmate | 000001_x.up.sql |
.down.sql atlanır. |
| Zaman damgalı | 20240115093000_x.sql |
Zaman sırasına göre. |
| Prisma | 20240115093000_init/migration.sql |
Sürüm klasör adındadır; klasör sırasına göre. Zaman çizelgesinde sürüm adı klasör adıdır. |
| Diesel | 2024-01-15-093000_init/up.sql |
Klasör sırasına göre; down.sql atlanır. |
| EF Core | 20240115093000_Initial.cs |
Zaman sırasına göre; Up() okunur, .Designer.cs ve model özeti atlanır (bkz. EF Core). |
| Numaralı / diğer | 01_tables.sql, a2.sql < a10.sql |
Doğal ad sırası. |
Migration'lar baştan sona uygulanır ve harita şemanın son hâlini gösterir. Bunun için şu ifadeler işlenir:
RENAME TO,RENAME COLUMNDROP TABLE,DROP COLUMN,DROP CONSTRAINTALTER COLUMN … TYPE,MODIFY,CHANGE- T-SQL
sp_rename, MySQLRENAME TABLE
Şema farkı. Alt bilgi çubuğundaki karşılaştır, açık dosyaları (sonra) önceki bir sürümle (önce) karşılaştırır:
- Önceki sürüm: migration klasöründe bir sürüm seçilir ("V7'ye kadarki hâliyle") ya da önceki sürümün dosyaları / klasörü ayrıca seçilir (ör. prod dökümü ile test dökümü).
- Haritada: eklenen tablolar yeşil, silinenler kırmızı, değişenler sarı; adı değişenlerin çevresinde mavi halka var. Değişmeyenler geri planda kalır. Silinen tablolar da haritada yerinde görünür.
- Panelde: seçili tablonun farkı: eklenen, silinen ve değişen kolonlar (tip, NULL, varsayılan, PK), adı değişen kolonlar, PK, FK ve UNIQUE farkları. Kartta eklenen ve değişen kolon satırları renklenir.
- Ad değişikliği tahmini: tablolar kolon kümesinin benzerliğiyle (
customer→customers), kolonlar tip ve ad benzerliğiyle (weight→weight_grams) eşleştirilir; tahmin olduğu yazılır. Adı değişen kolonun FK'si değişmiş sayılmaz. - Rapor: Markdown indir değişiklik listesini sürüm notu ya da inceleme için dosyaya yazar.
- Bağlantı:
?diff=V3migration klasöründe o sürümle karşılaştırmayı açar.
ALTER taslağı. Karşılaştırma ya da zaman çizelgesi açıkken karşılaştır penceresindeki ALTER taslağı, önceki sürümü sonrakine getiren SQL betiğini lehçeye göre yazar:
- Bağımlılık sırası: kaldırılan FK ve kısıtlar, ad değişiklikleri, yeni tablolar, eklenen ve değişen kolonlar (tip, NULL, varsayılan), birincil anahtarlar, kaldırılan kolonlar, yeni kısıt ve indeksler, kaldırılan tablolar.
- Notlar: tahmin edilen ad değişikliği, dosyada adı olmayan kısıt, varsayılansız
NOT NULL, veri dönüştürme gerektiren tip değişikliği adımın üstüne yorum olarak yazılır. - Güvenli varsayılan: veri kaybettiren adımlar (kolon ve tablo kaldırma) yorum satırıdır; kutu kaldırılınca açılır.
- Sınır: taslaktır; veri taşıma yazılmaz. Çalıştırmadan önce okuyun ve test ortamında deneyin.
- Bağlantı:
?diff=V3&alter=1taslağı açar.
Zaman çizelgesi. Migration klasöründe karşılaştır penceresindeki Zaman çizelgesi, sürümleri sırayla oynatır:
- Sabit harita: yerleşim bütün sürümlerdeki tablolardan bir kez kurulur. Adım değişince tablolar yerinde kalır, kamera oynamaz; yalnızca o sürümde var olan tablolar çizilir.
- Her adım bir fark: o sürümün bir öncekine göre eklediği, değiştirdiği ve sildiği tablolar şema farkındaki renklerle görünür. karşılaştır penceresi o adımın listesini ve Markdown raporunu verir.
- Gezinme: kaydırıcı, ‹ › düğmeleri ya da
,/.tuşları; ▶ sürümleri sırayla oynatır. - Tablo geçmişi: seçili tablonun panelinde, oluştuğu, değiştiği ve silindiği sürümler listelenir (
V4__plural_table_names ad: shipment → shipments). Bir satıra tıklayınca o sürüme gidilir. Adı değişen tablo seçili kalır. - Bağlantı:
?time=V4çizelgeyi o sürümde açar.
Ayrı veritabanları. Farklı lehçelerden dosyalar birlikte açılırsa (örneğin MySQL siparişler, MongoDB katalog, PostgreSQL raporlama) her klasör kendi galaksisi olarak çizilir.
| Oracle | SQL Server | MySQL / MariaDB | PostgreSQL | SQLite | Cassandra | |
|---|---|---|---|---|---|---|
CREATE TABLE, satır içi ve tablo seviyesi kısıtlar |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ PRIMARY KEY ((a, b), c) |
ALTER TABLE … ADD CONSTRAINT |
✓ | ✓ WITH CHECK/NOCHECK |
✓ | ✓ ONLY |
||
| Kolon değişiklikleri | MODIFY |
ALTER COLUMN |
MODIFY, CHANGE |
ALTER COLUMN … TYPE |
||
| Yeniden adlandırma, silme | RENAME, DROP |
sp_rename, DROP |
RENAME TABLE, DROP |
RENAME, DROP |
RENAME, DROP |
|
CREATE UNIQUE INDEX (1:1 tespiti) |
✓ | ✓ | ✓ | ✓ | ✓ | |
| Tablo / kolon açıklamaları | COMMENT ON |
sp_addextendedproperty |
COMMENT '…' |
COMMENT ON |
Veritabanı türü nasıl anlaşılır. Seçmeniz gerekmez; her dosyada yalnızca o veritabanına özgü ifadeler sayılır ve en çok puan alan seçilir:
| Veritabanı | Bakılan ipuçları |
|---|---|
| Oracle | VARCHAR2, NUMBER(…), TABLESPACE, SYSDATE, PCTFREE, NOVALIDATE, satırda tek başına / |
| SQL Server | [dbo], satırda tek başına GO, NVARCHAR, IDENTITY(…), CLUSTERED, DATETIME2, sp_addextendedproperty |
| MySQL / MariaDB | `ters tırnak`, ENGINE=, AUTO_INCREMENT, DEFAULT CHARSET, UNSIGNED; MariaDB döküm başlığından |
| PostgreSQL | SERIAL, ::tip, $$, TIMESTAMPTZ, JSONB, OWNER TO, character varying, ALTER TABLE ONLY |
| SQLite | AUTOINCREMENT, WITHOUT ROWID, PRAGMA |
| Cassandra | .cql uzantısı, CREATE KEYSPACE, WITH CLUSTERING ORDER, frozen<, map< |
DATE, INTEGER, VARCHAR gibi her veritabanında bulunan tipler ayırt etmeye yaramadığı için sayılmaz. İpucu taşımayan sade bir CREATE TABLE dosyası, aynı klasördeki dosyaların baskın türünü alır. MongoDB dosyaları uzantıdan ve içerikten ($jsonSchema, new Schema(…), JSON belgeleri) tanınır.
Çizime girmeyenler. View, sequence, trigger, package, procedure, function, type, grant ve INSERT raporda sayılır ama çizilmez (INSERT … VALUES satırları yalnızca sözlük değerleri için okunur). Ayrıştırıcı bunların içindeki ; işaretlerine takılmaz:
- PL/SQL blokları
/satırına kadar bütün tutulur. - T-SQL blokları
GOsatırına kadar bütün tutulur. - MySQL blokları
DELIMITERayracına kadar bütün tutulur.
Sorun çıkarmayanlar:
- SQL*Plus komutları
- Oracle depolama ve partition ifadeleri
- PostgreSQL
$$gövdeleri vePARTITION OFparçaları - CQL
//yorumları vemap<text, int>tipleri
Kodlama. Dosya UTF-8, UTF-16 (SSMS'in varsayılanı) ya da Windows-1254 olabilir; kodlama otomatik seçilir.
MongoDB'de DDL yoktur. Şema üç kaynaktan çıkarılır; aynı koleksiyon birden fazla kaynakta geçiyorsa tek tabloda birleşir.
| Kaynak | Örnek | Okunan |
|---|---|---|
mongosh betikleri (.js) |
db.createCollection('x', { validator: { $jsonSchema } }), collMod, createIndex(…, { unique }) |
Alanlar, tipler, zorunlu alanlar, açıklamalar, enum değerleri |
Mongoose modelleri (.js, .ts) |
new Schema({ author: { type: ObjectId, ref: 'User' } }) |
Alanlar ve ref ilişkileri. Koleksiyon adları Mongoose'un çoğul kurallarıyla türetilir. |
Örnek belgeler (.json, .jsonl, .ndjson) |
mongoexport çıktısı |
İlk 5 000 belgeden alan birleşimi; Extended JSON ($oid, $date) |
Gömülü nesneler ve nesne dizileri, sahibinin yanında duran uydu tablolara (users.profile, orders.items) dönüşür.
Şeması .NET kodunda tanımlı projelerde (Entity Framework Core) SQL dosyası gerekmez: EF'in ürettiği model özeti Migrations/<Bağlam>ModelSnapshot.cs doğrudan okunur. Dosya araç tarafından üretildiği için düzenlidir ve modelin tamamını tek yerde tutar; kod çalıştırılmaz. Projenin klasörünü olduğu gibi açabilirsiniz: entity sınıfları, .Designer.cs dosyaları, appsettings.json, bin/ ve obj/ atlanır.
| Snapshot'ta | Haritada |
|---|---|
ToTable("Dealers", "sales"), HasDefaultSchema |
Şema ve tablo adı |
Property<int?>, IsRequired, HasColumnType, HasColumnName, HasDefaultValue(Sql), HasComment |
Kolon, tip, NULL, varsayılan, açıklama |
HasKey, HasAlternateKey, HasIndex(...).IsUnique(), HasCheckConstraint |
PK, UNIQUE, indeks, CHECK değer listesi |
HasOne(...).WithMany / WithOne().HasForeignKey(...), OnDelete |
FK ve silme davranışı (bire bir, bileşik anahtar, HasPrincipalKey) |
OwnsOne / OwnsMany |
Aynı tabloda Address_City gibi kolonlar ya da kendi tablosu |
HasBaseType |
TPH (temel tabloya, kolonlar NULL olabilir), TPT (kendi tablosu ve temel tabloya FK), TPC (temel kolonlar kopyalanır) |
| Çoka çok | EF'in ürettiği ara tablo (DealerRegion) |
- Sağlayıcı: SQL Server, PostgreSQL (Npgsql), Oracle, MySQL ve SQLite snapshot'taki ek sınıf adlarından, olmazsa kolon tiplerinden anlaşılır.
- Karma projeler: DBA betikleri (
.sql) aynı klasörde ya da birlikte açılabilir; betikteki FK'ler EF tablolarına bağlanır. Panelde EF'ten gelen tabloların EF Core etiketi vardır; hangi tablonun kodda, hangisinin yalnızca DBA betiğinde tanımlı olduğu bir bakışta anlaşılır. - Migration geçmişi: klasörde
20240115093000_Initial.csgibi migration dosyaları varsa her biri bir sürümdür veUp()içindekimigrationBuilderçağrıları okunur (CreateTable,AddColumn,AlterColumn,RenameColumn,RenameTable,CreateIndex,AddForeignKey,DropTable…;Sql("...")içindeki ham SQL de). Zaman çizelgesi, şema farkı, değişiklik incelemesi ve komut satırındaki--since 20240610150000_DealerStatusAndVknEF projesinde SQL'siz çalışır. Bu durumda model özeti son hâlin kopyası olduğu için atlanır. - Okunmayanlar:
ToViewile görünüme bağlanan varlıklar,HasDatatohum verisi ve migration'larınDown()yöntemi.
Ekipte yazılı bir adlandırma standardı yoksa ilk adım, şemada fiilen ne kullanıldığını görmektir. Sağ alttaki adlandırma bağlantısı adları şu boyutlarda sayar ve oranlarıyla gösterir:
| Boyut | Kalıplar |
|---|---|
| Tablo ve kolon adı harf düzeni | BÜYÜK_HARF, küçük_harf, PascalCase, camelCase |
| Birincil anahtar adı | ID, <TABLO>_ID, <TABLO>_NO / _KOD, tablo adıyla ilgisiz |
| Yabancı anahtar kolonu | <HEDEF>_ID, <HEDEF>_NO / _KOD, rol önekli (GONDEREN_MUSTERI_ID, AGENT_USER_ID → APP_USER), hedefin PK adıyla aynı, yalnızca rol adı (SAHIBI), hedef adını içermeyen (CHZ_REF) |
| Tablo adı | tekil / çoğul (tahmini), TBL_ gibi önekler |
| Karakterler ve uzunluk | Türkçe / ASCII dışı karakter, 30 karakteri aşan adlar |
| Veri tipleri | tarih kolonları (tarih tipi, metin, YYYYMMDD sayı), tutar kolonları (ondalık, tamsayı, FLOAT, metin), evet / hayır kolonları (BOOLEAN, E/H, Y/N, 0/1, değerleri yazılmamış CHAR(1) / NUMBER(1)) |
- Her boyutta baskın kalıp ve ona uymayanlar listelenir. Listedeki bir ada tıklamak tabloyu seçer.
- En çok kullanılan kalıbın payı %60'ın altındaysa "baskın" denmez; pencere belirgin baskın kalıp yok uyarısı gösterir. %51'e %49 gibi bir dağılım, şemada iki ayrı alışkanlık olduğunu söyler.
- Kapsam seçimiyle profil tek bir şema için hesaplanır. Böylece hangi modülün hangi alışkanlıkla yazıldığı ayrılır.
- Tutarlılık puanı, her boyutta baskın kalıba uyan adların ortalama oranıdır. Veri tipleri puana katılmaz.
- Veri tipleri bölümü aynı anlamdaki kolonların hangi tiplerle tutulduğunu gösterir. Tarih ve tutar kolonları addan tahmin edilir; tasarım denetimi aynı sınıflandırmayı kullanır. Böylece "tarihlerin %8'i metin" gibi bir oran, denetimin tek tek bulduğu kolonların toplamını verir.
- Haritada: her boyutun başlığındaki haritada düğmesi haritayı o boyuta göre boyar; her kalıp penceredeki rengini alır. Baskın kalıba uymayan bir öğesi olan tablo o kalıbın rengiyle öne çıkar. Kolon düzeyindeki boyutlarda (harf düzeni, FK, karakter) kartta ilgili kolon satırları da renklenir. Böylece hangi ekibin şemanın neresini yazdığı bir bakışta görünür.
?style=pkStylebu görünümü açar. - Markdown indir profili ekiple paylaşmak için bir dosyaya yazar.
Araç bir kural dayatmaz: ID mi <TABLO>_ID mi doğru, buna ekip karar verir.
Orana katılmayanlar:
- Bileşik PK'ler, PK'si üst tablodan gelen 1:1 tablolar ve PK'siz tablolar. Bunlar ayrıca gösterilir.
CREATED_BY,UPDATED_BY,GUNCELLEYEN,KAYIT_KULLANICIgibi denetim kolonları. Kullanıcı tablosuna bağlı olsalar da kendi yerleşik kalıpları vardır; ayrıca sayılırlar.- Tahmini ilişkiler: zaten ada dayandıkları için yalnızca tanımlı FK'ler sayılır.
- MongoDB koleksiyonlarının
_idverefalanları.
Karışık adlandırma örneği bu özellik için hazırlanmıştır: iki ekibin farklı alışkanlıklarla tablo eklediği bir Oracle şeması.
Sağ alttaki denetim bağlantısı şemayı yaygın tasarım hatalarına karşı tarar. Her bulgu üç şey söyler:
- Ne: "
BASLANGIC_TARkolonuVARCHAR2(20)" - Neden sorun: tarih metin olunca aralık sorguları indeks kullanamaz, sıralama yanlış olur
- Öneri:
DATEya daTIMESTAMPkullanın
Kurallar dört grupta toplanır:
| Grup | Örnek kurallar |
|---|---|
| Anahtarlar ve bütünlük | PK'siz tablo, FK ile hedef kolonun tipi uyuşmuyor, tanımlanmamış ilişki, indeksi olmayan FK, döngüsel FK zinciri, gereksiz indeks, devre dışı FK, bulunamayan @ref hedefi |
| Veri tipleri | metin tarih, metin sayı, FLOAT tutar, gereğinden geniş metin, değişken veri için CHAR, kısa metin için CLOB, aynı adlı kolonların farklı tipi, farklı biçimlerde mantıksal kolonlar (E/H, Y/N, 0/1) |
| Normalizasyon | TEL1, TEL2, TEL3 gibi tekrarlayan kolonlar, virgülle ayrılmış liste, anahtar-değer (EAV) tablosu, çok kolonlu tablo |
| Adlandırma | ad sınırını aşan ad (Oracle 12.1 ve öncesinde 30), ayrılmış kelime, Türkçe karakter, SYS_C0012345 gibi sistem adları; PK, FK ve harf düzeninde baskın kalıba uymayanlar |
- Önem: hata, uyarı ve bilgi. Addan tahmin yürüten kurallar (metin tarih, tutar, EAV ...) addan tahmin olarak işaretlenir.
- Yanlış alarmı azaltmak için:
- Kayıt, geçmiş ve olgu tablolarında (
_LOG,_HIST,_CDR,FACT_) PK ve FK yokluğu bilinçli sayılır. - SQLite'ta metin tarih olağandır.
- Rol adlı FK'ler (
FATURA_ADRES_ID) ve metin tipli doğal anahtarlar (PARA_BIRIMI_KOD) kalıp dışı sayılmaz. - Dosyalarda hiç indeks tanımı yoksa FK indeksi denetlenmez.
- Kayıt, geçmiş ve olgu tablolarında (
- Haritada göster: hatalı tablolar kırmızı, uyarılılar sarı; öbürleri geri planda kalır. Kartta bulgusu olan kolon satırları renklenir.
- Panelde: seçili tablonun bulguları ve önerileri Denetim bölümündedir.
- Pencerede: en çok bulgu olan on tablo listelenir. Markdown indir bütün bulguları neden ve öneriyle bir inceleme belgesine yazar.
- Zaman çizelgesiyle: her sürümde denetim yeniden hesaplanır; bir bulgunun hangi migration'la geldiği görünür.
- Bağlantı:
?audit=1denetimi haritada açar,?pop=auditpencereyi açar.
Standart ve kurallar. Adlandırma profili şemanın fotoğrafıdır; standart ise ekibin kararıdır. adlandırma penceresindeki Standart öner (ya da denetim penceresindeki Standart ve kurallar) profilden bir standart önerir:
- Öneri: her boyutta baskın kalıp belirginse (%60 ve üstü) o önerilir: tablo ve kolon harf düzeni, PK adı, FK kolonu, tekil / çoğul. Değilse öneri boş kalır, seçenekler oranlarıyla gösterilir ve pencere "ekip karar vermeli" der. Rol önekli FK her standartta kabul edilir.
- Zorunlular: ad uzunluğu sınırı (Oracle'da 30 önerilir), yalnızca ASCII, açıklama zorunluluğu (tablolar ya da tablolar ve kolonlar), denetim kolonları (ör.
CREATED_AT, CREATED_BY). - Kuralların önemi: her denetim kuralı hata, uyarı, bilgi ya da kapalı yapılabilir.
- Etkisi: kaydedilince denetim baskın kalıp yerine standarda göre yapılır ("PK adı kalıba uymuyor: _ID (standart: ID)"). Standarda bağlı üç kural yalnızca standartta tanımlıysa çalışır: tekil / çoğul, eksik açıklama, eksik denetim kolonu.
- Paylaşmak: standart, borç kaydıyla aynı
<ad>.sqlschema.jsonproje dosyasına yazılır. Klasörü açan herkes ve komut satırı aynı standardı kullanır. - Standart belgesi: pencerenin Standart belgesi düğmesi ekibe gönderilecek bir Markdown belge üretir: tablo ve kolon adları, PK (en sık tipiyle), FK, kısıt adları, zorunlular, anahtar ve veri tipi önerileri, kuralların önem tablosu. Her maddede doğru örnekler standarda uyan adlardan, yanlış örnekler o standartla yapılan denetimin bulgularından, yani ekibin kendi şemasından seçilir. Henüz kaydedilmiş standart yoksa belge öneriden üretilir ve bunu söyler.
?doc=1belgeyi açar.
Borç kaydı: geçmişi affet, geleceği denetle. Dağınık bir veritabanında ilk denetim yüzlerce bulgu çıkarır; yüzlerce eski tabloyu bir anda düzeltmek de gerçekçi değildir.
- Kabul etmek: pencerede Mevcut bulguları borç olarak kabul et o anki bulguları kaydeder. Kayıttaki bulgular ayrı bir Kabul edilmiş borç listesinde durur, hata sayılmaz ve haritada renk almaz. Bundan sonra yalnızca yeni bulgular öne çıkar: yeni bir migration'ın getirdiği PK'siz tablo hemen görünür.
- İlerleme: düzeltilen bulgular ödenen borç olarak sayılır; çubuk borcun ne kadarının ödendiğini gösterir.
- Ekiple paylaşmak: Proje dosyasını indir borç kaydını (ve kayıtlı görünümleri)
<ad>.sqlschema.jsondosyasına yazar. Dosyayı şema klasörüne koyup depoya ekleyin: klasörü açan herkes aynı borcu görür. Dosya şemayı içermez. - Saklama: kayıt tarayıcıda proje adına göre de tutulur; yeni migration eklenince kaybolmaz. Klasördeki dosya ile tarayıcıdaki kayıttan daha yeni olanı geçerlidir.
- Kimlik: bir bulgu kural, tablo ve kolon adıyla eşleşir. Tablonun adı değişirse bulgu yeni sayılır.
Düzeltme önerileri. Pencerede Düzeltme betiği düzeltilebilen bulgular için lehçeye uygun SQL üretir (Oracle, PostgreSQL, SQL Server, MySQL / MariaDB, SQLite):
- Ne üretilir:
- eksik FK ve FK indeksi; Oracle'da
ENABLE NOVALIDATE, PostgreSQL'deNOT VALID, SQL Server'daWITH NOCHECKseçeneğiyle - devre dışı FK'yi açma (önce yetim kayıtları bulan sorgu)
- gereksiz indeksi kaldırma
- PK ekleme (kolon adı şemanın baskın PK adlandırmasını izler)
- FK kolonunu genişletme
- metin tarih, metin sayı,
FLOATtutar veCLOBdönüşümü: yeni kolon, kopyalama, doğrulama, eski kolonu kaldırma, yeniden adlandırma - sistem adlı kısıtları ve Türkçe karakterli, harf düzeni farklı ya da belirsiz adlı kolonları yeniden adlandırma
- eksik FK ve FK indeksi; Oracle'da
- Risk: her öneri güvenli (indeks, FK, kısıt adı), gözden geçirin (PK ekleme, indeks kaldırma, tip genişletme) ya da riskli (veri dönüşümü, ad değişikliği) olarak işaretlenir. Riskliler varsayılan olarak betiğe girmez.
- Notlar: her adımın üstünde açıklama vardır ("tarih biçimini verinize göre değiştirin", "bu adı kullanan uygulama kodu da güncellenmeli"). Veri temizlendikten sonra çalıştırılacak doğrulama adımları yorum olarak yazılır. Tablo adını değiştiren adımlar en sondadır.
- Elle düzeltilenler: döngü, EAV, tekrarlayan kolonlar ya da yeni bir ad seçmeyi gerektiren bulgular için SQL üretilmez; tasarım kararı gerektirir.
- Kullanım: borç kaydı varsa yalnızca yeni bulgular için üretilir. Betik kopyalanır ya da
.sqlolarak indirilir. Panelde her bulgunun altında kendi SQL'i de görünür. - Sınama: testler üretilen betiği örneklere yeni bir migration olarak ekleyip yeniden denetler; düzeltilen bulguların kaybolduğunu ve yeni bulgu çıkmadığını doğrular.
Değişiklik incelemesi (PR). Hatayı canlıya çıkmadan, yeni migration'ın PR'ında yakalamak için:
- Açmak: bir karşılaştırma (önce → sonra) ya da zaman çizelgesi açıkken karşılaştır penceresindeki İnceleme raporu. Denetim penceresinin başında da bu değişikliğin özeti görünür.
- Ne sayılır: "sonra"da olup "önce"de olmayan bulgular bu değişiklikle gelmiştir; tersi giderilmiştir. Adı değişen tablolar eşlenir: eski bulgu yeni adıyla "yeni" görünmez. Borç kaydındakiler sayılmaz. Önce denetlenemeyen bir kural (dökümde indeks yoktu) sonra çalışırsa değişmeyen tablolardaki bulguları yeni sayılmaz.
- Rapor: PR yorumuna yapıştırılacak Markdown. Eklenen, değişen ve silinen tablo sayıları; önem sırasıyla yeni bulgular; giderilenler. İsteğe bağlı olarak güvenli ve gözden geçirilecek düzeltme SQL'i katlanır bir bölümde.
- Bağlantı:
?diff=V14&review=1raporu açar.
Komut satırı ve CI. Aynı denetim, borç kaydı ve değişiklik incelemesi tarayıcı olmadan da çalışır; böylece PR'lar elle incelenmeden atlanmaz:
node tools/sqlschema-lint.js db/migration --since V15 --format md --fail-on error| Seçenek | Görevi |
|---|---|
<dosya|klasör>... |
denetlenecek şema; klasörler özyinelemeli taranır |
--since V15 |
migration klasöründe V15 ve sonrasını incele (önce = V15'ten öncekiler) |
--baseline <yol> |
bu kopyayla karşılaştırarak incele (ör. ana dalın şeması) |
--project <dosya> |
proje dosyası (standart, kural önemleri, borç); verilmezse klasördeki *.sqlschema.json okunur |
--format text|md|json|sarif |
metin, PR yorumu için Markdown, JSON ya da GitHub kod taraması için SARIF |
--fail-on error|warning|info|none |
bu önemde yeni bulgu varsa çıkış kodu 1 (varsayılan error) |
--fix <dosya> |
güvenli ve gözden geçirilecek düzeltme SQL'ini dosyaya yaz |
--out <dosya>, --lang tr|en, --separate |
çıktı dosyası, dil, klasörleri ayrı veritabanı sayma |
- Çıkış kodu: 0 eşiğin altında, 1 eşikte ya da üstünde yeni bulgu, 2 kullanım hatası ya da şema bulunamadı.
- Borç kaydındaki bulgular ve (inceleme kipinde) değişiklikten önce de var olan bulgular eşiğe sayılmaz.
- Node 18+ yeterlidir; bağımlılık yoktur. Dosyalar yalnızca okunur, ağ isteği yapılmaz; şema ekibin makinesinden ya da CI sunucusundan çıkmaz.
GitHub Actions örneği: PR'ın getirdiği bulguları yorum olarak yazar, hata varsa kontrolü kırar ve SARIF'i kod taramasına yükler. GitLab CI ve Jenkins'te aynı komut çalışır.
name: sqlSchema
on: pull_request
permissions: { contents: read, pull-requests: write, security-events: write }
jobs:
schema-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-node@v4
with: { node-version: 20 }
# bir sürüm etiketine sabitleyin
- run: git clone --depth 1 --branch v0.13.0 https://github.com/umitkrkmz/sqlSchema.git ../sqlschema
- run: git worktree add ../base origin/${{ github.base_ref }}
- run: node ../sqlschema/tools/sqlschema-lint.js db/migration --baseline ../base/db/migration --format md --out review.md --fail-on error
- if: always()
run: gh pr comment ${{ github.event.pull_request.number }} --body-file review.md
env: { GH_TOKEN: ${{ github.token }} }
- if: always()
run: node ../sqlschema/tools/sqlschema-lint.js db/migration --baseline ../base/db/migration --format sarif --out sqlschema.sarif --fail-on none
- if: always()
uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: sqlschema.sarif }Hatalı tasarım (DBA incelemesi) örneği bu özellik için hazırlanmıştır: düzgün bir başlangıç şemasına üç geliştiricinin özensiz eklediği migration'lar. Her kural en az bir kez tetiklenir.
Araç çubuğundaki Dışa aktar şemayı bir belge ya da başka bir aracın biçiminde verir. Dosyalar tarayıcıda üretilir; şema hiçbir yere gönderilmez.
| Biçim | İçerik | Kullanım |
|---|---|---|
| Markdown veri sözlüğü | İçindekiler; tablo başına açıklama, kolon tablosu (tip, boşluk, anahtar, açıklama, kod değerleri) ve ilişkiler (zorunlu / isteğe bağlı, @ref koşulu, tahmini) |
Wiki, Git, Confluence |
Mermaid erDiagram |
Karga ayağı birebir; tanımlayıcı ilişki düz, öbürü kesik çizgi | GitHub / GitLab Markdown'ında doğrudan çizilir |
| PlantUML | IE notasyonu; PK kolonları çizginin üstünde, * zorunlu |
Kurumsal belge araçları |
| DBML | Tablolar, notlar, bileşik PK; tanımlı FK'ler Ref, @ref ve tahmini ilişkiler yorum |
dbdiagram.io |
| CSV | Şema, tablo, kolon, tip, boşluk, PK, bağlantı, açıklama, değerler | Excel (Türkçe'de ; ayırıcı, UTF-8) |
| SVG | Haritanın yerleşimiyle kartlar, kolon satırlarına bağlanan çizgiler, karga ayağı | Sunum, baskı, poster |
- Kapsam: bütün şema, tek bir şema, alt diyagram ya da seçili tablolar. İlişki yalnızca iki ucu kapsamdaysa yazılır.
- Önizleme uzun çıktıları kısaltır; kopyalanan ve indirilen metin tamdır.
?export=mermaidpencereyi o biçimle açar.
"Kişisel veri hangi tablolarda? Bir müşterinin verisini silmemiz ya da maskelememiz gerekirse nereye bakmalıyız?" Alt bilgi çubuğundaki KVKK bağlantısı bunu şemadan çıkarır:
- Sınıflandırma: kolon adı, açıklaması ve tablo adından beş kategori:
- Kimlik: TCKN, ad soyad, doğum tarihi, cinsiyet, uyruk
- İletişim: telefon, MSISDN, e-posta, adres ve adres tablosunun satırları
- Finans: IBAN, kart numarası ve kart belirteci, maaş, gelir
- Konum / cihaz: IP, IMEI, IMSI, ICCID, koordinat
- Özel nitelikli (KVKK md. 6): tanı, reçete, alerji, kan grubu, din, sendika, biyometrik veri. Tanı ve reçete gibi tabloların bütün kayıtları da sayılır.
- Kişiyle ilişkilendirilebilir tablolar: kişisel veri tutan tablolara FK ya da
@refile (zincir boyunca) bağlananlar: faturanın satırı, hesap üzerinden müşteriye bağlıdır. Panel hangi tablo üzerinden ve kaç adımda bağlandığını yazar. - Yanlış alarmı azaltmak için:
- Anahtar kolonlar veri sayılmaz (
ADDRESS_IDadres değil, adres satırının kimliğidir). - Kod katalogları (ICD-10, ilaç listesi) ve altyapının konumu (baz istasyonu, ATM) kişisel sayılmaz.
- Konum verisi ancak bir kişiye doğrudan bağlı tabloda sayılır.
- Teknik adresler (sunucu, eSIM sunucusu) ve cihaz parmak izi ayrılır.
- Anahtar kolonlar veri sayılmaz (
- Haritada göster: özel nitelikli veri tutan tablolar kırmızı, kişisel veri tutanlar sarı, kişiyle ilişkilendirilebilenler mavi; kartta kişisel veri kolonları renklenir.
- Envanter: CSV (Excel) ve Markdown olarak indirilir.
- Bağlantı:
?privacy=1haritayı,?pop=privacypencereyi açar.
Bulgular adlardan ve açıklamalardan tahmindir, hukuki görüş değildir; envanteri veri sorumlusu ve hukuk birimiyle doğrulayın.
samples/ altındaki örnekler sentetiktir: gerçek bir kuruma ait değildir. Her biri bir sektörün tipik yapısını ve bir aracın gerçek dışa aktarım biçimini taklit eder. Örnekler menüsünden açılırlar.
| Örnek | Veritabanı | Senaryo |
|---|---|---|
| Küçük telekom | Oracle | 20 tablo, uygulamaya gömülü |
| Telekom BSS/OSS | Oracle | SQL Developer dökümü tek dosyada: 318 tablo, 16 şema, partition, trigger, paket |
| Telekom, şema başına dosya | Oracle | Aynı şema 16 dosyaya bölünmüş; bütün FK'ler en sondaki dosyada |
| Çekirdek bankacılık | SQL Server | SSMS "Generate Scripts": UTF-16, GO, IDENTITY, açıklamalar |
| Sigorta (eski sistem) | Oracle | Modül başına klasör, Türkçe adlar, hiç FK yok |
| Pazaryeri e-ticaret | MySQL | mysqldump --no-data, DELIMITER'lı yordam |
| Hastane bilgi sistemi | PostgreSQL | OMOP CDM biçimi: tablolar, PK, FK, indeks ve açıklamalar ayrı dosyalarda |
| Lojistik / kargo | PostgreSQL | Flyway, 14 sürüm: adı değişen ve silinen tablolar, partition |
| IoT telemetri | Cassandra | İki keyspace, sorgu başına tablo |
| Sosyal medya | MongoDB | $jsonSchema + Mongoose + mongoexport |
| Saha servisi mobil uygulaması | SQLite | sqlite3 .dump, çevrimdışı önbellek |
| Çok veritabanlı e-ticaret | MySQL + MongoDB + PostgreSQL | Mikroservisler, her klasör ayrı galaksi |
| Karışık adlandırma | Oracle | İki ekip, iki alışkanlık: PK ID ve <TABLO>_ID, kuralsız FK'ler, ORM tabloları |
| Sözlük ağırlıklı | Oracle | Bütün kodlar tek bir SOZLUK tablosunda; 30'dan fazla kolon ona @ref ile bağlı |
| Hatalı tasarım (DBA incelemesi) | Oracle | Düzgün bir şemaya özensiz eklenmiş migration'lar; her denetim kuralı tetiklenir |
| Bayi portalı (EF Core) | SQL Server | .NET uygulamasının üç sürümlük migration geçmişi ve ModelSnapshot.cs'i ile DBA'nın raporlama ve arşiv betikleri birlikte: owned tip, TPH / TPT, çoka çok |
| Veritabanı | Nasıl |
|---|---|
| Oracle, SQL Developer | Araçlar → Veritabanı Dışa Aktarma, yalnızca DDL. "Nesne türüne göre ayrı dosyalar" çıktısı klasör olarak açılabilir. |
| Oracle, SQL*Plus / SQLcl | Aşağıdaki DBMS_METADATA betiği |
| SQL Server | SSMS → veritabanı → Tasks → Generate Scripts (yalnızca şema) |
| MySQL / MariaDB | mysqldump --no-data veritabani > sema.sql |
| PostgreSQL | pg_dump --schema-only veritabani > sema.sql |
| SQLite | sqlite3 app.db .schema > sema.sql |
| Cassandra | cqlsh -e "DESCRIBE KEYSPACE telemetry" > sema.cql |
| MongoDB | Doğrulayıcı betikleri, Mongoose model klasörü ya da mongoexport --limit 1000 çıktıları |
Migration kullanan projelerde db/migration klasörünü olduğu gibi açmanız yeterlidir.
-- Oracle: veri sözlüğünden DDL ve açıklamalar
SET LONG 20000000 LONGCHUNKSIZE 20000000 PAGESIZE 0 LINESIZE 32767 TRIMSPOOL ON FEEDBACK OFF
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', FALSE);
SPOOL sema.sql
SELECT DBMS_METADATA.GET_DDL('TABLE', table_name, owner) FROM all_tables WHERE owner IN ('CRM', 'BILLING');
SELECT DBMS_METADATA.GET_DEPENDENT_DDL('COMMENT', table_name, owner) FROM all_tables t
WHERE owner IN ('CRM', 'BILLING')
AND (EXISTS (SELECT 1 FROM all_tab_comments c WHERE c.owner = t.owner AND c.table_name = t.table_name AND c.comments IS NOT NULL)
OR EXISTS (SELECT 1 FROM all_col_comments c WHERE c.owner = t.owner AND c.table_name = t.table_name AND c.comments IS NOT NULL));
SPOOL OFFŞema kodda tanımlıysa (ORM, "code first"). sqlSchema ORM kodunu okumaz (EF Core model özeti ve Mongoose hariç); ama her ORM şemayı SQL olarak verebilir ve sonunda veritabanı aynıdır:
| Araç | SQL'i almak |
|---|---|
| EF Core | Migrations/*ModelSnapshot.cs doğrudan açılır (bkz. EF Core); SQL için dotnet ef migrations script -o sema.sql (bütün migration'lar) ya da dotnet ef dbcontext script -o sema.sql (modelin bugünkü hâli) |
| Hibernate / JPA | jakarta.persistence.schema-generation.scripts.action=create ve ...scripts.create-target=sema.sql ayarları DDL dosyası yazar. Flyway kullanılıyorsa db/migration klasörü doğrudan açılır; Liquibase'te liquibase update-sql |
| Django | Her migration için python manage.py sqlmigrate <uygulama> <numara>; ya da migration'ları bir test veritabanına uygulayıp yukarıdaki dökümü alın |
| Rails | config.active_record.schema_format = :sql ile bin/rails db:schema:dump → db/structure.sql |
| Prisma | prisma/migrations klasörü doğrudan açılır (zaman çizelgesi de çalışır); tek dosya için prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script |
| Alembic | alembic upgrade head --sql > sema.sql (çevrimdışı kip) |
| Diesel | migrations klasörü doğrudan açılır |
| Diğerleri | Migration'ları bir test veritabanına uygulayıp yukarıdaki tablodaki gibi döküm alın |
Tabloların bir kısmı ORM'den, bir kısmı DBA betiklerinden geliyorsa iki çıktıyı birlikte açın. Karşılaştırma (karşılaştır) ORM'in ürettiği şema ile veritabanı dökümü arasındaki farkı da gösterir.
Arayüz Türkçe ve İngilizcedir. İlk açılışta sistem dili Türkçe ise Türkçe, değilse İngilizce seçilir. Sağ üstteki TR / EN düğmeleriyle değiştirilebilir; seçim tarayıcıda hatırlanır. Bir bağlantıda dili sabitlemek için ?lang=tr ya da ?lang=en kullanılabilir.
Paylaşılabilir bağlantılar. URL parametreleriyle bir örnek, bir tablo ve yakınlaştırma düzeyi doğrudan açılabilir:
index.html?lang=tr&sample=telekom&select=BILLING_ACCOUNT&zoom=0.9&legend=0
Açılışta bir pencere göstermek için pop=naming, pop=report ya da pop=files eklenir. center=TABLO bir tabloyu seçmeden ortalar.
index.html sayfa iskeleti, lejant
style.css görünüm
js/ tarayıcıda bu sırayla yüklenir; hepsi globalThis.sqlSchema ad alanına ekler
i18n.js Türkçe / İngilizce sözlükler, dil seçimi
lexer.js tokenizer, ifade ayırıcı, lehçe tahmini
sql-parser.js DDL → sıralı işlem listesi (create, fk, rename, drop ...)
mongo.js $jsonSchema, Mongoose ve JSON belgelerinden aynı işlem listesi
efcore.js EF Core model özeti ve migration dosyalarından aynı işlem listesi
files.js dosya sıralama (Flyway, golang-migrate, Prisma, Diesel, EF Core), ayrıştırıcı seçimi
model.js işlemleri uygular: tablolar, ilişkiler, kardinalite, ara tablo, tahmini ilişki; etki analizi, yol bulma
diff.js iki modelin farkı: tablo, kolon, PK, FK, UNIQUE; ad değişikliği tahmini; zaman çizelgesi
layout.js veritabanı → şema → takımyıldız → yıldız, hiyerarşik kuvvet yerleşimi
conventions.js adlandırma profili: kalıplar, oranlar, baskın kalıba uymayanlar
audit.js tasarım denetimi: kurallar, bulgular (kod döner, metin arayüzde)
fixes.js düzeltme önerileri: lehçeye uygun SQL, risk düzeyi
migrate.js farkı kapatan SQL taslağı: aşamalar, bağımlılık sırası, notlar
export.js dışa aktarma: Markdown veri sözlüğü, Mermaid, PlantUML, DBML, CSV
privacy.js KVKK haritası: kişisel veri kolonları, kişiyle ilişkilendirilebilen tablolar
sample-small.js gömülü küçük örnek
render.js canvas çizimi, kamera, karga ayağı
ui.js yükleme, dosya listesi, arama, panel, rapor, URL parametreleri
samples/ sentetik örnekler ve catalog.js (üretilir)
tools/ komut satırı denetimi (sqlschema-lint.js), örnek ve ekran görüntüsü üreticileri, sektör tanımları
tests/run.js bütün örnekleri, ayrıştırıcı kenar durumlarını ve çevirileri denetler
docs/images/ README görüntüleri (tr/ ve en/)
Geliştirme komutları (Node 18+, bağımlılık yok):
node tests/run.js # testler
node tools/gen-samples.js # samples/ klasörünü yeniden üretir
node tools/screenshots.js http://localhost:8000/ # README görüntülerini yeniler (Chrome gerekir)Ayrıştırıcı, model, yerleşim ve adlandırma profili DOM'a dokunmaz; Node'da require edilebilir. Konsoldan inceleme için window.sqlSchema açıktır:
sqlSchema.S.model.tables.filter(t => t.junction).map(t => t.name)
sqlSchema.loadText('CREATE TABLE a (id int PRIMARY KEY);', 'deneme.sql')- View'lar ve view'lar üzerinden kurulan ilişkiler çizilmez.
- Tahmini ilişkiler yalnızca kolon adlarına dayanır; adlandırma kuralı tutarsız şemalarda eksik ya da fazla çıkabilir. MongoDB'de
authorIdgibi koleksiyon adıyla eşleşmeyen alanlar bağlanmaz. CREATE TABLE … AS SELECTtabloları kolonsuz görünür.- MongoDB şeması örnek belgelerden çıkarılıyorsa yalnızca o belgelerde görülen alanlar listelenir.
- Değişkenle kurulan dinamik Mongoose şemaları (
new Schema(buildFields())) okunmaz. - EF Core'da yalnızca model özeti (
ModelSnapshot.cs) ve migration dosyaları okunur; entity sınıfları veOnModelCreatingiçindeki fluent API okunmaz. Başka ORM'lerin (Hibernate, Django, Rails …) model kodu okunmaz; SQL çıktısı kullanılabilir (bkz. Şemayı dışa aktarmak). - Bir dosya okunamazsa (bozuk ya da yarım) öbür dosyalar yine çizilir; okunamayan dosya dosyalar listesinde hatasıyla görünür.
- Katkı rehberi: CONTRIBUTING.md
- Davranış kuralları: CODE_OF_CONDUCT.md
- Güvenlik açığı bildirimi: SECURITY.md
- Değişiklik geçmişi: CHANGELOG.md
- Yapay zekâ kodlama ajanları için proje rehberi: AGENTS.md
Lütfen hata bildirirken gerçek bir kuruma ait şema paylaşmayın; tablo adlarını değiştirmek yeterlidir.
MIT lisansı ile dağıtılır.
sqlSchema reads database schema files in the browser and draws them as a star map:
- Every table is a star.
- Every relationship is a line between two stars.
- Every schema is a region of sky, and every database is a galaxy.
Zoom in and the stars turn into table cards with columns, and relationships read in crow's foot notation.
It is less manual than draw.io and lighter than a data-modelling tool. The goal is that someone seeing a schema for the first time can answer "what is connected to what?" in seconds.
- Highlights
- Quick start
- Reading the map
- Multiple files and migrations
- Supported databases
- MongoDB
- EF Core (code first)
- Naming profile
- Design audit
- Exporting documents and diagrams
- Personal data map
- Samples
- Exporting a schema
- Language
- Project layout and development
- Limitations
- Contributing, security, license
- Plain HTML, CSS and JavaScript. No dependencies, no build step; just open the folder.
- Privacy: files never leave the browser and are not sent to any server.
- Eight databases: Oracle, SQL Server, MySQL, MariaDB, PostgreSQL, SQLite, Cassandra and MongoDB.
- Code-first projects: the EF Core model snapshot (
ModelSnapshot.cs) and migration history are read without converting them to SQL; it can be opened together with DBA scripts. - One file, many files or a whole folder: split dumps, migration folders (Flyway, golang-migrate, Prisma, Diesel), multi-database projects.
- Crow's foot notation: cardinality is derived from
NOT NULL,UNIQUEand primary keys. - Inferred relationships: links are found from column names in legacy systems without FKs, in Cassandra and in MongoDB.
- Naming profile: shows which naming patterns the schema uses, in what proportion, and which tables depart from the dominant pattern.
- Design audit: lists mistakes such as tables without a PK, text dates and unindexed FKs, with reasons and suggestions.
- Schema diff and timeline: compares two versions and plays migrations in order.
- Scale: an Oracle dump with 2,900 tables and 4,300 FKs opens in about 0.8 s including parsing, layout and the interface; a frame draws in under 10 ms.
- Turkish and English interface.
- Download or clone the repository.
- Open
index.htmlin a browser. - Drag your schema files or a folder onto the page. Alternatively use Open files (multiple selection allowed), Folder, Paste or Samples.
The browser can read the sample files and dropped folders only when the page is served. Run this in the project folder and open http://localhost:8000:
python -m http.server 8000The app also works when
index.htmlis opened directly from disk (file://). In that case choose folders with the Folder button instead of dragging them. The embedded small sample always opens.
| Gesture | Result |
|---|---|
| Wheel / pinch | Zoom |
| Drag | Pan |
| Click | Select a table, open the detail panel |
| Double-click | Zoom into a table, show its columns |
/ |
Search tables or columns |
F |
Fit everything |
C |
Hide / show column details |
L |
Open / close the table list |
↑ / ↓, Enter |
Move through the panel's relationships, go to the chosen table |
Alt + ← / → |
Back / forward in the navigation history |
, / . |
Previous / next version on the timeline |
Esc |
Close the path or leave focus mode / clear the selection |
The view changes with the zoom level:
| View | What you see |
|---|---|
| Galaxy | Databases, schemas and bundles of relationships between schemas (the number on a line = relationship count) |
| Constellation | Tables become stars: size = number of links, colour = schema. The lines of the selected table show crow's feet and column names. |
| Close-up | Tables become cards; lines attach directly to the FK and PK column rows. |
The View menu holds the table list, column details, inferred relations, lookup links, grid and constellation grouping options. With column details off (shortcut C), close-up cards show only the table name and lines attach to the card header, leaving just tables and their relationships. The detail panel still lists the columns. The choice is remembered in the browser.
The detail panel lists:
- the columns and their comments
- the file and line where the table is defined
- a plain-language reading of every relationship, such as "Every INVOICE record belongs to exactly one BILLING_ACCOUNT record. A BILLING_ACCOUNT record can have zero or many INVOICE records."
Focus mode keeps only the neighbours one or two steps away from the selected table and dims everything else.
Following relationships. Clicking a relationship in the panel (or picking it with ↓ and pressing Enter) goes to that table. The trail at the top of the panel lists the tables visited in order (ABONE › IS_EMRI › CIHAZ); click a name in it, the ‹ › buttons, or press Alt + ← / → to go back and forward. The whole schema can be walked without touching the mouse.
Table list. Lists every table under schema and constellation headings (View → Table list or L; off by default):
- Order: tables are listed in the order they are defined in the SQL files (File order) or by name (A → Z).
- Navigation:
↑/↓moves from table to table; the selection, the panel and the map move together. Press↓in the filter box to step into the list. - Filter: the box at the top filters only the list, not the map.
- Marks: each row shows the column count; tables without a PK, junction (M:N), lookup and external tables carry small tags.
- The list and the legend share the same edge; opening one closes the other. The choice is remembered in the browser.
Sub-diagram. To see only the tables you care about in a large schema, on a map of their own:
- Picking:
Ctrl/Cmd+ click on the map, the Add to selection button in the panel, orCtrl/Cmd+ click in the table list. The + on a constellation heading in the list adds the whole constellation (for example one module file). Picked tables are marked with a highlighted ring. - Opening: Open sub-diagram in the bar that appears at the top. With with neighbours ticked, tables directly linked to the picked ones come along.
- In the sub-diagram: only these tables and the relationships between them are drawn, with a layout of their own; the panel, search, table list and naming profile also look only at these tables.
- Going back: Back to all or
Esc. The full map returns with the same positions. - Link:
?sub=BILLING_ACCOUNT,INVOICE&near=1opens this sub-diagram directly. - Saved views: while in a sub-diagram, Save gives it a name. Views are kept in the browser per set of opened files; when the same files are opened again they are listed under View → Saved views. Export writes them to a
.sqlschema.jsonfile and Import reads it back. The file carries only the view (table names), not the schema, so it is safe to share within a team.
Impact analysis. "What is affected if I change this table or delete one of its rows?" Opened with the Impact button in the panel:
- Affected tables: every table that points to it is listed level by level (level 1 points directly, level 2 points to those …). On the map unaffected tables fade and affected ones get a ring coloured by level.
- What happens on delete: each link says whether rows are deleted too (
ON DELETE CASCADE), set to NULL (SET NULL), whether it blocks the delete (an FK without an action) or is not enforced (@ref, inferred or disabled FK: the database does not protect it and orphan rows may remain). - Deleted together: tables reached through the CASCADE chain when a row is deleted are shown separately.
- Column level: with the analysis on, clicking a column in the panel keeps only the tables pointing to that column (for example before changing a PK type).
- Sharing: Download Markdown writes the result to a file to share with the team before a change. The mode follows the selection; moving to another table recomputes it.
Esccloses it.
Finding a path. "How are these two tables connected?" Press Find path in the panel and click the target table (or search for it); with two tables picked, Show path in the selection bar does the same:
- On the map: only the tables and links on the path stay bright, and the camera fits the path on screen.
- In the panel: the path is written step by step:
TICKET_NOTE.TROUBLE_TICKET_ID → TROUBLE_TICKET.TROUBLE_TICKET_ID(the FK goes this way),CUSTOMER.CUSTOMER_ID ← CUSTOMER_ORDER.CUSTOMER_ID(the other table points to this one). When two tables are linked more than once (billing and delivery address), every link is listed. - Options: the shortest path is not always the one you want (reaching an order through the user who wrote a note, for example). Five paths are listed from shortest to longest; choose with ‹ › or from the list.
- What is not passed through: lookup tables and audit columns such as
CREATED_BYlink everything to everything; they are not used along the way, only as ends. When there is no path through declared relationships, inferred ones are used as well and this is stated. - No JOIN SQL is generated; the path only shows which tables and columns it goes through.
Esccloses it; the link?path=PAYMENT_ALLOCATION,ADDRESSopens it.
The mark at the end of a line tells how many records can exist on that side. The mark next to the table is the upper bound; the outer one is the lower bound.
| Mark | Meaning | How it is derived from the schema |
|---|---|---|
──‖ |
exactly one | FK column is NOT NULL; owner of an embedded document |
──○┼ |
zero or one | FK column is nullable, or the FK is also a PK/UNIQUE (1:1) |
──○< |
zero or many | default for the table holding the FK; arrays of ObjectIds |
──┼< |
one or many | DDL cannot enforce it (it needs a trigger or application rule), so it is never drawn |
| Line | Meaning |
|---|---|
| Solid | Declared foreign key or Mongoose ref |
| Long-dashed | Relationship declared with a @ref tag in the column comment (see below) |
| Dashed | Inferred relationship (see below); can be turned off in the View menu |
| Dotted | Disabled FK (DISABLE, RELY DISABLE NOVALIDATE, T-SQL NOCHECK) |
| Dash-dot | MongoDB embedded document: the sub-document lives inside its owner |
| Star | Meaning |
|---|---|
| Filled star | Table; size = number of links, colour = schema |
| Ring | Junction table (M:N): its PK is made of two FKs, or it is a pure link table |
| Small faded star | Satellite: an embedded MongoDB sub-document, placed next to its owner |
| Dashed ring | Referenced by an FK but not defined in the files |
On cards, PK marks a primary key, FK a foreign key and CK a Cassandra clustering key. A faded column name means the column is nullable.
Constellations. A small schema is one constellation. Large schemas are split by table-name prefix (CUSTOMER_*, INVOICE_*) and by links. Each star gets a Bayer-style designation by brightness within its constellation (α Billing, β Billing). The layout is deterministic: the same files always give the same map.
Inferred relationships are drawn dashed in two cases:
- No FK is declared, but the column name equals another table's primary key:
CDR.SUBSCRIPTION_ID→SUBSCRIPTION.SUBSCRIPTION_ID. - An
X_ID/xIdcolumn points to a table X whose key isIDor_id:orders.customerId→customers._id.
They are not drawn when the types disagree or when there is more than one candidate.
Relationships from comments: @ref. Some relationships cannot be declared as FKs. The most common case is columns that point to only one type in a generic lookup table (SOZLUK: ID, TIP_ID, AD). The database cannot express "only rows where TIP_ID = 7". Such relationships are added to the map with a tag in the column comment:
COMMENT ON COLUMN ABONE.DURUM_ID IS 'Subscriber status. @ref SOZLUK.ID (TIP_ID = 7)';
COMMENT ON COLUMN SESSION_LOG.USERID IS 'The user ID. @ref USERS';| Syntax | Meaning |
|---|---|
@ref TABLE |
To the target's primary key |
@ref TABLE.COLUMN |
To a specific column of the target (read as SCHEMA.TABLE when TABLE.COLUMN does not exist) |
@ref SCHEMA.TABLE.COLUMN |
With the schema |
… (CONDITION) |
The condition in parentheses is written on the line and in the panel |
- Where it is read: the tag can be anywhere in the comment. Oracle and PostgreSQL
COMMENT ON COLUMN, MySQL inlineCOMMENT '…'and SQL Serversp_addextendedpropertydescriptions are all read. - On the map: these relationships are not guesses but the DBA's statement; they are drawn long-dashed and tagged "from comment" in the panel.
- With an FK: if the column already has an FK, only the condition is added to it.
- Errors: a target that cannot be found is listed as a warning in the parse report.
In the insurance sample, status columns point to the generic code table (KOD_TABLO) this way.
Lookup tables. When hundreds of columns point to a generic code table, the lines swamp the map and the lookup becomes a giant hub. So a table that is the target of at least two conditional relationships counts as a lookup table:
- On the map: lines to it are not drawn. On the card, a
→ KOD_TABLObadge replaces the column type. The line is drawn only while the lookup or the referencing table is selected or hovered. - In the layout: lookup relationships do not pull tables together, so the lookup does not sit in the middle of the schema and squeeze the rest.
- In the panel: selecting the lookup shows a Lookup usage section listing which columns use which condition (
KOD_TIP = 'POLICE_DURUM'→POLICE.POLICE_DURUM). - By hand: the Show as lookup table / Not a lookup table button in the panel overrides the automatic choice; it is remembered in the browser.
- As lines: View → Draw lookup links always draws the lines.
In the Lookup-heavy sample, more than 30 columns point to a single SOZLUK table.
Code values. The meaning of codes is not always kept in a separate table; often it is written straight into the column comment:
COMMENT ON COLUMN MUSTERI.MUSTERI_TIP IS 'G = Gerçek kişi, T = Tüzel kişi';
COMMENT ON COLUMN HASAR_IHBAR.IHBAR_KANAL IS 'Channel of the claim: ACN = Agency, CAG = Call centre, WEB = Online branch';- Recognised forms:
1 = Active, 2 = Passive·A: Active; P: Passive·Y-Yes / N-No·Status (1=Active, 2=Passive)·0 => off, 1 => on. - Against false matches: at least two pairs, the same separator and short, code-like codes are required. "Note: old field, Source: SAP" or "Version 2 = new format" is not a list.
- In the panel: the values appear as chips under the column; the part of the comment outside the list ("Channel of the claim") is shown separately.
- On the card: a small
≡next to the column name. - In search: the meanings of values are searched too. Typing "iptal" finds the column holding
4 = İptal; case and Turkish characters are ignored.
Allowed values may be defined elsewhere too; all of them are shown with the same chips, with the source next to them:
| Source | Example |
|---|---|
CHECK constraint |
CHECK (MUSTERI_TIP IN ('G', 'T')) · SQL Server: CHECK (([Gender]='F' OR [Gender]='M')) |
ENUM type |
MySQL status enum('active','passive') |
MongoDB enum |
enum: ['tr', 'en'] in $jsonSchema and Mongoose fields |
When the values come from a constraint or type and their meanings are written in the comment, the two are combined: CHECK (MUSTERI_TIP IN ('G','T')) with the comment 'G = Gerçek kişi, T = Tüzel kişi' shows as G Gerçek kişi · T Tüzel kişi. Ranges (BETWEEN), comparisons (> 0) and multi-column conditions are not value lists.
Lookup data. If the files also contain the INSERT rows of the lookup table, a column linked with @ref SOZLUK.ID (TIP_ID = 7) shows the values of that type (1 Aktif · 2 Pasif …; source: "from the lookup: SOZLUK · TIP_ID = 7"):
- Code and meaning: the code comes from the link's target column, the meaning from a column such as
AD,ACIKLAMAorNAME. - Condition: only
COLUMN = valueequalities (several joined withAND) are applied. - Unconditional lookup link: no values are shown, because it is not known which type of the lookup applies. For plain FKs to small tables that are not lookups, all rows of the table become values.
- Limits: only plain
INSERT … VALUESis read, notINSERT … SELECT. For large data dumps the first 2,000 rows per table are taken.INSERTs are still not drawn and are counted in the report. - Priority: the column's own
CHECKor comment list comes first; meanings missing there are filled in from the lookup.
All files are merged into one model and names are resolved at the end. So these cases just work:
- an FK in one file pointing to a table in another
constraints.sqlsorting beforeddl.sql
The N files link in the bottom-right corner opens the file list. There you can:
- include or exclude individual files
- see each file's dialect and table count
- turn on "separate database"
One constellation per file. When a schema's tables come from more than one file, each file's tables gather in their own constellation. Teams usually split modules into files, so the map keeps that split.
- Kept apart: constellations of different files stay clearly apart even when they are related.
- Boundary and name: each constellation is outlined with a thin circle, with its name above the outline.
- Name: taken from the file path; files with the same name are told apart by their folders (
POLICE/tablolar,HASAR/tablolar).
In a migration folder a file is a version, not a module; there, and for MongoDB, tables are grouped by name prefix and relationships. View → Constellations changes the choice by hand: Automatic, By file or By name and relationships.
Reading order follows the conventions of migration tools:
| Tool | Files | Behaviour |
|---|---|---|
| Flyway | V1__init.sql, V1_1__x.sql, V2__y.sql |
By version number (V10 after V2). R__*.sql last, U*__ undo scripts skipped. |
| golang-migrate, dbmate | 000001_x.up.sql |
.down.sql skipped. |
| Timestamped | 20240115093000_x.sql |
By time. |
| Prisma | 20240115093000_init/migration.sql |
The version is in the folder name; by folder order. On the timeline the version name is the folder name. |
| Diesel | 2024-01-15-093000_init/up.sql |
By folder order; down.sql skipped. |
| EF Core | 20240115093000_Initial.cs |
By time; Up() is read, .Designer.cs and the model snapshot are skipped (see EF Core). |
| Numbered / other | 01_tables.sql, a2.sql < a10.sql |
Natural name order. |
Migrations are applied from first to last, and the map shows the final state of the schema. These statements are applied:
RENAME TO,RENAME COLUMNDROP TABLE,DROP COLUMN,DROP CONSTRAINTALTER COLUMN … TYPE,MODIFY,CHANGE- T-SQL
sp_rename, MySQLRENAME TABLE
Schema diff. compare in the bottom bar compares the open files (after) with an earlier version (before):
- Earlier version: in a migration folder, pick a version ("as of V7"), or choose the files / folder of the earlier version separately (for example a production dump and a test dump).
- On the map: added tables are green, removed ones red, changed ones yellow; renamed tables have a blue ring. Unchanged tables stay in the background. Removed tables also appear in place on the map.
- In the panel: the difference for the selected table: added, removed and changed columns (type, NULL, default, PK), renamed columns, PK, FK and UNIQUE differences. Added and changed column rows are tinted on the card.
- Rename guesses: tables are matched by the similarity of their column sets (
customer→customers), columns by type and name similarity (weight→weight_grams); guesses are labelled as such. The FK of a renamed column is not counted as changed. - Report: Download Markdown writes the change list to a file for release notes or reviews.
- Link:
?diff=V3opens the comparison with that version of a migration folder.
ALTER draft. With a comparison or the timeline active, ALTER draft in the compare window writes the SQL script that takes the earlier version to the later one, in the right dialect:
- Dependency order: dropped FKs and constraints, renames, new tables, added and changed columns (type, NULL, default), primary keys, dropped columns, new constraints and indexes, dropped tables.
- Notes: a guessed rename, a constraint with no name in the files,
NOT NULLwithout a default and a type change that needs data conversion are written as comments above the step. - Safe default: data-losing steps (dropping columns and tables) are comments; unticking the box turns them on.
- Limit: it is a draft; data migration is not written. Read it and try it in a test environment before running it.
- Link:
?diff=V3&alter=1opens the draft.
Timeline. In a migration folder, Timeline in the compare window plays the versions in order:
- A stable map: the layout is built once from the tables of every version. When the step changes, tables stay in place and the camera does not move; only the tables that exist in that version are drawn.
- Each step is a diff: the tables that version added, changed and removed compared with the previous one appear in the schema-diff colours. The compare window gives that step's list and Markdown report.
- Navigation: the slider, the ‹ › buttons or the
,/.keys; ▶ plays the versions one after another. - Table history: the selected table's panel lists the versions in which it was created, changed and dropped (
V4__plural_table_names name: shipment → shipments). Clicking a row goes to that version. A renamed table stays selected. - Link:
?time=V4opens the timeline at that version.
Separate databases. When files of different dialects are opened together (for example orders in MySQL, a catalogue in MongoDB and reporting in PostgreSQL), each folder is drawn as its own galaxy.
| Oracle | SQL Server | MySQL / MariaDB | PostgreSQL | SQLite | Cassandra | |
|---|---|---|---|---|---|---|
CREATE TABLE, inline and table-level constraints |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ PRIMARY KEY ((a, b), c) |
ALTER TABLE … ADD CONSTRAINT |
✓ | ✓ WITH CHECK/NOCHECK |
✓ | ✓ ONLY |
||
| Column changes | MODIFY |
ALTER COLUMN |
MODIFY, CHANGE |
ALTER COLUMN … TYPE |
||
| Renames and drops | RENAME, DROP |
sp_rename, DROP |
RENAME TABLE, DROP |
RENAME, DROP |
RENAME, DROP |
|
CREATE UNIQUE INDEX (1:1 detection) |
✓ | ✓ | ✓ | ✓ | ✓ | |
| Table / column comments | COMMENT ON |
sp_addextendedproperty |
COMMENT '…' |
COMMENT ON |
How the database type is recognised. You do not have to choose it; each file is scored only on expressions specific to one database, and the highest score wins:
| Database | Hints looked for |
|---|---|
| Oracle | VARCHAR2, NUMBER(…), TABLESPACE, SYSDATE, PCTFREE, NOVALIDATE, a / on its own line |
| SQL Server | [dbo], GO on its own line, NVARCHAR, IDENTITY(…), CLUSTERED, DATETIME2, sp_addextendedproperty |
| MySQL / MariaDB | `backticks`, ENGINE=, AUTO_INCREMENT, DEFAULT CHARSET, UNSIGNED; MariaDB from the dump header |
| PostgreSQL | SERIAL, ::type, $$, TIMESTAMPTZ, JSONB, OWNER TO, character varying, ALTER TABLE ONLY |
| SQLite | AUTOINCREMENT, WITHOUT ROWID, PRAGMA |
| Cassandra | the .cql extension, CREATE KEYSPACE, WITH CLUSTERING ORDER, frozen<, map< |
Types found in every database, such as DATE, INTEGER or VARCHAR, cannot tell databases apart and are not counted. A plain CREATE TABLE file without hints takes the dominant type of the other files in its folder. MongoDB files are recognised by extension and content ($jsonSchema, new Schema(…), JSON documents).
Not drawn. Views, sequences, triggers, packages, procedures, functions, types, grants and INSERTs are counted in the report but not drawn (INSERT … VALUES rows are read only for lookup values). The parser does not trip over the ; inside them:
- PL/SQL blocks are kept whole up to the
/line. - T-SQL blocks are kept whole up to the
GOline. - MySQL blocks are kept whole up to the
DELIMITERmark.
Also handled:
- SQL*Plus commands
- Oracle storage and partition clauses
- PostgreSQL
$$bodies andPARTITION OFchildren - CQL
//comments andmap<text, int>types
Encoding. Files may be UTF-8, UTF-16 (the SSMS default) or Windows-1254; the encoding is detected automatically.
MongoDB has no DDL. The schema is taken from three sources; a collection that appears in several of them is merged into one table.
| Source | Example | What is read |
|---|---|---|
mongosh scripts (.js) |
db.createCollection('x', { validator: { $jsonSchema } }), collMod, createIndex(…, { unique }) |
Fields, types, required fields, descriptions, enum values |
Mongoose models (.js, .ts) |
new Schema({ author: { type: ObjectId, ref: 'User' } }) |
Fields and ref relationships. Collection names follow Mongoose's pluralisation rules. |
Sample documents (.json, .jsonl, .ndjson) |
mongoexport output |
Union of fields across the first 5,000 documents; Extended JSON ($oid, $date) |
Embedded objects and arrays of objects become satellite tables (users.profile, orders.items) placed next to their owner.
Projects whose schema is defined in .NET code (Entity Framework Core) need no SQL file: the model snapshot EF generates, Migrations/<Context>ModelSnapshot.cs, is read directly. Because the tool generates it, the file is regular and holds the whole model in one place; no code is run. You can open the project folder as it is: entity classes, .Designer.cs files, appsettings.json, bin/ and obj/ are skipped.
| In the snapshot | On the map |
|---|---|
ToTable("Dealers", "sales"), HasDefaultSchema |
Schema and table name |
Property<int?>, IsRequired, HasColumnType, HasColumnName, HasDefaultValue(Sql), HasComment |
Column, type, NULL, default, comment |
HasKey, HasAlternateKey, HasIndex(...).IsUnique(), HasCheckConstraint |
PK, UNIQUE, index, CHECK value list |
HasOne(...).WithMany / WithOne().HasForeignKey(...), OnDelete |
FK and delete behaviour (one-to-one, composite keys, HasPrincipalKey) |
OwnsOne / OwnsMany |
Columns such as Address_City in the same table, or a table of its own |
HasBaseType |
TPH (into the base table, columns nullable), TPT (own table plus an FK to the base table), TPC (base columns copied) |
| Many-to-many | The join table EF generates (DealerRegion) |
- Provider: SQL Server, PostgreSQL (Npgsql), Oracle, MySQL and SQLite are recognised from the extension class names in the snapshot, or else from the column types.
- Mixed projects: DBA scripts (
.sql) can sit in the same folder or be opened together; their FKs connect to the EF tables. In the panel, tables from EF carry an EF Core tag, so you see at a glance which tables the code defines and which exist only in DBA scripts. - Migration history: when the folder holds migration files such as
20240115093000_Initial.cs, each is a version and themigrationBuildercalls inUp()are read (CreateTable,AddColumn,AlterColumn,RenameColumn,RenameTable,CreateIndex,AddForeignKey,DropTable…; raw SQL inSql("...")too). The timeline, schema diff, change review and--since 20240610150000_DealerStatusAndVknon the command line work for EF projects without SQL. The model snapshot is then skipped, since it is a copy of the final state. - Not read: entities mapped to a view with
ToView,HasDataseed data and theDown()method of migrations.
When a team has no written naming standard, the first step is to see what the schema actually uses. The naming link in the bottom-right corner counts names along these dimensions and shows their shares:
| Dimension | Patterns |
|---|---|
| Table and column name case | UPPER_SNAKE, lower_snake, PascalCase, camelCase |
| Primary key name | ID, <TABLE>_ID, <TABLE>_NO / _CODE, unrelated to the table name |
| Foreign key column | <TARGET>_ID, <TARGET>_NO / _CODE, role prefix (SENDER_CUSTOMER_ID, AGENT_USER_ID → APP_USER), same as the target PK, role name only (OWNER), not containing the target name (CHZ_REF) |
| Table name | singular / plural (estimated), prefixes such as TBL_ |
| Characters and length | Turkish / non-ASCII characters, names longer than 30 characters |
| Data types | date columns (date type, text, YYYYMMDD number), amount columns (decimal, integer, FLOAT, text), yes / no columns (BOOLEAN, E/H, Y/N, 0/1, CHAR(1) / NUMBER(1) with no values written) |
- Each dimension lists the dominant pattern and the names that do not follow it. Clicking a name selects its table.
- If the most used pattern has less than 60%, it is not called dominant; the window shows no clear dominant pattern. A 51% to 49% split means the schema has two separate habits.
- Scope computes the profile for a single schema, which separates the habits of different modules.
- The consistency score is the average share of names that follow the dominant pattern in each dimension. Data types do not count towards it.
- The Data types section shows which types hold columns with the same meaning. Date and amount columns are guessed from their names; the design audit uses the same classification, so a share such as "8% of dates are text" adds up the columns the audit finds one by one.
- On the map: the on map button in each dimension's heading colours the map by that dimension; each pattern takes its colour from the window. A table with an item outside the dominant pattern stands out in that pattern's colour. For column-level dimensions (case, FK, characters) the matching column rows on the card are tinted too. You see at a glance which team wrote which part of the schema.
?style=pkStyleopens this view. - Download Markdown writes the profile to a file to share with the team.
The tool imposes no rule: whether ID or <TABLE>_ID is right is the team's decision.
Not counted in the shares:
- Composite PKs, 1:1 tables whose PK comes from the parent, and tables without a PK. These are shown separately.
- Audit columns such as
CREATED_BY,UPDATED_BY,GUNCELLEYENandKAYIT_KULLANICI. They point to the user table but follow their own established pattern; they are counted separately. - Inferred relationships: only declared FKs are counted, because inferred ones are already based on names.
- The
_idandreffields of MongoDB collections.
The Mixed naming sample was made for this feature: an Oracle schema to which two teams added tables with different habits.
audit in the bottom bar scans the schema for common design mistakes. Each finding says three things:
- What: "column
BASLANGIC_TARisVARCHAR2(20)" - Why it matters: with dates as text, range queries cannot use indexes and sorting is wrong
- Suggestion: use
DATEorTIMESTAMP
The rules fall into four groups:
| Group | Example rules |
|---|---|
| Keys and integrity | table without a PK, FK and target column types differ, undeclared relationship, FK without an index, circular FK chain, redundant index, disabled FK, unresolved @ref target |
| Data types | dates and numbers as text, FLOAT amounts, oversized text, CHAR for variable data, CLOB for short text, same-named columns with different types, booleans in different formats (E/H, Y/N, 0/1) |
| Normalisation | repeating columns like PHONE1, PHONE2, PHONE3, comma-separated lists, key-value (EAV) tables, very wide tables |
| Naming | names over the limit (30 on Oracle 12.1 and earlier), reserved words, Turkish characters, system names like SYS_C0012345; PK, FK and case outliers from the dominant pattern |
- Severity: error, warning and info. Rules that reason from names (text dates, amounts, EAV ...) are marked guessed from names.
- To keep false alarms down:
- Missing PKs and FKs on log, history and fact tables (
_LOG,_HIST,_CDR,FACT_) are treated as deliberate. - Text dates are normal on SQLite.
- Role-named FKs (
BILLING_ADDRESS_ID) and text natural keys (CURRENCY_CODE) are not counted as outliers. - If the files contain no index definitions at all, FK indexes are not checked.
- Missing PKs and FKs on log, history and fact tables (
- Show on map: tables with errors are red, with warnings yellow; the rest stay in the background. Column rows with findings are tinted on the card.
- In the panel: the selected table's findings and suggestions are in the Audit section.
- In the window: the ten tables with the most findings are listed. Download Markdown writes every finding with its reason and suggestion into a review document.
- With the timeline: the audit is recomputed at each version, so you can see which migration brought a finding.
- Link:
?audit=1shows the audit on the map,?pop=auditopens the window.
Standard and rules. The naming profile is a snapshot of the schema; a standard is the team's decision. Propose a standard in the naming window (or Standard and rules in the audit window) proposes one from the profile:
- Proposal: where a dimension has a clear dominant pattern (60% or more), it is proposed: table and column case, PK name, FK column, singular / plural. Otherwise the proposal is left empty, the options are shown with their shares, and the window says the team should decide. Role-prefixed FKs are accepted under any standard.
- Requirements: a name length limit (30 is proposed on Oracle), ASCII only, required comments (tables, or tables and columns), audit columns (e.g.
CREATED_AT, CREATED_BY). - Rule severity: every audit rule can be set to error, warning, info or off.
- Effect: once saved, the audit checks against the standard instead of the dominant patterns ("PK name does not follow the pattern: _ID (standard: ID)"). Three rules run only when the standard defines them: singular / plural, missing comments, missing audit columns.
- Sharing: the standard is written to the same
<name>.sqlschema.jsonproject file as the debt register. Everyone who opens the folder, and the command line, use the same standard. - Standard document: the Standard document button generates a Markdown document for the team: table and column names, PK (with its most common type), FK, constraint names, requirements, key and data type advice, and the rule severity table. For each item, right examples come from names that follow the standard and wrong examples from the audit findings under that standard, i.e. from the team's own schema. With no saved standard yet, the document is generated from the proposal and says so.
?doc=1opens it. - Accepting: Accept current findings as debt in the window records the current findings. Recorded findings sit in a separate Accepted debt list, are not counted as errors and are not coloured on the map. From then on only new findings stand out: a table without a PK brought by a new migration shows up at once.
- Progress: fixed findings count as paid-off debt; a bar shows how much of the debt has been paid.
- Sharing with the team: Download project file writes the debt register (and saved views) to
<name>.sqlschema.json. Put it in the schema folder and commit it: everyone who opens the folder sees the same debt. The file does not contain the schema. - Storage: the register is also kept in the browser under the project name, so it survives new migrations. Between the folder's file and the browser's copy, the newer one wins.
- Identity: a finding is matched by rule, table and column name. If a table is renamed, its findings count as new.
- What is generated:
- missing FKs and FK indexes, with
ENABLE NOVALIDATEon Oracle,NOT VALIDon PostgreSQL andWITH NOCHECKon SQL Server as an option - enabling a disabled FK (with a query that finds orphan rows first)
- dropping a redundant index
- adding a PK (the column name follows the schema's dominant PK naming)
- widening an FK column
- converting text dates, text numbers,
FLOATamounts andCLOBs: new column, copy, verify, drop the old column, rename - renaming system-named constraints and columns with Turkish characters, a different case or an unclear name
- missing FKs and FK indexes, with
- Risk: each suggestion is marked safe (indexes, FKs, constraint names), review (adding a PK, dropping an index, widening a type) or risky (data conversion, renames). Risky ones are left out of the script by default.
- Notes: each step carries an explanation ("change the date format to match your data", "application code using this name must be updated too"). Validation steps to run after the data is cleaned are written as comments. Steps that rename a table come last.
- Fixed by hand: no SQL is generated for cycles, EAV, repeating columns or findings that need a new name to be chosen; they need a design decision.
- Use: with a debt register, SQL is generated for new findings only. The script is copied or downloaded as
.sql. In the panel, each finding also shows its own SQL. - Tested: the tests add the generated script to the samples as a new migration and audit again, checking that the fixed findings disappear and no new ones appear.
- Opening: with a comparison (before → after) or the timeline active, Review report in the compare window. The audit window also shows a summary of the change at the top.
- What counts: findings in "after" but not in "before" came with this change; the reverse were resolved. Renamed tables are matched, so an old finding does not reappear as "new" under a new name. Findings in the debt register are not counted. If a rule could not run before (the dump had no indexes) but runs after, its findings on unchanged tables are not counted as new.
- Report: Markdown to paste into a PR comment: added, changed and removed table counts, new findings by severity, and resolved findings. Optionally, safe and review-level fix SQL in a collapsible section.
- Link:
?diff=V14&review=1opens the report. - Exit code: 0 below the threshold, 1 for new findings at or above it, 2 for usage errors or when no schema is found.
- Findings in the debt register and (in review mode) findings that existed before the change do not count towards the threshold.
- Node 18+ is enough; there are no dependencies. Files are only read and no network requests are made; the schema does not leave the team's machine or CI server.
- Scope: the whole schema, a single schema, the sub-diagram or the picked tables. A relationship is written only when both ends are in scope.
- The preview shortens long output; the copied and downloaded text is complete.
?export=mermaidopens the window with that format. - Classification: five categories from the column name, comment and table name:
- Identity: national ID, name, date of birth, gender, nationality
- Contact: phone, MSISDN, email, address and the rows of an address table
- Financial: IBAN, card number and card token, salary, income
- Location / device: IP, IMEI, IMSI, ICCID, coordinates
- Special category (KVKK art. 6, cf. GDPR art. 9): diagnosis, prescription, allergy, blood type, religion, trade union, biometric data. Every row of tables such as diagnoses and prescriptions also counts.
- Tables that relate to a person: tables linked to personal-data tables by an FK or
@ref(along the chain): an invoice line relates to the customer through the account. The panel shows which table it goes through and in how many steps. - To keep false alarms down:
- Key columns are not data (
ADDRESS_IDis the address row's identifier, not the address). - Code catalogues (ICD-10, a drug list) and the location of infrastructure (cell sites, ATMs) are not personal.
- Location data counts only in a table directly linked to a person.
- Technical addresses (servers, eSIM servers) and device fingerprints are told apart.
- Key columns are not data (
- Show on map: tables with special-category data in red, with personal data in yellow, those relating to a person in blue; personal-data columns are tinted on the card.
- Inventory: downloaded as CSV (Excel) and Markdown.
- Link:
?privacy=1opens the map,?pop=privacythe window. - Views and relationships expressed only through views are not drawn.
- Inferred relationships rely on column names only; schemas with inconsistent naming can produce missing or extra links. In MongoDB, fields such as
authorIdthat do not match a collection name are not linked. CREATE TABLE … AS SELECTtables appear without columns.- When a MongoDB schema comes from sample documents, only fields seen in those documents are listed.
- Dynamic Mongoose schemas built from variables (
new Schema(buildFields())) are not read. - For EF Core only the model snapshot (
ModelSnapshot.cs) and migration files are read; entity classes and the fluent API inOnModelCreatingare not. Model code of other ORMs (Hibernate, Django, Rails …) is not read; their SQL output can be used (see Exporting a schema). - If a file cannot be read (broken or truncated), the other files are still drawn; the unreadable file is listed with its error under files.
- Contribution guide: CONTRIBUTING.md
- Code of conduct: CODE_OF_CONDUCT.md
- Reporting a vulnerability: SECURITY.md
- Changelog: CHANGELOG.md
- Project guide for AI coding agents: AGENTS.md

Debt register: forgive the past, audit the future. In a messy database the first audit finds hundreds of problems, and fixing hundreds of old tables at once is not realistic.
Fix suggestions. Fix script in the window generates dialect-specific SQL for the findings that can be fixed (Oracle, PostgreSQL, SQL Server, MySQL / MariaDB, SQLite):

Change review (PR). To catch problems in a new migration's PR before they reach production:

Command line and CI. The same audit, debt register and change review run without a browser, so PRs are not skipped when reviewing by hand:
node tools/sqlschema-lint.js db/migration --since V15 --format md --fail-on error| Option | Purpose |
|---|---|
<file|folder>... |
the schema to check; folders are scanned recursively |
--since V15 |
review V15 and later in a migration folder (before = the versions before V15) |
--baseline <path> |
review against this copy (e.g. the main branch's schema) |
--project <file> |
project file (standard, rule severities, debt); by default *.sqlschema.json in the folder is read |
--format text|md|json|sarif |
text, Markdown for PR comments, JSON, or SARIF for GitHub code scanning |
--fail-on error|warning|info|none |
exit code 1 if there are new findings at this severity (default error) |
--fix <file> |
write the safe and review-level fix SQL to a file |
--out <file>, --lang tr|en, --separate |
output file, language, treat folders as separate databases |
GitHub Actions example: writes the findings a PR brings as a comment, fails the check on errors and uploads SARIF to code scanning. The same command runs in GitLab CI and Jenkins.
name: sqlSchema
on: pull_request
permissions: { contents: read, pull-requests: write, security-events: write }
jobs:
schema-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-node@v4
with: { node-version: 20 }
# pin to a release tag
- run: git clone --depth 1 --branch v0.13.0 https://github.com/umitkrkmz/sqlSchema.git ../sqlschema
- run: git worktree add ../base origin/${{ github.base_ref }}
- run: node ../sqlschema/tools/sqlschema-lint.js db/migration --baseline ../base/db/migration --format md --out review.md --fail-on error
- if: always()
run: gh pr comment ${{ github.event.pull_request.number }} --body-file review.md
env: { GH_TOKEN: ${{ github.token }} }
- if: always()
run: node ../sqlschema/tools/sqlschema-lint.js db/migration --baseline ../base/db/migration --format sarif --out sqlschema.sarif --fail-on none
- if: always()
uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: sqlschema.sarif }
The Flawed design (DBA review) sample was made for this feature: migrations three developers carelessly added to a clean baseline. Every rule fires at least once.
Export in the toolbar gives the schema as a document or in another tool's format. Files are generated in the browser; the schema is not sent anywhere.
| Format | Content | Use |
|---|---|---|
| Markdown data dictionary | Contents; per table a comment, a column table (type, nullability, key, comment, code values) and relationships (mandatory / optional, @ref condition, inferred) |
Wiki, Git, Confluence |
Mermaid erDiagram |
Crow's foot as is; identifying relationships solid, others dashed | Rendered directly in GitHub / GitLab Markdown |
| PlantUML | IE notation; PK columns above the line, * mandatory |
Corporate documentation tools |
| DBML | Tables, notes, composite PKs; declared FKs as Ref, @ref and inferred relationships as comments |
dbdiagram.io |
| CSV | Schema, table, column, type, nullability, PK, reference, comment, values | Excel (; separator in Turkish, UTF-8) |
| SVG | Cards with the map's layout, lines attached to column rows, crow's foot | Slides, print, posters |
"Which tables hold personal data? If we have to delete or mask a customer's data, where do we look?" privacy in the bottom bar works this out from the schema (the categories follow Turkey's KVKK, which closely mirrors the GDPR):
Findings are guesses from names and comments, not legal advice; verify the inventory with the data controller and legal team.
The samples under samples/ are synthetic: they do not belong to any real organisation. Each imitates the typical structure of a sector and the real export format of a tool. Open them from the Samples menu.
| Sample | Database | Scenario |
|---|---|---|
| Small telecom | Oracle | 20 tables, embedded in the app |
| Telecom BSS/OSS | Oracle | SQL Developer dump in one file: 318 tables, 16 schemas, partitions, triggers, packages |
| Telecom, one file per schema | Oracle | The same schema split into 16 files; all FKs in the final file |
| Core banking | SQL Server | SSMS "Generate Scripts": UTF-16, GO, IDENTITY, descriptions |
| Insurance (legacy system) | Oracle | A folder per module, Turkish names, no FKs at all |
| Marketplace e-commerce | MySQL | mysqldump --no-data, a DELIMITER procedure |
| Hospital information system | PostgreSQL | OMOP CDM layout: tables, PKs, FKs, indexes and comments in separate files |
| Logistics / parcel delivery | PostgreSQL | Flyway, 14 versions: renamed and dropped tables, partitioning |
| IoT telemetry | Cassandra | Two keyspaces, table-per-query design |
| Social network | MongoDB | $jsonSchema + Mongoose + mongoexport |
| Field service mobile app | SQLite | sqlite3 .dump, offline cache |
| Polyglot e-commerce | MySQL + MongoDB + PostgreSQL | Microservices, one galaxy per folder |
| Mixed naming | Oracle | Two teams, two habits: PK ID and <TABLE>_ID, irregular FKs, ORM tables |
| Lookup-heavy | Oracle | Every code lives in a single SOZLUK table; more than 30 columns point to it with @ref |
| Flawed design (DBA review) | Oracle | Careless migrations added to a clean schema; every audit rule fires |
| Dealer portal (EF Core) | SQL Server | A .NET application's three-version migration history and ModelSnapshot.cs together with the DBA's reporting and archive scripts: owned types, TPH / TPT, many-to-many |
| Database | How |
|---|---|
| Oracle, SQL Developer | Tools → Database Export, DDL only. The "separate files per object type" output can be opened as a folder. |
| Oracle, SQL*Plus / SQLcl | The DBMS_METADATA script below |
| SQL Server | SSMS → database → Tasks → Generate Scripts (schema only) |
| MySQL / MariaDB | mysqldump --no-data mydb > schema.sql |
| PostgreSQL | pg_dump --schema-only mydb > schema.sql |
| SQLite | sqlite3 app.db .schema > schema.sql |
| Cassandra | cqlsh -e "DESCRIBE KEYSPACE telemetry" > schema.cql |
| MongoDB | Validator scripts, the Mongoose models folder, or mongoexport --limit 1000 output |
For projects that use migrations, open the db/migration folder as it is.
-- Oracle: DDL and comments from the data dictionary
SET LONG 20000000 LONGCHUNKSIZE 20000000 PAGESIZE 0 LINESIZE 32767 TRIMSPOOL ON FEEDBACK OFF
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', FALSE);
SPOOL schema.sql
SELECT DBMS_METADATA.GET_DDL('TABLE', table_name, owner) FROM all_tables WHERE owner IN ('CRM', 'BILLING');
SELECT DBMS_METADATA.GET_DEPENDENT_DDL('COMMENT', table_name, owner) FROM all_tables t
WHERE owner IN ('CRM', 'BILLING')
AND (EXISTS (SELECT 1 FROM all_tab_comments c WHERE c.owner = t.owner AND c.table_name = t.table_name AND c.comments IS NOT NULL)
OR EXISTS (SELECT 1 FROM all_col_comments c WHERE c.owner = t.owner AND c.table_name = t.table_name AND c.comments IS NOT NULL));
SPOOL OFFIf the schema is defined in code (ORM, "code first"). sqlSchema does not read ORM code (except the EF Core model snapshot and Mongoose), but every ORM can give the schema as SQL, and in the end the database is the same:
| Tool | Getting the SQL |
|---|---|
| EF Core | Open Migrations/*ModelSnapshot.cs directly (see EF Core); for SQL, dotnet ef migrations script -o schema.sql (all migrations) or dotnet ef dbcontext script -o schema.sql (the model as it is today) |
| Hibernate / JPA | The jakarta.persistence.schema-generation.scripts.action=create and ...scripts.create-target=schema.sql settings write a DDL file. With Flyway, open the db/migration folder directly; with Liquibase, liquibase update-sql |
| Django | python manage.py sqlmigrate <app> <number> for each migration; or apply the migrations to a test database and take a dump as above |
| Rails | config.active_record.schema_format = :sql, then bin/rails db:schema:dump → db/structure.sql |
| Prisma | Open the prisma/migrations folder directly (the timeline works too); for a single file, prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script |
| Alembic | alembic upgrade head --sql > schema.sql (offline mode) |
| Diesel | Open the migrations folder directly |
| Others | Apply the migrations to a test database and take a dump as in the table above |
If some tables come from the ORM and others from DBA scripts, open both outputs together. compare also shows the difference between the schema the ORM generates and a database dump.
The interface is available in Turkish and English. On first visit Turkish is chosen if the system language is Turkish, English otherwise. Switch with the TR / EN buttons in the top-right corner; the choice is remembered in the browser. Use ?lang=tr or ?lang=en to pin the language in a link.
Shareable links. URL parameters open a sample, a table and a zoom level directly:
index.html?lang=en&sample=telekom&select=BILLING_ACCOUNT&zoom=0.9&legend=0
Add pop=naming, pop=report or pop=files to open a window on load. center=TABLE centres a table without selecting it.
index.html page shell, legend
style.css styles
js/ loaded in this order; each file adds to the globalThis.sqlSchema namespace
i18n.js Turkish / English dictionaries, language selection
lexer.js tokenizer, statement splitter, dialect detection
sql-parser.js DDL → ordered operation list (create, fk, rename, drop ...)
mongo.js the same operation list from $jsonSchema, Mongoose and JSON documents
efcore.js the same operation list from the EF Core model snapshot and migration files
files.js file ordering (Flyway, golang-migrate, Prisma, Diesel, EF Core), parser selection
model.js applies operations: tables, relationships, cardinality, junctions, inference; impact analysis, paths
diff.js difference of two models: tables, columns, PK, FK, UNIQUE; rename guesses; timeline
layout.js database → schema → constellation → star, hierarchical force layout
conventions.js naming profile: patterns, shares, names that depart from the dominant pattern
audit.js design audit: rules and findings (returns codes; text lives in the UI)
fixes.js fix suggestions: dialect-specific SQL, risk level
migrate.js SQL draft that closes a diff: phases, dependency order, notes
export.js export: Markdown data dictionary, Mermaid, PlantUML, DBML, CSV
privacy.js personal data map: personal-data columns, tables relating to a person
sample-small.js embedded small sample
render.js canvas drawing, camera, crow's feet
ui.js loading, file list, search, panel, report, URL parameters
samples/ synthetic samples and catalog.js (generated)
tools/ command-line audit (sqlschema-lint.js), sample and screenshot generators, sector definitions
tests/run.js checks every sample, parser edge cases and translations
docs/images/ README images (tr/ and en/)
Development commands (Node 18+, no dependencies):
node tests/run.js # tests
node tools/gen-samples.js # regenerate samples/
node tools/screenshots.js http://localhost:8000/ # refresh README images (needs Chrome)The parser, model, layout and naming profile never touch the DOM and can be required in Node. window.sqlSchema is exposed for inspection in the console:
sqlSchema.S.model.tables.filter(t => t.junction).map(t => t.name)
sqlSchema.loadText('CREATE TABLE a (id int PRIMARY KEY);', 'test.sql')When reporting a bug, please do not share a schema that belongs to a real organisation; renaming the tables is enough.
Released under the MIT license.



































