{
    "version": "https://jsonfeed.org/version/1",
    "title": "Tunahan Ali Öztürk Blog",
    "home_page_url": "https://tunahanaliozturk.dev/tr/blog",
    "description": "Tunahan Ali Öztürk Blog",
    "items": [
        {
            "id": "https://tunahanaliozturk.dev/tr/blog/the-orion-family",
            "content_html": "<p>.NET backend'lerinin çoğu sonunda aynı düzine şeye ihtiyaç duyuyor: validation, distributed lock, audit\nkaydı, outbox, şifreli kolonlar, tipli ID'ler, idempotent endpoint'ler, rate limit, retry. Her ekip bunları\nyeniden yazıyor; her seferinde biraz farklı, her biri kendince biraz hatalı.</p>\n<p>Orion ailesi buna benim cevabım: bu problemlerin her biri için küçük, odaklı, tek bir kalite çıtasıyla\nyazılmış ve NuGet'te yayınlanmış kütüphaneler.</p>\n<p>Bugün 89 paket altında 24 kütüphane var ve 350 binden fazla kez indirildiler. Bu yazı neden var\nolduklarını, onları neyin bir arada tuttuğunu ve her birinin ne işe yaradığını anlatıyor.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"framework-değil-yapı-taşı\">Framework değil, yapı taşı<a href=\"https://tunahanaliozturk.dev/tr/blog/the-orion-family#framework-de%C4%9Fil-yap%C4%B1-ta%C5%9F%C4%B1\" class=\"hash-link\" aria-label=\"Framework değil, yapı taşı doğrudan bağlantı\" title=\"Framework değil, yapı taşı doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>Her Orion kütüphanesi tek bir problemi çözüyor ve kendi başına kullanılabiliyor. OrionLock'u bir lock'a\nihtiyacınız olduğu için eklersiniz, bir platforma üye olduğunuz için değil. Aralarında derin bir bağımlılık\nağı yok; sadece ihtiyacınız olanı alırsınız.</p>\n<p>Bu, bazen \"hayır\" demek anlamına da geliyor. OrionPatch bir transactional outbox; dokümanı saga'ların\nkapsam dışında olduğunu açıkça söylüyor: bir process manager'a ihtiyacınız varsa MassTransit ya da\nWolverine'e bakın. Nerede durduğunu bilen bir kütüphaneye, her şey olmak isteyen bir kütüphaneden daha\nkolay güvenilir.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"aileyi-bir-arada-tutan-şey\">Aileyi bir arada tutan şey<a href=\"https://tunahanaliozturk.dev/tr/blog/the-orion-family#aileyi-bir-arada-tutan-%C5%9Fey\" class=\"hash-link\" aria-label=\"Aileyi bir arada tutan şey doğrudan bağlantı\" title=\"Aileyi bir arada tutan şey doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>Kütüphaneleri birbiri ardına yazarken beş şeyin tekrar tekrar yazıldığını ve her seferinde birbirinden\nuzaklaştığını fark ettim:</p>\n<ul>\n<li class=\"\">observer'ları güvenli çağırmak; gözlemlenebilirlik tarafındaki bir arıza asıl işi yapan kodu asla\nbozmasın diye,</li>\n<li class=\"\">OpenTelemetry isimlendirmesi; her kütüphanenin trace ve metrikleri dashboard'da aynı görünsün diye,</li>\n<li class=\"\">testlerin kontrol edebildiği bir saat,</li>\n<li class=\"\">options ve DI kaydının şekli,</li>\n<li class=\"\">hataların ortak dili.</li>\n</ul>\n<p>Bunlar artık tek bir yerde, <code>Orion.Abstractions</code> içinde yaşıyor. Yüzeyi 1.0'da donduruldu: bütün\nsözleşmeler 1.x boyunca kaynak ve binary olarak uyumlu kalıyor; bir kütüphane, kardeşinin güncellemesiyle\nkırılmıyor. Bunlara eşlik eden kurallar yazılı ve ailedeki her paket için geçerli.</p>\n<p>Bu omurgadan iki kütüphane doğdu. <strong>OrionClock</strong> bir <code>TimeProvider</code>; onu kabul eden her .NET API'sine\ndoğrudan takılıyor ve testlerin beklemek yerine zamanı ileri sarmasını sağlıyor. <strong>OrionResult</strong> beklenen\nhatalara bir şekil veriyor: sıfır allocation'lı bir <code>Result&lt;T&gt;</code>, bir <code>Option&lt;T&gt;</code> ve kodu, türü ve alan\nhataları olan yapılandırılmış bir <code>Error</code>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ailede-neler-var\">Ailede neler var?<a href=\"https://tunahanaliozturk.dev/tr/blog/the-orion-family#ailede-neler-var\" class=\"hash-link\" aria-label=\"Ailede neler var? doğrudan bağlantı\" title=\"Ailede neler var? doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p><strong>Girdi ve domain</strong></p>\n<ul>\n<li class=\"\"><strong>OrionGuard</strong>: validation, guard clause'lar ve DDD yapı taşları; ASP.NET Core, MediatR, Blazor, gRPC,\nSignalR ve OpenTelemetry entegrasyonları, source generator'lar ve 14 dilde hata mesajları. Ailenin en çok\nkullanılanı.</li>\n<li class=\"\"><strong>OrionKey</strong>: tek bir attribute ile tipli ID'ler; eşitlik, EF Core ve JSON dönüştürücüleri sizin için\nüretiliyor.</li>\n</ul>\n<p><strong>Veri</strong></p>\n<ul>\n<li class=\"\"><strong>OrionAudit</strong>: JSON Patch farklarıyla otomatik EF Core audit kaydı ve bir entity'yi herhangi bir andaki\nhâliyle yeniden kurmak için zamanda yolculuk.</li>\n<li class=\"\"><strong>OrionVault</strong>: EF Core için kolon seviyesinde şifreleme: AES-256-GCM, anahtar rotasyonu ve şifreli\ndeğerlerde arama yapmak için blind index.</li>\n<li class=\"\"><strong>OrionPage</strong>: 10.000. sayfada bile hızlı kalan keyset pagination; çünkü <code>OFFSET</code> bir tablo taraması.</li>\n</ul>\n<p><strong>Mesajlaşma ve tutarlılık</strong></p>\n<ul>\n<li class=\"\"><strong>OrionPatch</strong> ve <strong>OrionInbox</strong>: güvenilir mesajlaşmanın iki yarısı. Aynı <code>SaveChanges</code> transaction'ı\niçinde kuyruğa al, en az bir kez gönder; karşı tarafta her mesajın etkisini tam bir kez uygula.</li>\n<li class=\"\"><strong>OrionSaga</strong>: süreç içi saga orkestrasyonu; bir adım başarısız olursa tamamlanan adımlar geri alınıyor.</li>\n<li class=\"\"><strong>OrionRelay</strong>: HMAC-SHA256 ile imzalanan, backoff ve jitter ile yeniden denenen giden webhook'lar.</li>\n</ul>\n<p><strong>Koordinasyon</strong></p>\n<ul>\n<li class=\"\"><strong>OrionLock</strong>: Redis, Postgres, SQL Server ya da EF Core üzerinde, lease yenilemeli ve fencing token'lı\ndistributed lock'lar.</li>\n<li class=\"\"><strong>OrionBeacon</strong>: leader election; bir kez çalışması gereken işi tam olarak bir instance çalıştırsın diye.</li>\n</ul>\n<p><strong>HTTP ve API'ler</strong></p>\n<ul>\n<li class=\"\"><strong>OrionOnce</strong>: idempotency key'ler; yeniden denenen bir istek iki kez çalışmak yerine saklanan cevabı\nalıyor.</li>\n<li class=\"\"><strong>OrionEnvelope</strong>: bütün API için tek bir HTTP sözleşmesi: başarıda tipli <code>{ data, meta }</code>, hatada RFC\n9457 problem details.</li>\n<li class=\"\"><strong>OrionRate</strong>: token-bucket ve sliding-window rate limiting.</li>\n<li class=\"\"><strong>OrionGrant</strong> ve <strong>OrionLedger</strong>: izinler ve politikalar; API key'lerin bütün yaşam döngüsü.</li>\n<li class=\"\"><strong>OrionStream</strong>: sınırlı buffer'lar ve heartbeat'lerle Server-Sent Events.</li>\n</ul>\n<p><strong>Her yerde işe yarayanlar</strong></p>\n<ul>\n<li class=\"\"><strong>OrionLens</strong> bir correlation id'yi async çağrılar ve HTTP boyunca taşıyor; <strong>OrionShade</strong> secret'ları ve\nkişisel verileri log'a ulaşmadan maskeliyor; <strong>OrionCache</strong> stampede yaşatmadan cache-aside yapıyor;\n<strong>OrionResilience</strong> OrionClock üzerinden jitter'lı retry yapıyor, böylece bir retry testi hiç zaman almıyor.</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"hepsi-bir-arada\">Hepsi bir arada<a href=\"https://tunahanaliozturk.dev/tr/blog/the-orion-family#hepsi-bir-arada\" class=\"hash-link\" aria-label=\"Hepsi bir arada doğrudan bağlantı\" title=\"Hepsi bir arada doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>Paket sayfaları kütüphaneleri tek tek gösteriyor. <strong>OrionShowcase</strong> ise birlikte nasıl çalıştıklarını\ngösteriyor: tek bir para transferinin OrionGuard'ın validation'ından, OrionLock'un distributed lock'larından,\nOrionAudit'in değişiklik kaydından, OrionPatch'in outbox'ından, OrionKey'in tipli ID'lerinden ve OrionVault'un\nşifreli kişisel verilerinden geçtiği, production'a benzeyen bir bankacılık örneği. Bu bütünü kurmak, tek bir\npaketin göründüğünden çok daha zor; örneğin bütün amacı bu.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"neden-paylaşıyorum\">Neden paylaşıyorum?<a href=\"https://tunahanaliozturk.dev/tr/blog/the-orion-family#neden-payla%C5%9F%C4%B1yorum\" class=\"hash-link\" aria-label=\"Neden paylaşıyorum? doğrudan bağlantı\" title=\"Neden paylaşıyorum? doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>Bunları ihtiyacım olduğu için yazdım; yayınlıyorum ki kimse onları yeniden yazmak zorunda kalmasın. Her\nkütüphane MIT lisanslı, dokümantasyonu bu sitede ve issue'lar GitHub'da açık. Veritabanı ya da mesaj\nkuyruğu gerektirmeyenleri doğrudan buradaki <a class=\"\" href=\"https://tunahanaliozturk.dev/tr/playground\">playground</a>'da deneyebilirsiniz.</p>\n<p>Birini kullanıyorsanız ya da denediniz ve işinize yaramadıysa, nedenini bilmek isterim. Birinin bana\nsöyleyebileceği en faydalı şey bu.</p>",
            "url": "https://tunahanaliozturk.dev/tr/blog/the-orion-family",
            "title": "Orion ailesini neden yaptım",
            "summary": ".NET backend'lerinin çoğu sonunda aynı düzine şeye ihtiyaç duyuyor: validation, distributed lock, audit",
            "date_modified": "2026-09-30T00:00:00.000Z",
            "author": {
                "name": "Tunahan Ali Öztürk",
                "url": "https://github.com/tunahanaliozturk"
            },
            "tags": [
                "dotnet",
                "orion",
                "open-source"
            ]
        },
        {
            "id": "https://tunahanaliozturk.dev/tr/blog/why-i-built-derbent",
            "content_html": "<p>Aynı repolarda birden fazla coding agent kullanıyorum. Claude Code bir işi yaparken Codex başka bir işi\nyapıyor, arada Copilot CLI'a bir şey soruyorum. Hepsi işini iyi yapıyor ama hiçbiri diğerlerinin ne\nyaptığını bilmiyor.</p>\n<p>Claude Code'un bir saat önce \"bu tablo neden böyle\" diye öğrendiğini Codex bilmiyor. Hangi agent'ın hangi\nkomutu çalıştırdığının tek bir kaydı yok. Her CLI'ın kendi MCP server listesi var; GitHub'ı dört kez\nbağlıyorum. Bir agent'ın <code>git push</code>'tan önce bana sormasını istesem, bunu dört ayrı yerde dört ayrı\nbiçimde ayarlamam gerekiyor.</p>\n<p>Derbent bu dağınıklığı toplamak için yazdığım, ücretsiz ve açık kaynak bir araç.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ne-yapıyor\">Ne yapıyor?<a href=\"https://tunahanaliozturk.dev/tr/blog/why-i-built-derbent#ne-yap%C4%B1yor\" class=\"hash-link\" aria-label=\"Ne yapıyor? doğrudan bağlantı\" title=\"Ne yapıyor? doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>Derbent, coding agent'larla araçları arasında duran bir kapı. Claude Code, Codex, GitHub Copilot CLI ve\nAntigravity CLI ona sıradan bir MCP server olarak bağlanıyor; sizin MCP server'larınız onun arkasına\ngeçiyor. Her tool çağrısı kapıdan geçiyor ve kapıda dört şey oluyor.</p>\n<p><strong>Ortak hafıza.</strong> Agent'ların <code>memory_write</code>, <code>memory_search</code> ve <code>memory_read</code> araçları var. Bir agent'ın\nbir repoda yazdığı notu, aynı repoda çalışan başka bir agent bulabiliyor. Arama tam metin; bir git\nworktree'si eklendiği repoyla aynı hafızayı paylaşıyor.</p>\n<p><strong>Kurallar.</strong> Agent, tool ve argümana göre izin ver, reddet ya da sor. Kurallar sırayla deneniyor, ilk\neşleşen kazanıyor. Bir agent'ın kullanamayacağı tool ona hiç listelenmiyor; ismini bilip çağırsa da\nreddediliyor.</p>\n<p><strong>Onay.</strong> \"Sor\" kuralına takılan çağrı siz karar verene kadar bekliyor. Ayrı bir terminalde <code>derbent</code>\nçalıştırınca bekleyen çağrılar en üstte: bir kez onaylarsınız, o agent'ın oturumunun geri kalanı için\nonaylarsınız ya da reddedersiniz. Aynısı herhangi bir shell'den <code>derbent approve 12</code> ile de oluyor. Kimse\ncevap vermezse süre dolunca çağrı reddediliyor ve agent'a nedeni söyleniyor.</p>\n<p><strong>Makbuz.</strong> Kapıdan geçen her çağrı bir makbuz bırakıyor: hangi agent, hangi tool, hangi argümanlar, ne\nkarar verildi, sonuç ne oldu. Makbuzlar bir hash zinciri oluşturuyor; <code>derbent verify</code> bir kaydın\ndeğiştirilip değiştirilmediğini ya da silinip silinmediğini söylüyor. Secret'lar kaydedilmeden önce\nmaskeleniyor.</p>\n<p>Agent'ların kendi araçları, yani shell komutları ve dosya düzenlemeleri, MCP'den geçmiyor. Ama dört CLI'ın\nda her tool çağrısından önce sizin belirlediğiniz bir komutu çalıştırabildiği bir hook mekanizması var. O\nkomutu <code>derbent gate</code> yapınca bir <code>git push</code> da aynı kurallardan, aynı onaydan ve aynı makbuz zincirinden\ngeçiyor.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"i̇sim\">İsim<a href=\"https://tunahanaliozturk.dev/tr/blog/why-i-built-derbent#i%CC%87sim\" class=\"hash-link\" aria-label=\"İsim doğrudan bağlantı\" title=\"İsim doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>Türk tarihinde derbent, dağ geçitlerindeki ve tehlikeli yollardaki muhafızlı karakollardı. Buraları bekleyen\nderbentçiler geçidin güvenliğinden sorumluydu, karşılığında bazı vergilerden muaf tutulurlardı.\nGeçitten kimin geçeceğine karar verir, geçenleri kayda geçirirlerdi.</p>\n<p>Denediğim her İngilizce kelime (gatekeeper, warden, checkpoint, bastion) ya başka bir güvenlik ürününün\nadıydı ya da fazla genel kalıyordu. Derbent hem yaptığı işi birebir anlatıyor hem de kimsenin kullanmadığı\nbir isim.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"nasıl-yapıldı\">Nasıl yapıldı?<a href=\"https://tunahanaliozturk.dev/tr/blog/why-i-built-derbent#nas%C4%B1l-yap%C4%B1ld%C4%B1\" class=\"hash-link\" aria-label=\"Nasıl yapıldı? doğrudan bağlantı\" title=\"Nasıl yapıldı? doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>En önemli karar: daemon yok. Akla ilk gelen şekil, bütün agent'ların bağlandığı merkezi bir süreç. Ama o\nmerkez her agent'tan önce başlatılmak, ayakta tutulmak, çökünce yeniden başlatılmak zorunda; dinlediği\nport da ayrıca korunmalı. Derbent'te her agent oturumu kendi kapı sürecini başlatıyor ve hepsi aynı SQLite\ndosyasını açıyor. Önceden çalışması gereken hiçbir şey yok, açık port yok, bir süreç çökerse sadece o\nagent'ın kapısı düşüyor.</p>\n<p>Bunun bir bedeli var ve dokümanda açıkça yazıyor: her agent oturumu kapının arkasındaki server'ların kendi\nkopyasını başlatıyor, onaylar da anında değil yoklamayla fark ediliyor.</p>\n<p>Go ile yazıldı. Claude Code her tool çağrısında <code>derbent gate</code> sürecini yeniden başlatıyor; yani her shell\nkomutu bir sürecin açılıp karar verip kapanmasını bekliyor. Go binary'si bir yorumlayıcı yüklemeden\nbaşlıyor; Windows, macOS ve Linux için tek bir dosya ve makinede başka hiçbir şey istemiyor.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"neyi-yapmıyor\">Neyi yapmıyor?<a href=\"https://tunahanaliozturk.dev/tr/blog/why-i-built-derbent#neyi-yapm%C4%B1yor\" class=\"hash-link\" aria-label=\"Neyi yapmıyor? doğrudan bağlantı\" title=\"Neyi yapmıyor? doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<p>Derbent'in yapmadıklarını yazmak, yaptıklarını yazmak kadar önemliydi.</p>\n<ul>\n<li class=\"\"><strong>Agent ismi bir etiket, kimlik doğrulama değil.</strong> Sizin kullanıcınızla çalışan her süreç kendine\nistediği ismi verebilir.</li>\n<li class=\"\"><strong>Zaten sizin yetkinizle shell'i olan bir agent'a karşı sınır değil.</strong> Böyle bir agent <code>derbent approve</code>\nkomutunu kendisi çalıştırabilir ya da veritabanına yazabilir. Onaylar hatalara ve MCP içinde kalan\nprompt injection'a karşı koruyor.</li>\n<li class=\"\"><strong>Zincir her şeyi tek başına yakalamaz.</strong> Ortadaki değişiklikleri buluyor; sondan kesilmiş kayıtlar ya da\nbaştan yeniden yazılmış bir zincir, ancak başka bir yerde sakladığınız son hash ile karşılaştırınca\nortaya çıkıyor.</li>\n<li class=\"\"><strong>Glob kuralları shell sözdizimini anlamaz.</strong> <code>git push*</code> kuralı <code>cd repo &amp;&amp; git push</code> komutunu yakalamaz.</li>\n</ul>\n<p>Bir güvenlik aracının yapabileceği en kötü şey, olduğundan fazlasını vaat etmek. Sınırlarını bilerek\nkullanılan Derbent çok işe yarar; sınırları bilinmeden güvenilen Derbent zarar verir.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"denemek-için\">Denemek için<a href=\"https://tunahanaliozturk.dev/tr/blog/why-i-built-derbent#denemek-i%C3%A7in\" class=\"hash-link\" aria-label=\"Denemek için doğrudan bağlantı\" title=\"Denemek için doğrudan bağlantı\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">go </span><span class=\"token function\" style=\"color:#d73a49\">install</span><span class=\"token plain\"> github.com/tunahanaliozturk/derbent/cmd/derbent@latest</span><br></div><div class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></div><div class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">claude mcp </span><span class=\"token function\" style=\"color:#d73a49\">add</span><span class=\"token plain\"> derbent -- derbent mcp </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--agent</span><span class=\"token plain\"> claude</span><br></div><div class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">codex mcp </span><span class=\"token function\" style=\"color:#d73a49\">add</span><span class=\"token plain\"> derbent -- derbent mcp </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--agent</span><span class=\"token plain\"> codex</span><br></div></code></pre></div></div>\n<p>Bu kadarıyla iki agent aynı hafızayı paylaşmaya başlıyor ve her çağrı kayda geçiyor. Kurallar, onaylar ve\nhook'lar için <a href=\"https://derbent.dev/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">dokümantasyona</a> bakabilirsiniz.</p>\n<p>Birden fazla coding agent kullanıyorsanız fikrinizi çok isterim; özellikle hangi çağrıların onaya düşmesini\nistediğinizi merak ediyorum. Issue'lar ve fikirler için <a href=\"https://github.com/tunahanaliozturk/derbent\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">GitHub</a>.</p>",
            "url": "https://tunahanaliozturk.dev/tr/blog/why-i-built-derbent",
            "title": "Derbent'i neden yaptım",
            "summary": "Aynı repolarda birden fazla coding agent kullanıyorum. Claude Code bir işi yaparken Codex başka bir işi",
            "date_modified": "2026-09-29T00:00:00.000Z",
            "author": {
                "name": "Tunahan Ali Öztürk",
                "url": "https://github.com/tunahanaliozturk"
            },
            "tags": [
                "derbent",
                "ai-agents",
                "mcp"
            ]
        }
    ]
}