Ş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
- Adlandırma profili
- Ö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.
- 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), ç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.
- Ölçek: 2 862 tabloluk 4,7 MB'lık bir döküm yaklaşık 0,6 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 |
↑ / ↓, Enter |
Paneldeki ilişkiler arasında dolaş, seçilen tabloya git |
Alt + ← / → |
Gezinme geçmişinde geri / ileri |
Esc |
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 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.
Ç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.
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. |
| 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
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 |
Çizime girmeyenler. View, sequence, trigger, package, procedure, function, type, grant ve INSERT raporda sayılır ama çizilmez. 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.
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 |
- 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.
- 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ı.
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ı |
| 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 OFFArayü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
files.js dosya sıralama (Flyway, golang-migrate), ayrıştırıcı seçimi
model.js işlemleri uygular: tablolar, ilişkiler, kardinalite, ara tablo, tahmini ilişki
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
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/ ö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.
- 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
- Naming profile
- 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.
- One file, many files or a whole folder: split dumps, migration folders (Flyway, golang-migrate), 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.
- Scale: a 4.7 MB dump with 2,862 tables opens in about 0.6 s, and 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 |
↑ / ↓, Enter |
Move through the panel's relationships, go to the chosen table |
Alt + ← / → |
Back / forward in the navigation history |
Esc |
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 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.
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.
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. |
| 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
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 |
Not drawn. Views, sequences, triggers, packages, procedures, functions, types, grants and INSERTs are counted in the report but not drawn. 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.
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 |
- 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.
- 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.
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 |
| 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 OFFThe 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
files.js file ordering (Flyway, golang-migrate), parser selection
model.js applies operations: tables, relationships, cardinality, junctions, inference
layout.js database → schema → constellation → star, hierarchical force layout
conventions.js naming profile: patterns, shares, names that depart from the dominant pattern
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/ 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')- 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.
- 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
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.













