Çok kiracılık ve RLS
Her proje ayrı bir alan. İzolasyon uygulamada değil veritabanında: PostgreSQL satır düzeyi güvenlik, uygulama katmanı hata yapsa bile bir kiracının verisini diğerine sızdırmaz.
API-first, çok kiracılı headless CMS. Okuma yolu API'ye hiç uğramaz — ziyaretçi arttıkça faturanız değil, cache isabetiniz artar.
Veriniz bizim yönettiğimiz sunucularda Kullanım başına ücretlenen dış servis yok Kurumsal planda kendi sunucunuza kurulum
Özellikler
Her şey API'nin arkasında; hiçbir özellik panele kilitli değil.
Her proje ayrı bir alan. İzolasyon uygulamada değil veritabanında: PostgreSQL satır düzeyi güvenlik, uygulama katmanı hata yapsa bile bir kiracının verisini diğerine sızdırmaz.
İçerik tipleri koda gömülü değil; panelden veya API'den tanımlanır. Alanlar title, slug, body gibi roller taşır — derleme hattı ve SEO üretimi alan adına değil role bakar.
Medya, arama, webhook, SEO, GraphQL, ithalat, analitik — hepsi ayrı ve kapatılabilir. Kapatmak veri silmez; modülü açtığınızda kaldığı yerden devam eder.
Yayınlanan içerik derleme anında değişmez bir adrese yazılır ve nginx kenar cache'inden servis edilir. İçerik sayısı da ziyaretçi sayısı da okuma maliyetini artırmaz.
S3 uyumlu nesne deposu (Garage), üç bölgeye kopyalanan görseller ve otomatik türevler. Yüklediğiniz dosya kendi altyapımızda kalır, kullanım başına ücretlenen bir CDN'e gitmez.
Typesense destekli, çok dilli tam metin arama. "İstanul" yazan ziyaretçi de doğru içeriği bulur; yanıt 50 milisaniyenin altında döner.
Yayınlama, güncelleme, silme — her olayda sisteminize haber gider. Teslimat kalıcı kuyrukta tutulur ve üstel geri çekilmeyle yeniden denenir; süreç ölse bile olay kaybolmaz.
Şema elle yazılmaz; alanın içerik tiplerinden türetilir. Yeni bir tip eklediğinizde sorgulanabilir hâle gelir. Derinlik ve uzunluk sınırları sorgu bombasına karşı zorunlu.
@corpusctl/client ile React, Vue ve Next.js adaptörleri. Blok render'ıcıları sıfır varsayılan stille gelir — tek satır CSS dayatmayız, tasarım tamamen sizin.
Kod örnekleri
Panelde yapabildiğiniz her şeyin API karşılığı var; hiçbir özellik arayüze kilitli değil.
# 1) İçerik tipini tanımla — şema koda gömülü değil
curl -X PUT "$API/v1/content-types/yazi" \
-H "authorization: Bearer $TOKEN" \
-H "x-corpusctl-tenant: $TENANT" \
-H "content-type: application/json" \
-d '{
"name": "yazi",
"title": "Yazı",
"fields": [
{ "name": "baslik", "type": "text", "role": "title", "required": true },
{ "name": "yol", "type": "slug", "role": "slug", "required": true },
{ "name": "govde", "type": "blocks", "role": "body" }
]
}'
# 2) Taslak oluştur
curl -X POST "$API/v1/documents" \
-H "authorization: Bearer $TOKEN" \
-H "x-corpusctl-tenant: $TENANT" \
-d '{ "type": "yazi", "data": { "baslik": "Merhaba", "yol": "merhaba" } }'
# 3) Yayınla — doğrulama, derleme ve kenara taşıma tek çağrıda
curl -X POST "$API/v1/documents/$ID/publish" \
-H "authorization: Bearer $TOKEN" \
-H "x-corpusctl-tenant: $TENANT"
# → { "data": { "version": 3, "contentHash": "…", "durationMs": 42 } }
import { ReadClient } from '@corpusctl/client'
import { Content } from '@corpusctl/react'
// ReadClient token TAŞIMAZ ve API'yi hiç çağırmaz — doğrudan kenardan okur.
const client = new ReadClient({
tenantId: '3f2b…',
edgeUrl: 'https://cdn.ornek.com',
manifestTtlMs: 60_000,
})
export default async function Page({ params }) {
// slug → parça hesabı (yerel) → manifesto → değişmez adres.
// İki HTTP isteği, ikisi de cache'ten. Bulunamazsa undefined döner,
// hata fırlatmaz — 404 kararı sizin sayfanızın.
const yazi = await client.getBySlug(params.slug)
if (!yazi) notFound()
return (
<article>
<h1>{yazi.data.baslik}</h1>
{/* Sıfır varsayılan stil: her blok tipi override edilebilir */}
<Content value={yazi.data.govde} components={{ ... }} />
</article>
)
}
# Şema elle yazılmaz: alanın içerik tiplerinden türetilir.
# "yazi" tipini tanımladığınız an sorgulanabilir olur.
query YaziGetir($yol: String!) {
yazi(slug: $yol) {
baslik
yol
govde
# Hesaplanan alanlar da şemada: okuma süresi, kelime sayısı…
okumaSuresi
}
}
# Liste sorgusu — imleçli sayfalama, ofset yok
query SonYazilar {
yaziListesi(limit: 10) {
data { baslik yol }
cursor
}
}
ReadClient gizli token taşımaz, tarayıcıda çalışabilir; ManagementClient yalnız sunucuda. Tek sınıf olsaydı token sızdırmak bir satırlık hata olurdu.
Mimari
Yayınla düğmesi bir derleme tetikler; ziyaretçi o derlemenin çıktısını okur, sistemi değil.
İçerik hash'iyle adreslenir. Aynı adres asla farklı bir içerik döndürmez, bu yüzden 30 gün cache'lenebilir; yayın anında manifesto tazelenir.
Slug'dan hangi manifesto parçasının okunacağı istemcide hesaplanır. On bin içerikli bir alanda da tek bir küçük dosya indirilir.
Her kayıt sürümlenir, eski sürüm taslağa geri yüklenebilir. İleri tarihli yayın zamanlanır; zamanlayıcı derlemeyi kendisi tetikler.
Karşılaştırma
Her satırda kazanan biz değiliz. Aşağıdaki tablo neyi seçtiğinizi açıkça göstersin diye var.
| Ölçüt | corpusctl | Contentful | DatoCMS |
|---|---|---|---|
| Fiyat modeli | Sabit plan. Okuma isteği API'ye uğramadığı için ölçülen bir çağrı yok. | API çağrısı, kayıt ve kullanıcı başına ölçülür; aşımda ek ücret. | API çağrısı ve trafik (bandwidth) başına ölçülür. |
| Çok proje yönetimi | Çekirdekte. Tek panel, sınırsız alan; kullanıcı her alanda ayrı rol taşır. | Her proje ayrı "space"; çoğu planda space başına ücret. | Her proje ayrı ortam; proje başına plan. |
| Kiracı izolasyonu | Veritabanı seviyesinde — PostgreSQL satır düzeyi güvenlik (RLS). | Uygulama seviyesinde; ayrıntı açıklanmıyor. | Uygulama seviyesinde; ayrıntı açıklanmıyor. |
| Veri konumu | Bizim yönettiğimiz sunucular; kurumsal planda tamamen sizin sunucunuza kurulum. | Sağlayıcının bulutu; bölge seçimi üst planlarda. | Sağlayıcının bulutu; bölge seçimi üst planlarda. |
| Kullanım başına dış servis | Yok. PostgreSQL, Valkey, Typesense, Garage, nginx — hepsi kendi altyapımızda. | Var; arama, görsel ve CDN katmanları ölçülür. | Var; görsel CDN ve dönüşümler ölçülür. |
| Render dayatması | Yok. Blok render'ıcıları sıfır varsayılan stille gelir; bilinmeyen blok çökertmez, atlanır. | Rich text render'ıcısı var; stil kararları sizde. | Yapılandırılmış metin render'ıcısı var; stil kararları sizde. |
| Özellik kapatma | Her özellik kapatılabilir modül; kapatmak veri silmez, plan düşmesi de silmez. | Plan sınırı özelliği erişilemez kılar. | Plan sınırı özelliği erişilemez kılar. |
| Küresel kenar ağı | Tek bölge kenar cache. Küresel PoP ağımız yok. | Çok bölgeli küresel CDN. | Çok bölgeli küresel CDN. |
| Uygulama pazaryeri | Yok. Entegrasyon webhook ve API ile yazılır. | Geniş, olgun bir uygulama ekosistemi. | Eklenti ekosistemi mevcut. |
| Kurumsal olgunluk | Genç ürün; SSO ve resmî SLA yol haritasında. | SOC 2, SSO, SLA — olgun. | SSO ve SLA üst planlarda. |
Küresel bir kitleye milisaniye seviyesinde servis yapmanız ve hazır entegrasyon pazaryerine ihtiyacınız varsa dürüst cevap: bugün Contentful daha olgun. Türkiye ve Avrupa'ya servis eden, çok projeli, faturasının ziyaretçi sayısıyla oynamasını istemeyen ekipler içinse corpusctl bilinçli olarak daha iyi bir takas.
İçerik, medya ve arama indeksi dahil her bileşen bizim yönettiğimiz sunucularda çalışır: PostgreSQL, Valkey, Typesense, Garage (S3 uyumlu nesne deposu) ve nginx. Kullanım başına ücretlenen üçüncü taraf bir servise veri aktarılmaz — bu bir pazarlama tercihi değil, mimarinin kuralı. Kurumsal planda kurulumun tamamı sizin sunucunuza da yapılabilir.
Hayır. Yayınlanan içerik derleme anında değişmez bir adrese yazılır ve kenar cache'inden servis edilir; okuma isteği API'ye veya veritabanına hiç uğramaz. Ölçülecek bir çağrı olmadığı için ziyaretçi sayısı faturayı hareket ettirmez. Yazma tarafında da ücret kayıt sayısına değil plana bağlıdır.
Evet — çok kiracılık sonradan eklenmiş bir özellik değil, ürünün çekirdeği. Her proje ayrı bir alan (tenant) ve veriler PostgreSQL satır düzeyi güvenlikle veritabanı seviyesinde ayrılır. Aynı kullanıcı bir alanda editör, diğerinde yalnızca okuyucu olabilir; panel alanlar arasında tek tıkla geçer.
WordPress ve Ghost dışa aktarımları için ithalat modülü var. İçe aktarma önce dryRun ile çalıştırılır: hangi kaydın hangi içerik tipine düşeceğini ve ayrıştırma hatalarını hiçbir şey yazmadan raporlar. Raporu onayladıktan sonra gerçek aktarım çalışır. Başka bir kaynaktan geliyorsanız API ile aktarım yazmak da mümkün; şema ve doküman uçları bunun için açık.
Hayır. corpusctl hiçbir sayfa render etmez; ürün API ve yönetim panelinden ibaret. Blok render'ıcıları sıfır varsayılan stille gelir — tek satır CSS dayatmayız ve her blok tipi override edilebilir. React, Vue ve Next.js adaptörleri çerçeveden bağımsız render ağacının üstünde ince birer katman; düz HTML üreterek de tüketebilirsiniz.
Hayır. Kapatmak veriyi korur; modülü tekrar açtığınızda kaldığı yerden devam eder. Veri yalnızca açıkça kaldırma seçildiğinde ve çift onaydan sonra temizlenir. Plan düşürülmesi de modülü yalnızca kapatır — asla veri silmez. Bu, faturanız düştüğünde içeriğinizi kaybetmeyeceğiniz anlamına gelir.
Hesap açmak birkaç dakika sürüyor: e-posta, parola ve alanınızın adı yeter. Kart istemiyoruz. Taşıma konusunda yardım gerekirse yazın.