Takip et

Multi-Tenant RAG: Motia ve SpiceDB ile Kapsamlı Yetkilendirme

Modern yapay zeka uygulamaları, özellikle Retrieval-Augmented Generation (RAG) sistemleri, bilgiye erişimi devrim niteliğinde kolaylaştırıyor. Ancak bu sistemleri birden fazla kiracının (örneğin, farklı şirketler veya departmanlar) kullanabileceği çok kiracılı (multi-tenant) bir yapıda kurmak, veri güvenliği ve hassas yetkilendirme konusunda ciddi zorluklar doğurabilir. Peki, veri sızıntısı riskini ortadan kaldırırken her kullanıcının sadece yetkili olduğu bilgilere erişmesini nasıl sağlayabiliriz?

Günümüz iş dünyasında, yapay zeka tabanlı çözümler verimliliği artırmanın ve rekabet avantajı sağlamanın anahtarı haline gelmiştir. Özellikle RAG (Retrieval-Augmented Generation) mimarileri, büyük dil modellerinin (LLM) güncel ve kurum içi verilerle zenginleştirilerek daha doğru ve bağlamsal yanıtlar üretmesini sağlamaktadır. Bir müşteri destek sistemi düşünün; farklı şirketlerin temsilcileri, kendi şirketlerinin iç politikaları, ürün bilgileri ve müşteri kayıtları hakkında anında doğru bilgiye ulaşmak ister. Ancak bu noktada kritik bir soru ortaya çıkar: Bir şirket temsilcisinin başka bir şirketin hassas verilerine erişimi nasıl engellenecek? İşte bu, çok kiracılı RAG sistemlerinin en büyük meydan okumalarından biridir ve bu sorunun cevabı, güçlü bir yetkilendirme mekanizmasında yatmaktadır. Bu gibi senaryolarda, veri güvenliğini sağlamak sadece bir tercih değil, yasal uyumluluk (KVKK, GDPR gibi) ve müşteri güveni açısından mutlak bir zorunluluktur.

Ölçeklenebilirlik, modern yazılım sistemlerinin temel taşlarından biridir. Bir RAG uygulamasını, başlangıçta küçük bir kullanıcı grubu için tasarlayıp daha sonra yüzlerce veya binlerce kiracıya hizmet verecek şekilde büyütmek istediğinizde, altyapınızın bu yükü kaldırabilmesi gerekir. Her kiracı için ayrı bir RAG altyapısı kurmak, maliyetli ve yönetimi zor bir çözüm olacaktır. Bu nedenle, çok kiracılı bir mimari, kaynakları verimli kullanarak maliyetleri düşürmenin ve yönetimi kolaylaştırmanın en etkili yoludur. Ancak bu verimlilik arayışı, güvenlikten ödün vermemeyi gerektirir. Her kiracının verisinin diğerlerinden tamamen izole edilmesi, sorgu performansının düşmemesi ve yetkilendirme kararlarının milisaniyeler içinde alınması, tasarım sürecinin temel öncelikleridir. Bu zorlu dengeyi sağlamak için Motia gibi RAG geliştirmeyi kolaylaştıran bir çerçeve ile SpiceDB gibi ince taneli yetkilendirme çözümlerini bir araya getirmek, hem geliştirici verimliliğini artıracak hem de nihai ürünün sağlamlığını garanti edecektir. Geleceğin yapay zeka uygulamaları, sadece akıllı olmakla kalmayacak, aynı zamanda güvenli ve ölçeklenebilir de olmak zorunda.

Temel Kavramlar Nelerdir? RAG, Çok Kiracılılık ve İnce Taneli Yetkilendirme

Bu karmaşık konuyu anlamak için öncelikle temel yapı taşlarını netleştirmemiz gerekiyor. RAG, çok kiracılılık ve ince taneli yetkilendirme, birbiriyle sıkıca bağlantılı üç kritik kavramdır ve her birini ayrı ayrı ele almak, entegre çözümümüzün neden bu kadar güçlü olduğunu anlamamızı sağlayacaktır.

  • RAG (Retrieval-Augmented Generation) Nedir?

    RAG, büyük dil modellerinin (LLM’ler) bilgi oluşturma yeteneklerini, harici bir bilgi tabanından (örneğin, belgeler, veritabanları, web sayfaları) ilgili bilgiyi alma (retrieval) yeteneğiyle birleştiren bir yapay zeka mimarisidir. Geleneksel LLM’ler, eğitim verilerinde öğrendikleri bilgilerle sınırlıdır ve “halüsinasyon” olarak adlandırılan yanlış veya uydurma bilgiler üretebilirler. RAG, bu sorunu çözmek için tasarlanmıştır. Bir kullanıcı sorgusu geldiğinde, sistem önce bir vektör veritabanı veya arama motoru aracılığıyla ilgili belgeleri veya metin parçacıklarını bulur. Daha sonra bu alınan bilgiler (context), orijinal sorgu ile birlikte LLM’e sunulur. Böylece LLM, güncel, doğru ve spesifik verilere dayanarak yanıt üretir. Bu yaklaşım, LLM’lerin doğruluğunu, güncelliğini ve şeffaflığını önemli ölçüde artırır, özellikle kurumsal ortamlarda kritik bir avantaj sağlar. Motia, bu RAG pipeline’ını oluşturmayı ve yönetmeyi kolaylaştıran bir çerçeve olarak öne çıkar.

  • Çok Kiracılılık (Multi-Tenancy) Kavramı ve Zorlukları Nelerdir?

    Çok kiracılılık, bir yazılım uygulamasının ve altyapısının birden fazla müşteriye veya “kiracıya” hizmet verecek şekilde tasarlandığı bir yazılım mimarisidir. Her kiracı, uygulamayı kendi özelleştirilmiş ve izole edilmiş bir örneği gibi görür, ancak aslında tüm kiracılar aynı temel kodu ve genellikle aynı altyapıyı paylaşır. Bunun en büyük avantajları maliyet verimliliği (kaynak paylaşımı), kolay yönetim ve daha hızlı dağıtımdır. Örneğin, bir SaaS şirketinin ürünü, yüzlerce farklı şirkete aynı uygulama üzerinden hizmet verebilir. Ancak çok kiracılı mimarinin önemli zorlukları da vardır: Veri izolasyonu, her kiracının verisinin diğerlerinden tamamen ayrı tutulması hayati önem taşır. Güvenlik, bir kiracının verilerinin yanlışlıkla veya kötü niyetle diğer kiracılara ifşa edilmemesi gerekir. Performans, bir kiracının yüksek yükünün diğer kiracıların performansını etkilememesi sağlanmalıdır. Bu zorluklar, özellikle hassas verilerle çalışan RAG sistemlerinde, güçlü bir yetkilendirme ve erişim kontrolü mekanizmasını zorunlu kılar.

  • İnce Taneli Yetkilendirme (Fine-Grained Authorization) Ne Anlama Geliyor?

    Yetkilendirme, bir kullanıcının veya sistemin belirli bir kaynağa (örneğin, bir belge, bir özellik, bir API uç noktası) erişip erişemeyeceğini belirleme sürecidir. Geleneksel olarak, yetkilendirme genellikle rol tabanlı (RBAC – Role-Based Access Control) veya ACL (Access Control List) gibi daha geniş seviyelerde uygulanır. RBAC’ta, kullanıcılara “yönetici”, “editör” veya “okuyucu” gibi roller atanır ve bu roller belirli izin setleriyle ilişkilendirilir. Ancak ince taneli yetkilendirme, bu yaklaşımı bir adım öteye taşır. Kaynaklara erişimi çok daha detaylı bir seviyede kontrol etmeyi sağlar. Örneğin, bir kullanıcının sadece belirli bir projenin içindeki belirli bir belgenin “sadece okunabilir” kopyasına erişimi olması, ama o belgenin “düzenleme” yetkisinin olmaması ince taneli yetkilendirmedir. Bir başka örnek: Bir muhasebe departmanındaki bir kullanıcının sadece kendi bölgesindeki müşterilerin finansal raporlarına erişimi olması, diğer bölgelerdeki raporlara olmaması. Bu seviyede bir kontrol, özellikle karmaşık ve çok kiracılı ortamlarda veri güvenliğini ve uyumluluğu sağlamak için vazgeçilmezdir. İşte SpiceDB, bu karmaşık ince taneli yetkilendirme modellerini hızlı ve ölçeklenebilir bir şekilde yönetmek için tasarlanmış bir çözümdür.

Motia ve SpiceDB Neden İdeal Bir İkili?

Modern bir çok kiracılı RAG sisteminin karmaşıklığını ve güvenlik gereksinimlerini karşılamak için doğru araçları seçmek, projenin başarısı için hayati öneme sahiptir. Motia ve SpiceDB’nin birlikte ele alındığında neden bu kadar güçlü bir ikili oluşturduğunu anlamak, mimarimizin temelini atacaktır.

Motia: RAG Uygulamalarında Hız ve Esneklik

Motia, yapay zeka uygulamaları, özellikle de RAG tabanlı çözümler geliştirmek için tasarlanmış bir framework’tür. Temel amacı, geliştiricilerin büyük dil modelleri ve harici veri kaynakları arasındaki entegrasyonu kolaylaştırmaktır. Bir RAG pipeline’ı kurmak, genellikle karmaşık adımlar içerir: verilerin alımı (ingestion), vektörleştirilmesi, vektör veritabanına kaydedilmesi, kullanıcı sorgularının işlenmesi, ilgili belgelerin alınması (retrieval) ve son olarak LLM’in bu bilgilerle beslenerek yanıt üretmesi. Motia, bu adımların çoğunu soyutlayarak veya kolaylaştırarak geliştiricilerin asıl iş mantığına odaklanmasına olanak tanır. Örneğin, farklı vektör veritabanları veya LLM sağlayıcıları arasında geçiş yapmayı basitleştirir, böylece teknoloji seçiminde esneklik sunar. Motia’nın modüler yapısı, RAG akışının özelleştirilmesine ve çeşitli entegrasyonların kolayca yapılmasına imkan verir. Bu da onu, çok kiracılı bir yapıda her kiracı için özelleştirilmiş RAG deneyimleri sunmak isteyen geliştiriciler için cazip kılar.

SpiceDB: Yetkilendirme Kararlarında Güvenilirlik ve Ölçeklenebilirlik

SpiceDB, Google’ın dahili yetkilendirme sistemi Zanzibar’dan ilham alan açık kaynaklı, yüksek performanslı bir yetkilendirme veritabanıdır. Geleneksel yetkilendirme sistemlerinden farklı olarak, SpiceDB ilişkisel bir model kullanır. Bu model, “kullanıcı, bir belgeyi okuyabilir” veya “grup X’in tüm üyeleri, bir klasördeki tüm belgelere erişebilir” gibi karmaşık yetkilendirme ilişkilerini tanımlamanıza olanak tanır. En önemlisi, bu ilişkileri milisaniyeler içinde sorgulayabilir ve tutarlı yetkilendirme kararları verebilir. SpiceDB’nin temel gücü, yetkilendirme modelinizi bir şema (schema) olarak tanımlamanıza olanak tanımasıdır. Bu şema, sisteminizdeki kaynaklar (belge, kiracı, klasör vb.) ve bu kaynaklar üzerindeki izinler (okuma, yazma, düzenleme vb.) arasındaki ilişkileri açıkça belirtir. Bu sayede, “hangi kullanıcının hangi belgeye hangi izinle erişimi var?” gibi sorulara hızlı ve doğru yanıtlar alabilirsiniz. Ölçeklenebilirlik açısından, SpiceDB’nin mimarisi, yüksek yük altında bile düşük gecikme süresi ve yüksek verimlilik sağlayacak şekilde tasarlanmıştır. Bu da onu, binlerce kiracının milyonlarca belgeye erişim yetkilerini yönetmesi gereken çok kiracılı RAG sistemleri için ideal bir çözüm haline getirir.

Birlikteki Güçleri: Motia ve SpiceDB Synergy

Motia ve SpiceDB, birbirlerini mükemmel bir şekilde tamamlarlar. Motia, RAG sürecinin mekanik kısımlarını soyutlayarak ve kolaylaştırarak geliştiricilerin içeriğe odaklanmasını sağlarken, SpiceDB bu içeriğe kimin erişebileceğini belirleyen güçlü ve esnek bir omurga sunar. Şöyle bir senaryo düşünelim: Bir şirket (kiracı) kendi iç belgelerini Motia tabanlı bir RAG sistemine yükler. Bu belgeler, farklı departmanlara veya projelere ait olabilir ve farklı hassasiyet seviyelerine sahip olabilir. Örneğin, “Finans Departmanı”ndaki “Ayşe” sadece kendi departmanının “Bütçe Raporları”na erişebilirken, “İK Departmanı”ndaki “Fatma” sadece “Çalışan El Kitabı”nı görüntüleyebilir. Motia, Ayşe’nin “Bütçe Raporları” hakkında sorduğu bir soruyu işlerken, SpiceDB’ye başvurarak Ayşe’nin bu raporlara gerçekten erişim yetkisi olup olmadığını kontrol eder. Eğer yetki varsa, Motia sadece bu yetkili belgeler arasından bilgi çeker ve LLM’e sunar. Bu entegrasyon, bir yandan kullanıcıya sorunsuz ve doğru bir bilgi erişim deneyimi sunarken, diğer yandan kiracılar arası veri izolasyonunu ve ince taneli erişim kontrolünü garantiler. Bu sayede, hem geliştirme süreci hızlanır hem de nihai uygulamanın güvenliği ve ölçeklenebilirliği sağlanır.

Multi-Tenant RAG Sistemi Nasıl Tasarlanır? Mimari Yaklaşım

Çok kiracılı bir RAG sistemini Motia ve SpiceDB ile tasarlamak, hem esnekliği hem de güvenliği göz önünde bulunduran katmanlı bir yaklaşıma ihtiyaç duyar. Aşağıda, temel bileşenleri ve veri akışını açıklayan bir mimari taslağı bulunmaktadır.

Sistem Bileşenleri: Yapı Taşları Nelerdir?

  1. API Gateway/Yük Dengeleyici: Tüm gelen kullanıcı isteklerini alır, kimlik doğrulamasını (authentication) yapar ve isteği uygun servislere yönlendirir. Kiracı ID’si ve kullanıcı ID’si gibi bilgileri istek başlıklarına ekleyerek aşağı akış servislerine iletmek burada kritik bir adımdır.
  2. Motia RAG Servisi: Uygulamanın ana beynidir. Kullanıcı sorgularını işler, ilgili verileri almak için vektör veritabanına bağlanır ve bu verileri kullanarak LLM’den yanıt üretir. Bu serviste, SpiceDB ile entegrasyon sayesinde yetkilendirme kontrolleri gerçekleştirilir.
  3. Vektör Veritabanı: Belgelerin veya metin parçacıklarının sayısal vektör gösterimlerini (embedding’ler) saklar. Kullanıcı sorgusunun vektörü ile bu veritabanındaki vektörler karşılaştırılarak en alakalı belgeler bulunur. Her kiracının verisi için ya ayrı bir indeks ya da metaveri filtrelemesi ile izolasyon sağlanmalıdır. Popüler vektör veritabanları arasında Pinecone, Weaviate, Milvus veya Faiss bulunur.
  4. SpiceDB Yetkilendirme Servisi: İnce taneli yetkilendirme kararlarını verir. Sistemin hangi kullanıcının hangi kaynağa erişebileceğine dair tüm ilişkisel verileri saklar ve sorgulara hızlı yanıtlar verir. Motia RAG servisi, bu servise başvurarak yetki kontrollerini yapar.
  5. Veri Kaynağı (Doküman Deposu): Orijinal belgelerin (PDF, Word, metin dosyaları vb.) depolandığı yerdir. Bu belgeler, vektörleştirme için kullanılır ve RAG sürecinde LLM’e sunulmak üzere alınabilir. Veri izolasyonu burada da sağlanmalıdır (örneğin, kiracı bazlı klasör yapısı veya objeler arası yetkilendirme).
  6. LLM (Büyük Dil Modeli): Alınan bağlam (context) ile birlikte kullanıcı sorgusunu alır ve nihai yanıtı üretir. Bu genellikle bir üçüncü taraf API (OpenAI, Anthropic) veya şirket içi dağıtılan bir model olabilir.

Veri İzolasyonu Stratejileri: Kiracı Verilerini Korumak

Çok kiracılı bir yapıda veri izolasyonu, güvenliğin temelini oluşturur. İşte yaygın stratejiler:

  • Vektör Veritabanında Kiracı Bazlı İndeksleme: Her kiracı için vektör veritabanında ayrı bir indeks veya namespace oluşturmak, en güçlü izolasyon yöntemidir. Bu, bir kiracının sorgularının yanlışlıkla başka bir kiracının verilerine erişmesini teknik olarak imkansız hale getirir. Ancak yönetim ve maliyet açısından daha pahalı olabilir.
  • Metaveri Filtrelemesi (Row-Level Security): Daha esnek bir yaklaşım, tüm kiracıların verilerini aynı vektör veritabanı indeksinde tutmak ancak her vektöre bir ‘tenant_id’ metaverisi eklemektir. Sorgulama sırasında, Motia RAG servisi, kullanıcının kiracı ID’sini (ve SpiceDB’den gelen yetki bilgilerini) kullanarak sadece ilgili ‘tenant_id’ye sahip belgelerin getirilmesini sağlayacak filtreler uygular. Bu yöntem, daha az yönetim yükü ve daha iyi kaynak kullanımı sunar, ancak filtreleme mantığının doğru uygulanması kritik öneme sahiptir.
  • Fiziksel Veri Depolamasında İzolasyon: Orijinal belgelerin saklandığı depolama alanında (örneğin, S3 bucket’ları veya dosya sistemleri), her kiracı için ayrı bir dizin veya depolama alanı kullanmak, belgelerin fiziksel izolasyonunu sağlar.

Yetkilendirme Akışı: Bir İstek Nasıl İşlenir?

Şimdi bir kullanıcının RAG sistemine bir sorgu gönderdiği andan itibaren yetkilendirme sürecinin nasıl işlediğine bakalım:

  1. Kullanıcı Sorgusu ve Kimlik Doğrulama: Kullanıcı, bir web arayüzü veya API aracılığıyla Motia RAG servisine bir sorgu gönderir. İstek API Gateway’e ulaşır. Burada kullanıcının kimliği (user_id) ve kiracı kimliği (tenant_id) doğrulanır (örneğin, JWT token ile) ve istek başlıklarına eklenerek Motia RAG servisine iletilir.
  2. Motia RAG Servisi Tarafından İstek İşleme: Motia servisi sorguyu alır. RAG pipeline’ının bir parçası olarak, verileri vektör veritabanından çekmeden önce yetkilendirme kontrolü yapması gerektiğini bilir.
  3. SpiceDB’ye Yetki Sorgusu: Motia servisi, kullanıcının (user_id) belirtilen kiracı (tenant_id) içindeki belgelere erişim yetkisinin olup olmadığını veya daha spesifik olarak, hangi belgelere erişebileceğini öğrenmek için SpiceDB’ye bir sorgu gönderir. Bu sorgu “user:alice, tenant:companyA'nın document:X üzerinde 'view' izni var mı?” veya “user:alice, tenant:companyA'nın 'view' iznine sahip olduğu tüm document'ları listele” şeklinde olabilir.
  4. Yetki Kararı ve Belge Alma: SpiceDB, kendi şemasına ve ilişkisel verilerine dayanarak yetki kararını saniyeler içinde verir. Eğer kullanıcı yetkili ise, SpiceDB ilgili belge ID’lerini veya bir onay sinyalini Motia servisine döner.
  5. Filtreli Vektör Veritabanı Sorgusu: Motia servisi, SpiceDB’den aldığı yetkilendirilmiş belge ID’lerini kullanarak vektör veritabanına bir sorgu gönderir. Bu sorgu, kullanıcının orijinal metinsel sorgusu ile birlikte, sadece yetkili olduğu belgelerle eşleşen vektörleri aramak üzere filtrelenir. Bu adım, veri sızıntısını engellemede kilit rol oynar.
  6. LLM’den Yanıt Üretimi: Vektör veritabanından alınan yetkili ve ilgili belgeler, orijinal kullanıcı sorgusuyla birlikte LLM’e gönderilir. LLM, bu bağlamı kullanarak doğru ve güvenli bir yanıt oluşturur.
  7. Yanıtın Kullanıcıya İletilmesi: LLM’den gelen yanıt Motia servisi aracılığıyla API Gateway’e ve oradan da kullanıcıya iletilir.

Bu mimari yaklaşım, hem Motia’nın RAG yeteneklerinden faydalanırken hem de SpiceDB’nin güçlü ince taneli yetkilendirme mekanizmasıyla veri güvenliğini en üst düzeye çıkarmayı amaçlar. Her bileşenin rolü ve etkileşimi, ölçeklenebilir ve güvenli bir yapay zeka uygulamasının temelini oluşturur.

SpiceDB Şeması Nasıl Oluşturulur? İnce Taneli Yetkilendirme Modelleri

SpiceDB’nin kalbi, yetkilendirme modelinizi tanımladığınız şemalardır. Bu şemalar, sisteminizdeki objeleri (kaynaklar), kullanıcıları ve bunlar arasındaki izin ilişkilerini belirler. İnce taneli yetkilendirme için güçlü bir şema oluşturmak, doğru erişim kontrolünü sağlamanın ilk ve en önemli adımıdır.

SpiceDB’nin Temel Objeleri: definition ve relation

  • definition: Bir kaynak türünü veya bir kullanıcı türünü temsil eder. Örneğin, bir “kullanıcı”, bir “kiracı” veya bir “belge” birer definition olabilir. Her definition, kendi içinde ilişkileri ve izinleri tanımlar.
  • relation: İki definition arasındaki bir ilişkiyi ifade eder. Örneğin, tenant tanımının içinde bir member ilişkisi, bu kiracının hangi kullanıcılara sahip olduğunu belirtir. Veya document tanımının içinde owner ilişkisi, belgenin sahibini gösterir. İlişkiler, yetki kararlarını almak için kullanılır.
  • permission: Bir definition üzerinde yapılabilecek mantıksal bir eylemi temsil eder. Örneğin, bir document üzerinde “view” (görüntüleme) izni veya bir tenant üzerinde “admin” (yönetici) izni. İzinler, bir veya daha fazla relation‘ın birleşiminden (union), kesişiminden (intersection) veya hariç tutulmasından (exclusion) türetilebilir.

Örnek Bir Yetkilendirme Şeması: Çok Kiracılı RAG İçin

Şimdi, Motia tabanlı çok kiracılı RAG sistemimiz için basit ama güçlü bir SpiceDB şeması oluşturalım. Bu şema, kullanıcıların kiracılara, belgelerin kiracılara ve kullanıcılara nasıl bağlı olduğunu tanımlayacak.


definition user {}

definition tenant {
    // 'member' ilişkisi, bu kiracının hangi kullanıcılara sahip olduğunu belirtir.
    // Bir 'user' doğrudan 'member' olabilir veya bir gruptan gelebilir.
    relation member: user | user:... # user, user:group#member

    // 'document' ilişkisi, bu kiracıya ait belgeleri belirtir.
    // Genellikle bir belge, bir kiracıya bağlıdır.
    relation document: document

    // 'view_all_documents' izni, bu kiracının tüm belgelerini görebilme yetkisini tanımlar.
    // Bu izin, kiracının 'member'ı olan herkese otomatik olarak verilebilir.
    permission view_all_documents = member
}

definition document {
    // 'owner' ilişkisi, belgenin sahibini belirtir.
    relation owner: user

    // 'parent_tenant' ilişkisi, bu belgenin hangi kiracıya ait olduğunu belirtir.
    // Bu, çok kiracılı yapı için kritik bir bağlantıdır.
    relation parent_tenant: tenant

    // 'viewer' ilişkisi, doğrudan bu belgeye erişim yetkisi olan kullanıcıları belirtir.
    relation viewer: user

    // 'view' izni, bir belgenin görüntülenebilir olup olmadığını belirler.
    // Bu izin, birden fazla koşulun birleşimi olabilir:
    // 1. Belgenin sahibi olmak ('owner').
    // 2. Doğrudan 'viewer' olarak atanmış olmak.
    // 3. Belgenin ait olduğu kiracının tüm belgelerini görüntüleme yetkisine sahip olmak ('parent_tenant->view_all_documents').
    // 'parent_tenant->view_all_documents' ifadesi, 'document' objesinin 'parent_tenant' ilişkisi üzerinden
    // 'tenant' objesine bağlanıp, o 'tenant' objesi üzerindeki 'view_all_documents' iznini kontrol etmesi anlamına gelir.
    permission view = owner or viewer or parent_tenant->view_all_documents
}
    

Bu şema ile şunları yapabiliriz:

  • Bir kullanıcıyı bir kiracının üyesi (tenant:companyA#member@user:alice) yapabiliriz.
  • Bir belgeyi belirli bir kiracıya atayabiliriz (document:doc123#parent_tenant@tenant:companyA).
  • Belirli bir kullanıcıyı belirli bir belgenin görüntüleyicisi yapabiliriz (document:doc123#viewer@user:bob).

Daha sonra Motia RAG servisi, bir kullanıcının bir belgeye erişip erişemediğini kontrol etmek için SpiceDB'ye "check" sorgusu gönderebilir: "user:alice'ın document:doc123 üzerinde view izni var mı?" SpiceDB, şemadaki tanımlamalar ve var olan ilişkiler üzerinden bu soruyu hızlıca yanıtlar.

ACL ve RBAC Modellerinin SpiceDB ile İfadesi

SpiceDB, hem ACL (Access Control List) hem de RBAC (Role-Based Access Control) modellerini kolayca ifade etmenizi sağlar:

  • ACL Yaklaşımı: Her belge için doğrudan kimlerin görüntüleyici olacağını belirtebiliriz. Yukarıdaki şemadaki document#viewer: user ilişkisi buna bir örnektir. Doğrudan document:X#viewer@user:Y şeklinde ilişkiler ekleyerek spesifik belgelere bireysel erişim tanımlayabilirsiniz.
  • RBAC Yaklaşımı: Kiracıya "member" veya "admin" gibi roller tanımlayabiliriz. Yukarıdaki şemada tenant#member: user bir rolü temsil eder. Bu rol, tenant#view_all_documents gibi bir izni otomatik olarak taşır. Daha karmaşık senaryolarda, "group" veya "role" adında yeni definition'lar oluşturarak ve bunları kullanıcılarla veya diğer kaynaklarla ilişkilendirerek tam teşekküllü RBAC modelleri kurabiliriz. Örneğin, bir "admin" grubunun tüm kiracıların tüm belgelerini görüntüleme iznine sahip olmasını tanımlayabiliriz.

SpiceDB'nin esnekliği, iş gereksinimlerinize en uygun yetkilendirme modelini seçmenize ve bunu şemada açıkça ifade etmenize olanak tanır. Şema, sisteminizin yetkilendirme mantığını merkezi ve denetlenebilir bir yerde tutar, bu da bakım ve geliştirme süreçlerini basitleştirir. Şemanızı sürekli olarak gözden geçirmek ve geliştirmek, uygulamanızın güvenlik duruşunu güçlendirecektir.

Motia ile RAG Akışına Yetkilendirme Nasıl Entegre Edilir? Uygulamalı Adımlar

Şimdiye kadar temel kavramları ve mimariyi ele aldık. Artık Motia tabanlı RAG pipeline'ımıza SpiceDB ile ince taneli yetkilendirmeyi pratik olarak nasıl entegre edeceğimizi inceleyelim. Bu bölüm, kod örnekleriyle birlikte adım adım bir yaklaşım sunacaktır.

Adım 1: Motia RAG Pipeline'ı Oluşturma ve Hazırlık

Öncelikle, Motia'nın temel bir RAG pipeline'ını kurmuş olmanız gerekir. Bu, genellikle bir vektör veritabanı (örneğin, Chroma, Pinecone) ve bir LLM (örneğin, OpenAI GPT modelleri) ile entegrasyonu içerir. Motia, bu süreci basitleştiren soyutlamalar sunar. Diyelim ki, belgeleri zaten vektörleştirip vektör veritabanına kaydettiniz.

Yetkilendirme için, kullanıcının kimliğini (user_id) ve hangi kiracıya ait olduğunu (tenant_id) her istekte almanız hayati önem taşır. Bu bilgiler genellikle API Gateway'de kimlik doğrulama sürecinden sonra JWT token gibi bir mekanizma ile elde edilir ve RAG servisine başlıklar veya sorgu parametreleri olarak iletilir.

Adım 2: SpiceDB İstemcisini Entegre Etme

Motia servisi içinde SpiceDB ile iletişim kurmak için SpiceDB istemcisini kullanmanız gerekecek. Python için grpcio ve authzed kütüphanelerini yüklemeniz gerekir:


pip install grpcio grpcio-tools authzed
    

Ardından, Motia servisi uygulamanızda SpiceDB istemcisini başlatın:


    from motia import RAGPipeline
    from spicedb.api import Client as SpiceDBClient
    from spicedb.errors import PermissionDeniedError # Yetkilendirme reddedildiğinde kullanmak için

    # SpiceDB istemcisini global veya dependency injection ile başlatın
    # 'grpc.authzed.com:443' yerine kendi SpiceDB sunucunuzun adresini yazın.
    # 'your_spicedb_token' yerine Authzed.com'dan aldığınız veya kendi sunucunuzdan oluşturduğunuz API token'ı koyun.
    try:
        spicedb_client = SpiceDBClient("grpc.authzed.com:443", "your_spicedb_token")
        # Bir deneme check ile bağlantıyı kontrol edin (isteğe bağlı)
        # from spicedb.v1 import CheckPermissionRequest
        # request = CheckPermissionRequest(resource={"object_type": "tenant", "object_id": "any_tenant"},
        #                                  permission="view_all_documents",
        #                                  subject={"object_type": "user", "object_id": "test_user"})
        # response = spicedb_client.check_permission(request)
        # print(f"SpiceDB bağlantı testi başarılı: {response.permissionship}")
    except Exception as e:
        print(f"SpiceDB bağlantı hatası: {e}")
        spicedb_client = None # Hata durumunda istemciyi None yapabiliriz veya uygulamayı sonlandırabiliriz.
    

Yukarıdaki kod bloğu, uygulamanızın başlangıcında SpiceDB istemcisini nasıl yapılandıracağınızı gösterir. Hata yönetimi, üretim ortamlarında büyük önem taşır.

Adım 3: Motia RAG Pipeline'ına Yetkilendirme Mantığını Enjekte Etme

Motia'nın RAGPipeline sınıfını genişleterek veya pipeline'ın belirli adımlarını (özellikle retrieve adımını) özelleştirerek yetkilendirme mantığını entegre edebiliriz. Amacımız, vektör veritabanından belgeleri çekmeden önce kullanıcının yetkilerini kontrol etmek ve yalnızca yetkili belgelere ilişkin filtreleri uygulamaktır.


    from motia import RAGPipeline, Document
    from spicedb.api import Client as SpiceDBClient
    from spicedb.errors import PermissionDeniedError
    from spicedb.v1 import CheckPermissionRequest, LookupResourcesRequest, ObjectReference

    # SpiceDB istemcisini global olarak veya sınıf yapıcıda alın
    # Örnekte basitlik adına doğrudan kullanıyoruz
    # Gerçek uygulamada dependency injection kullanılması önerilir.
    _spicedb_client = SpiceDBClient("grpc.authzed.com:443", "YOUR_SPICEDB_TOKEN")

    class AuthorizedRAG(RAGPipeline):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.spicedb_client = _spicedb_client # Dışarıdan alınan istemciyi kullan

        def retrieve(self, query: str, user_id: str, tenant_id: str, **kwargs) -> list[Document]:
            # Kullanıcının hangi belgelere erişebileceğini SpiceDB'den sorgula
            authorized_document_ids = self._get_authorized_documents(user_id, tenant_id)

            if not authorized_document_ids:
                # Kullanıcının erişebileceği belge yoksa yetki reddi hatası fırlat
                raise PermissionDeniedError(f"Kullanıcı {user_id}'in kiracı {tenant_id} içinde erişebileceği belge bulunamadı.")

            print(f"DEBUG: Kullanıcı {user_id} için yetkilendirilen belge ID'leri: {authorized_document_ids}")

            # Vektör veritabanından sadece yetkili belgeler arasında arama yap
            # Bu kısım Motia'nın dahili filtreleme mekanizmalarıyla entegre edilmelidir.
            # Örneğin, vektör veritabanı sorgusuna metaveri filtresi ekleyerek:
            # Belgelerin 'document_id' metaverisi, yetkili ID'ler listesinde olmalıdır.
            # Motia'nın retrieve metodu genellikle bir 'filters' argümanı kabul eder.
            # Aşağıdaki satır, bu filtrenin nasıl eklenebileceğine dair bir örnek.
            
            # Not: Motia'nın kendi retrieve metodunu çağırırken, 
            # buradaki 'filters' argümanının vektör veritabanınız tarafından desteklendiğinden emin olun.
            # Örneğin, ChromaDB'de 'where' veya Pinecone'da 'filter' gibi isimler alabilir.
            # Eğer Motia doğrudan bu filtreyi desteklemiyorsa, retrieval öncesi belge ID'lerini
            # manuel olarak filtreleyebilir veya vektör veritabanı istemcinizi doğrudan çağırabilirsiniz.
            
            # Örnek: Motia'nın dahili retrieve metodunu kullanırken filtreleme
            documents = super().retrieve(query, filters={"document_id": {"$in": authorized_document_ids}})
            
            # Gerekirse, alınan belgeler üzerinde son bir yetkilendirme kontrolü daha yapabilirsiniz.
            # Bu, eğer vektör veritabanı filtrelemeyi tam olarak yapamıyorsa ek bir güvenlik katmanı sağlar.
            final_authorized_docs = [doc for doc in documents if doc.metadata.get("document_id") in authorized_document_ids]
            
            return final_authorized_docs

        def _get_authorized_documents(self, user_id: str, tenant_id: str) -> list[str]:
            # SpiceDB'ye sorgu yap: 'user:user_id' bu 'document' üzerinde 'view' iznine sahip mi?
            # Belirli bir kiracıya ait tüm belgeler için sorgulama yapmak genellikle 'LookupResources' API'si ile yapılır.
            
            print(f"DEBUG: SpiceDB'den user:{user_id} için tenant:{tenant_id} içindeki 'document' objeleri üzerinde 'view' izni aranıyor.")
            
            try:
                # 'LookupResources' ile belirli bir konu (user) için belirli bir izin (view) ile erişebileceği
                # belirli bir kaynak tipindeki (document) tüm kaynakları listele.
                # parent_tenant ilişkisi üzerinden tenant_id'yi de filtreleyebiliriz.
                lookup_request = LookupResourcesRequest(
                    resource_object_type="document",
                    permission="view",
                    subject=ObjectReference(object_type="user", object_id=user_id),
                    # Kontext olarak kiracı ID'sini vermek, lookup sonuçlarını kiracıya göre filtreleyebilir.
                    # Bu, SpiceDB şemasına ve ilişki tanımlamalarına bağlıdır.
                    context_raw={
                        "tenant_id": {"stringValue": tenant_id}
                    }
                )
                
                response = self.spicedb_client.lookup_resources(lookup_request)
                
                authorized_ids = [r.resource_object_id for r in response.resources]
                return authorized_ids
                
            except Exception as e:
                print(f"SpiceDB lookup hatası: {e}")
                return []

    # Bu authorized_rag_pipeline'ı Motia'nın normal pipeline'ı gibi kullanın.
    # Örnek kullanım:
    # from motia.vector_stores import ChromaVectorStore
    # from motia.llms import OpenAIModel

    # # Vektör deposu ve LLM'i başlat
    # vector_store = ChromaVectorStore(collection_name="my_documents") # Örnek
    # llm = OpenAIModel(model_name="gpt-4") # Örnek

    # # Yetkili RAG pipeline'ını oluştur
    # authorized_rag_pipeline = AuthorizedRAG(vector_store=vector_store, llm=llm)

    # try:
    #     response = authorized_rag_pipeline.query(
    #         "Şirket politikaları nelerdir?",
    #         user_id="alice",
    #         tenant_id="companyA"
    #     )
    #     print("Yanıt:", response.answer)
    # except PermissionDeniedError as e:
    #     print("Erişim Reddedildi:", e)
    # except Exception as e:
    #     print("Bir hata oluştu:", e)
    

Yukarıdaki kodda, AuthorizedRAG sınıfı, Motia'nın RAGPipeline'ını genişletir. Anahtar değişiklik, retrieve metodunda yapılmıştır. Bu metod, vektör veritabanından belge almadan önce _get_authorized_documents yardımcı metodunu çağırır. Bu yardımcı metod, SpiceDB'nin lookup_resources API'sini kullanarak belirli bir kullanıcının ve kiracının erişim yetkisine sahip olduğu tüm belge ID'lerini listeler. Daha sonra, Motia'nın orijinal retrieve metodu çağrılırken bu belge ID'leri bir filtre olarak kullanılır. Bu sayede, RAG sistemi sadece kullanıcının görmeye yetkili olduğu belgeler üzerinden bilgi çekip yanıt üretecektir.

Adım 4: Veri Alımı (Ingestion) ve İlişkilerin Yönetimi

Belgeleri Motia'ya yüklerken, her belge için ilgili tenant_id ve diğer metaverileri (örneğin, document_id) saklamak önemlidir. Aynı zamanda, bu belgeler ve kullanıcılar arasındaki yetkilendirme ilişkilerini SpiceDB'ye yazmanız gerekir. Örneğin, yeni bir belge eklendiğinde:

  • document:new_doc_id#parent_tenant@tenant:companyA ilişkisini ekleyin.
  • Gerekirse, belirli kullanıcılar için document:new_doc_id#viewer@user:alice ilişkisini ekleyin.
  • Motia'nın vektörleştirme sürecinde, document_id ve tenant_id gibi bilgileri vektörlerin metaverilerine ekleyin. Bu, daha sonra filtreleme için kullanılacaktır.

Bu adımlar, çok kiracılı RAG uygulamanızda hem güvenliği hem de ölçeklenebilirliği sağlarken, geliştirici deneyimini de basitleştirecektir. Motia, RAG sürecinin karmaşıklığını yönetirken, SpiceDB de yetkilendirme karmaşıklığını üstlenir.

İleri Düzey Optimizasyonlar ve En İyi Uygulamalar

Bir çok kiracılı RAG sistemini Motia ve SpiceDB ile kurduktan sonra, performansı artırmak, güvenliği pekiştirmek ve bakım kolaylığı sağlamak için bazı ileri düzey teknikleri ve en iyi uygulamaları göz önünde bulundurmak faydalı olacaktır.

Performans Optimizasyonu: Caching ve Sorgu Stratejileri

  • SpiceDB Cache: SpiceDB, yetkilendirme kararlarını hızlı bir şekilde vermek üzere tasarlanmıştır, ancak yüksek frekanslı sorgular için istemci tarafında veya bir ara katmanda caching kullanmak performansı önemli ölçüde artırabilir. Bir kullanıcının belirli bir belgeye erişim izni gibi sık sorgulanan kararlar, kısa ömürlü bir cache'te tutulabilir. Authzed'in sağladığı veya kendi geliştirdiğiniz cache katmanlarını kullanabilirsiniz. Özellikle CheckPermission çağrıları cache'lemek için iyi adaylardır.
  • RAG Cache: Sık sorulan kullanıcı sorguları ve bunların RAG tarafından üretilen yanıtları da cache'lenebilir. Bu, hem LLM maliyetlerini düşürür hem de yanıt sürelerini kısaltır. Kiracıya özel cache anahtarları kullanılarak izolasyon sağlanmalıdır.
  • Optimize Edilmiş SpiceDB Şeması: Şemanızı mümkün olduğunca verimli tasarlayın. Gereksiz veya çok geniş ilişkilerden kaçının. Özellikle LookupResources gibi işlemler, iyi tanımlanmış ilişkilerle daha hızlı çalışır. İlişki döngülerinden veya çok derin iç içe geçmiş ilişkilerden kaçınmak performansı artırabilir.
  • Vektör Veritabanı Optimizasyonu: Vektör veritabanınızın indeksleme stratejilerini ve donanım kaynaklarını optimize edin. Metaveri filtrelemelerinin hızlı çalıştığından emin olun. Büyük kiracılar için ayrı indeksler kullanmak veya sharding stratejileri uygulamak düşünülebilir.

Güvenlik Denetimleri ve Loglama

  • Kapsamlı Loglama: Tüm yetkilendirme kararlarını (başarılı ve başarısız), Motia RAG servisindeki anahtar işlemleri ve SpiceDB sorgularını loglayın. Bu loglar, güvenlik denetimleri, hata ayıklama ve potansiyel güvenlik ihlallerini tespit etmek için hayati öneme sahiptir.
  • Erişim Denetimi: SpiceDB'nin Audit Log özelliklerini kullanın. Bu loglar, kimin hangi yetkilendirme kararını ne zaman sorguladığını göstererek şeffaflık sağlar.
  • Güvenlik Taramaları ve Testleri: Düzenli olarak güvenlik açığı taramaları (Vulnerability Scans) ve sızma testleri (Penetration Tests) yapın. Çok kiracılı bir sistemde, kiracılar arası izolasyonun doğru çalıştığını test etmek kritik öneme sahiptir.
  • En Az Yetki Prensibi: Kullanıcılara ve sistem servislerine yalnızca görevlerini yerine getirmek için kesinlikle ihtiyaç duydukları minimum yetkileri verin. Bu prensip, olası güvenlik ihlallerinin etkisini sınırlar.

Hata Yönetimi ve Geri Dönüş Stratejileri

  • Yetkilendirme Hatalarının Yönetimi: SpiceDB'den gelen PermissionDeniedError gibi hataları düzgün bir şekilde ele alın. Kullanıcıya açık ve bilgilendirici mesajlar gösterin (ancak hassas iç sistem bilgilerini ifşa etmeyin). Güvenlik açısından, yetki hatasında "bulunamadı" yerine "erişim izniniz yok" gibi daha net ifadeler kullanmak önemlidir.
  • SpiceDB Erişilebilirlik Sorunları: SpiceDB servisine ulaşılamazsa ne olacağını planlayın. Sisteminiz, yetkilendirme servisinin geçici olarak kullanılamadığı durumlarda varsayılan bir güvenli modda çalışmalı veya kullanıcılara uygun bir hata mesajı sunmalıdır. Bir "fail-safe" mekanizması düşünün.
  • Geri Dönüş Mekanizmaları: Nadiren de olsa bir yetkilendirme kararının yanlış olma ihtimaline karşı bir geri dönüş veya manuel denetim mekanizması düşünülebilir.

Mobil Uyumluluk İçin HTML ve CSS İpuçları

Yapay zeka uygulamaları genellikle çeşitli cihazlardan erişilir. Mobil uyumlu bir kullanıcı deneyimi sunmak için HTML ve CSS tarafında aşağıdaki noktaları göz önünde bulundurabilirsiniz:

  • Duyarlı Tasarım (Responsive Design): Esnek bir grid sistemi ve göreceli birimler (%, em, rem, vw, vh) kullanarak uygulamanızın farklı ekran boyutlarına uyum sağlamasını sağlayın.
  • Meta Viewport Etiketi: Her zaman HTML bölümünüze aşağıdaki etiketi ekleyin:
    
    
                


    Bu, tarayıcıya sayfanın cihazın genişliğine göre ölçeklenmesini söyler.

  • Media Queries: Belirli ekran boyutları için farklı stil kuralları tanımlamak için CSS media query'lerini kullanın. İşte bir örnek:
    
    
                


    Yukarıdaki CSS örneğinde, özellikle pre etiketleri için white-space: pre-wrap; ve word-wrap: break-word; özelliklerini kullanarak uzun kod satırlarının mobil cihazlarda düzgün bir şekilde sarılmasını sağladık. Tablolar için de mobil uyumlu bir çözüm sunarak, dar ekranlarda yatay kaydırma çubuğu veya blok görünümü ile verilerin okunabilirliğini artırdık. Bu uygulamalar, son kullanıcının cihazından bağımsız olarak tutarlı ve erişilebilir bir deneyim yaşamasını sağlar.

Sonuç: Geleceğin Güvenli Yapay Zeka Uygulamalarına Doğru

Bu makalede, çok kiracılı RAG sistemlerinin karmaşıklıklarını, karşılaşılan güvenlik zorluklarını ve bu zorlukların üstesinden gelmek için Motia ve SpiceDB'nin nasıl güçlü bir kombinasyon oluşturduğunu detaylı bir şekilde inceledik. Modern yapay zeka uygulamalarının yaygınlaşmasıyla birlikte, veri güvenliği, kiracılar arası izolasyon ve ince taneli yetkilendirme her zamankinden daha kritik bir hale gelmiştir. Motia'nın RAG geliştirme süreçlerini basitleştiren yetenekleri ile SpiceDB'nin Google Zanzibar modelinden ilham alan ölçeklenebilir ve esnek yetkilendirme mimarisini bir araya getirerek, sadece işlevsel değil, aynı zamanda sağlam ve güvenli yapay zeka çözümleri inşa edebiliriz.

Motia, geliştiricilerin LLM'ler ve bilgi tabanları arasındaki entegrasyonun teknik detaylarına boğulmadan, asıl iş mantığına odaklanmasına olanak tanır. SpiceDB ise, hangi kullanıcının hangi veriye erişebileceği sorusunu hızlı ve tutarlı bir şekilde yanıtlayarak, RAG pipeline'ının her adımında veri güvenliğini teminat altına alır. Birbirini tamamlayan bu iki teknoloji, kurumsal düzeyde ölçeklenebilir ve hassas yetkilendirme gerektiren yapay zeka uygulamaları için ideal bir temel sunar. Bu entegrasyon sayesinde, farklı şirketlerin veya departmanların kendi verileri üzerinde güvenle çalışabildiği, veri sızıntısı riskinin minimuma indiği ve kullanıcı deneyiminin optimize edildiği bir ortam yaratılabilir. Gelecekte, yapay zeka teknolojileri iş süreçlerimize daha da entegre oldukça, bu tür güvenli ve ölçeklenebilir mimarilerin önemi artmaya devam edecektir. Bu bağlamda, Motia ve SpiceDB ikilisi, geleceğin güvenli ve verimli yapay zekası için bir yol haritası sunmaktadır.

Sıkça Sorulan Sorular (SSS)

  • Motia ve SpiceDB'nin kurulumu karmaşık mı?

    Her iki teknoloji de modern geliştirme yaklaşımlarını benimsemiştir. Motia, Python tabanlı bir kütüphane olup kurulumu nispeten basittir (pip install motia). SpiceDB ise bir gRPC servisi olarak çalışır ve Docker, Kubernetes gibi platformlarda kolayca dağıtılabilir. Authzed.com üzerinden yönetilen bir SpiceDB bulut servisi de mevcuttur, bu da kendi sunucunuzu kurma yükünü ortadan kaldırır. Entegrasyon kısmı, her iki API'nin nasıl kullanılacağını öğrenmeyi gerektirse de, sağladığı güvenlik ve esneklik göz önüne alındığında bu öğrenme eğrisi kesinlikle değerlidir.

  • Farklı yetkilendirme modelleri SpiceDB ile nasıl uygulanır?

    SpiceDB, şemalar aracılığıyla son derece esnek yetkilendirme modelleri oluşturmanıza olanak tanır. Rol tabanlı erişim kontrolü (RBAC) için "role" veya "group" gibi definition'lar tanımlayabilir ve bunları kullanıcılarla ilişkilendirebilirsiniz. Nitelik tabanlı erişim kontrolü (ABAC) için ise, şemaya objelerin veya ilişkilerin niteliklerini yansıtabilirsiniz. Örneğin, bir belgenin "gizlilik seviyesi" niteliğini şemaya ekleyerek, kullanıcının "güvenlik izni" niteliğine göre erişimini kontrol edebilirsiniz. İlişkisel yapısı sayesinde karmaşık hiyerarşik veya matris tabanlı yetkilendirme modelleri de uygulanabilir.

  • Bu entegrasyon performans üzerinde bir etki yaratır mı?

    Her ek güvenlik katmanı gibi, SpiceDB entegrasyonu da teorik olarak performansa minimal bir yük getirebilir. Ancak SpiceDB, Google Zanzibar'dan ilham alan mimarisi sayesinde yüksek performans ve düşük gecikme süresi için optimize edilmiştir. Doğru şema tasarımı ve etkili caching stratejileri (hem SpiceDB istemcisinde hem de Motia RAG servisinde) kullanılarak, bu etki minimize edilebilir. Aslında, yetkilendirme kararlarını uygulama katmanında manuel olarak yönetmekten çok daha verimli ve tutarlıdır.

  • Motia dışında başka RAG çerçeveleriyle kullanılabilir mi?

    Kesinlikle evet. SpiceDB, dilden ve framework'ten bağımsız bir yetkilendirme servisidir. Geliştirdiğimiz entegrasyon mantığı (yani, belge alımından önce SpiceDB'ye sorgu göndermek), LangChain, LlamaIndex gibi diğer RAG çerçeveleriyle veya tamamen özel olarak yazılmış RAG pipeline'larıyla da uyarlanabilir. Önemli olan, RAG akışının hangi noktasında yetkilendirme kontrolü yapılması gerektiğini ve bu kontrolün sonuçlarının (yetkilendirilmiş belge ID'leri gibi) nasıl kullanılacağını anlamaktır.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version