NEXT-GEN CONTENT MANAGEMENT FRAMEWORK
Bir İçerik Yönetim Sisteminden
"Kurşun Geçirmez"
Kurumsal Uygulama Framework'üne
Modern web ekosisteminde hazır eklenti sistemleriyle donatılmış ama hantal CMS'ler ile her şeye sıfırdan başlamayı gerektiren saf framework'ler arasındaki köprüyü kuran, dünya standartlarında optimize, güvenli ve genişletilebilir altyapı.
Modern web geliştirmede her yeni proje, iki ucu keskin bir bıçağın üzerinde başlar. CPalius bu iki dünya arasındaki boşluğu doldurmak için doğdu.
Hazır eklenti ve tema sistemleriyle donatılmış ancak hantal veritabanı şemaları, teknik borç dağları ve güvenlik zaafiyetleriyle boğuşan yapılar.
Her projede auth, ACL, dosya yönetimi ve admin paneli gibi temel bileşenleri sıfırdan yazarak zaman kaybettiren yaklaşım.
Kendi framework'ünü yazmak kulağa romantik gelse de güvenlik (CSRF, XSS, SQLi), DI Container ve HTTP katmanı gibi devasa bir "görünmez buzdağı" barındırır.
Symfony 7.4 LTS'nin kanıtlanmış güvenlik ve performans altyapısı üzerine inşa edilmiş, teknik borçtan arınmış mimari.
Auth, ACL, dosya yönetimi, çok dilli yapı ve admin paneli gibi temel bileşenler ilk günden çekirdekte. Tekerleği yeniden icat etmeye son.
CMS'ten öte bir uygulama platformu: Oto Galeri, Turizm Acentası, CRM/ERP — hepsi aynı altyapı üzerinde çalışır.
Kullanıcı modüllerinden gelen hatalar sistemi asla çökertmez. 4 kademeli aktif savunma ve karantina hattı.
Standart bir Symfony projesinde üçüncü parti paketler ve tarifler yüklendikçe ana dizin dosya çöplüğüne döner. CPalius, "Tertemiz Ana Dizin" politikasını benimsedi.
CPalius/ │ ├── cp-core/ # KERNEL & SYSTEM SPACE │ ├── bin/ # Konsol komut aracı │ ├── config/ # Core konfigürasyonları │ ├── migrations/ # Veritabanı göç dosyaları │ ├── src/ # PHP sınıfları (App\) │ └── var/ # Cache, log, SQLite │ ├── cp-includes/ # DEPENDENCIES SPACE │ └── vendor/ # Composer paketleri │ ├── cp-content/ # USER & DEVELOPER SPACE │ ├── config/ # Config Sync alanı │ ├── modules/ # Bağımsız modüller │ ├── themes/ # UI temaları │ └── translations/ # Çeviriler (tr, en) │ ├── public/ # WEB ROOT │ ├── index.php # Front Controller │ └── assets/ # Frontend varlıkları │ ├── .env └── composer.json
Kernel & System SpaceÇekirdek PHP sınıfları, konfigürasyonlar, konsol araçları ve veritabanı göç dosyaları. Symfony Flex tariflerinin doğrudan bu alana kurulması garanti altındadır.
Dependencies SpaceComposer paketleri ve Symfony kütüphaneleri bu izole alanda tutulur. vendor-dir yeniden yapılandırılmıştır.
User & Developer SpaceModüller, temalar, çeviriler ve Config Sync alanı. Geliştiricinin kendi kodları ile framework sistem dosyaları asla birbirine karışmaz.
Web RootDışarıya açık tek klasör. Front Controller (index.php) ve derlenmiş frontend varlıkları burada yer alır. Güvenlik sınırı.
Kullanıcı alanından gelebilecek kötü yazılmış veya bozuk kodların tüm sistemi kilitlemesini engelleyen Dört Kademeli Aktif Savunma ve Karantina Hattı.
Symfony boot edilirken config/bundles.php dosyası okunur. Bu aşamada henüz veritabanı bağlantısı, servis konteyneri veya autoloader tam olarak ayağa kalkmamıştır. Modüllerin aktiflik durumunu doğrudan veritabanından okumaya çalışırsak, sistem daha boot edilemeden kilitlenir.
Çözüm: CPalius, bir modül aktif/pasif edildiğinde active_modules.php adında statik, PHP opcache dostu bir dizi dosyası üretir. bundles.php sadece bu dosyayı okur — veritabanına hiç dokunmaz.
// Çekirdek her zaman ayakta $bundles = [ FrameworkBundle::class => ['all' => true], TwigBundle::class => ['all' => true], DoctrineBundle::class => ['all' => true], CoreBundle::class => ['all' => true], ]; // Aktif modülleri dosyadan oku $activeModules = require 'active_modules.php'; foreach ($activeModules as $moduleClass) { if (class_exists($moduleClass)) { $bundles[$moduleClass] = ['all' => true]; } }
Sınıfın fiziksel olarak var olması (class_exists), o modülün kodunun hatasız çalıştığı anlamına gelmez. Modülün boot() metodu içinde fırlatacağı bir TypeError veya RuntimeException tüm sistemi çökertebilir.
Çözüm: Kernel::boot() metodu override edilerek modül seviyesindeki tüm boot süreçleri try/catch (\Throwable) zırhıyla kuşatıldı. Hatalı modül otomatik karantinaya alınır, çekirdek çalışmaya devam eder.
Eklentideki geçersiz bir YAML sözdizimi veya yanlış bir DI tanımı, Symfony container'ı derlenemez hale getirir. Bu durumda terminalde komut bile çalıştırılamaz.
Çözüm: Modül aktive edilmeden önce symfony/process ile izole bir alt süreç başlatılır. Bu süreçte cache:clear → lint:yaml → lint:container komutları koşturulur. Hata varsa aktivasyon iptal edilir ve modül kalıcı olarak karantinaya alınır. Dosya asla bozuk haliyle kaydedilmez.
Standart Symfony'de bir modülün routes.yaml dosyasındaki syntax hatası tüm sistemi çökertir.
Çözüm: SafeModuleRouteLoader her modülün rotasını izole bir try/catch bloğunda yükler. Hatalı modül atlanır ancak sistemin geri kalanı %100 ayakta kalır.
foreach ($this->moduleRegistry->getHealthyModuleBundles() as $moduleClass) {
try {
$imported = $this->import($routesFile, 'yaml');
$collection->addCollection($imported);
} catch (\Throwable $e) {
// One broken routes.yaml never takes down the kernel.
$this->logger?->error('Skipping broken module routes', [
'module' => $moduleClass,
'error' => $e->getMessage(),
]);
}
}
Hibrit veri modeli, yüksek performanslı indeksleme ve çok dilli yapı — tümü ilk günden çekirdeğin hücrelerine işlenmiştir.
Sık sorgulanan temel alanlar (ID, Başlık, Slug, Durum) gerçek sütunlarda; dinamik, esnek alanlar (gövde, SEO, galeri) tek bir JSON sütununda. EAV'ın JOIN cehenneminden ve WordPress'in meta karmaşasından kurtulun.
JSON verilerini veritabanı bağımsız sorgulayın. NodeFieldIndex tablosu ve Doctrine Event Listener ile tip-uygun kolonlara sahip indeks tablosu. SQLite, MySQL ve Postgres'te aynı DQL çalışır.
Çoklu dil ilk günden çekirdeğe işlendi. Kompozit benzersizlik kısıtları ile UNIQUE(slug, locale) ve UNIQUE(translation_group_id, locale) güvencesi. Dil sonradan eklenen bir cila değildir.
Drupal'ın config sync yaklaşımı, Symfony TreeBuilder ile birleştirildi. Roller ve yetenek matrisleri YAML dosyalarında tutulur, Git ile taşınır. Kullanıcı verileri ise veritabanında kalır.
Her modül bağımsız bir Symfony Bundle olarak çalışır. Kendi routes, services, templates ve migrations dosyalarına sahiptir. Modules\ namespace'i ile tam izolasyon.
Geliştirici ve admin panelinde AssetMapper + Standalone Tailwind CSS kullanılır. Node.js bağımlılığı sıfır. Derleme adımı yok, doğrudan geliştirme — doğrudan deploy.
Manifesto Law 5.3 gereği, RichTextSanitizer ile veritabanına kaydedilecek her zengin metin çekirdek seviyesinde sterilize edilir.
Hibrit JSON tabanlı verilerden SchemaOrgBuilder aracılığıyla otomatik olarak JSON-LD (Schema.org) üretimi (BlogPosting, WebPage).
YAGNI prensibini çiğnemeden inşa edilen, asenkron ve decoupling odaklı reaktif haberleşme omurgası. Katmanlar arası bağımlılıklar ve hook tetikleyicileri (event subscribers), "Golden Ratio" hassasiyetinde orantılanarak minimize edilmiştir.
CPalius sadece bir CMS değildir; arkasında Oto Galeri, Turizm Acentası, Personel Yönetimi veya CRM/ERP sistemlerinin çalışabileceği esnek bir uygulama platformudur.
| Özellik | Content Entities (Node) | Business Records (Resource) |
|---|---|---|
| Kavramsal Karşılık | Sayfa, Yazı, İlan Vitrini, Blog | Araç, Fatura, Rezervasyon, Personel |
| Slug | Var — SEO dostu URL üretimi | Yok — İç yönetim kaydı |
| Çoklu Dil | Var — translation_group_id ile | Yok — Tek dilli kayıt |
| Yayın Durumu | Var — draft / published / archived | Yok — Durum makinesi (workflow) |
| SEO | Var — Meta bilgileri JSON data içinde | Yok — Herkese açık değil |
| Ortak Payda | Aynı Capability modeli, aynı Twig bileşenleri, aynı CLI yönetimi, aynı Config Sync | |
Geliştiricinin iş süreçlerini kodlamasını saniyeler seviyesine indirmek için özel bir PHP Attribute yapısı tasarlandı. Tek bir anotasyon ile veritabanındaki ham bir Doctrine sınıfını platformun tüm güçleriyle birleştiriyoruz.
Bu tek nitelik sayesinde:
#[CpResource( name: 'vehicle', module: 'oto-galeri', capabilities: [ 'create','edit', 'delete','view' ], auditable: true, multiTenant: true, workflow: 'vehicle_lifecycle' )] #[ORM\Entity] class Vehicle { private ?int $id; private ?string $plate; private ?string $brand; private ?int $price; }
#[CpResource(auditable: true)] veya #[Auditable] ile işaretlenmiş bir entity'nin her ekleme, güncelleme ve silme işlemi, denetlenen entity'ye asla dokunmayan tamamen izole bir Doctrine dinleyicisi tarafından otomatik olarak cp_audit_logs tablosuna yazılır.
onFlush / postFlush Dinleyicisi
Güncelleme ve silmeler onFlush içinde yakalanır — kimlikler zaten bilinir — ve UnitOfWork::computeChangeSet() ile aynı flush'a eklenir. Oluşturmalar, üretilen birincil anahtarın kaydedilebilmesi için postFlush'a kadar bekletilir, ardından tek bir korumalı yeniden flush ile kalıcı hale getirilir.
Aktif kullanıcı TokenStorageInterface'ten gelir; fark {field: [eskiDeğer, yeniDeğer]} JSON olarak saklanır. Oluşturmalar [null, yeniDeğer], silmeler [eskiDeğer, null] kullanır.
cp_audit_logs
Kolonlar: resource_name, resource_id (VARCHAR — kompozit ve UUID anahtarlar da sığar), user_id, action (create/update/delete), changes (JSON) ve created_at.
AuditLogRepository; findForResource(), findRecent() ve findByUser() metotlarını sunar. Kayıtlar uygulama üzerinden asla düzenlenmez veya silinmez — tasarım gereği yalnızca eklemedir.
#[AsDoctrineListener(event: Events::onFlush)]
#[AsDoctrineListener(event: Events::postFlush)]
final class AuditLogListener
{
public function onFlush(OnFlushEventArgs $args): void
{
$unitOfWork = $args->getObjectManager()->getUnitOfWork();
$auditable = $this->resourceRegistry->getAuditableEntityClasses();
foreach ($unitOfWork->getScheduledEntityUpdates() as $entity) {
if (!$this->isAuditable($entity, $auditable)) {
continue;
}
// {field: [eskiDeger, yeniDeger]} — ayni flush'a hesaplanir
$changes = $this->buildUpdateChanges($unitOfWork, $entity);
}
}
}
Whitepaper'ın ilk sürümünden bu yana çekirdeğe dört yeni genişletme omurgası eklendi: REST API Gateway, izole Hook Sistemi, birleşik Cron/Otomasyon Motoru ve Modülden bağımsız Plugin katmanı. Her biri aynı "Core Never Dies" zırhını taşır.
Tek bir /api/{path} joker route'u, #[CpApi] attribute'lu servis metotlarını derleme zamanında (ApiRegistrationPass) eşleştirir. Kimlik doğrulama X-CP-API-KEY header'ı ile, SHA-256 hashing ve zamanlama-saldırısı korumalı hash_equals() kullanılarak, fail-closed çalışır — anahtar geçersizse hedef metot hiç çağrılmaz. Her endpoint kendi try/catch zırhında izole edilir; çöken bir uç yalnızca kendini etkiler.
$providedHash = hash('sha256', $providedKey);
foreach ($this->loadAll() as $apiKey) {
if (!$apiKey->active) {
continue;
}
// Timing-attack safe compare — never early-return on length alone.
if (hash_equals($apiKey->hash, $providedHash)) {
return true;
}
}
return false;
Cotonti tarzı flat-file Hooks/{hook_point}.php dosyaları izole bir Closure scope içinde çalışır — dış scope'a değişken sızıntısı imkansızdır. Symfony tarzı #[CpHook] attribute'lu servisler ise HookRegistrationPass ile toplanır. Çöken hook sayfayı asla 500'e düşürmez, karantina günlüğüne yazılır.
// Cotonti-style: include inside a bound Closure — no $this leak.
$runner = static function (array $context) use ($file): void {
include $file;
};
try {
$runner($context);
} catch (\Throwable $e) {
$this->quarantineHook($file, $e);
}
// Attribute lane: #[CpHook('blog.render.sidebar')] on a service method
CronManager üç paralel kaynağı — veritabanındaki cp_cron_jobs, #[CpCronJob] işaretli servisler ve flat-file Hooks/cron.{job}.php dosyalarını — tek listede birleştirir. Görevler CronCommandWhitelist ile yalnızca cp:* önekli komutlara izin veren izole alt-süreçlerde çalıştırılır.
// 1) DB rows in cp_cron_jobs
// 2) #[CpCronJob] attribute methods
// 3) Hooks/cron.{name}.php flat files
foreach ($this->collectJobs() as $job) {
$this->processFactory->runIsolated($job);
}
Modüllerden ayrı ikinci bir genişletme noktası: PluginInterface işaretli servisler PluginRegistry tarafından toplanır, aktiflik durumu PluginToggleRepository ile veritabanında tutulur. Bir modül kendi içinde widget/sidebar gibi opsiyonel alt-özellikleri, modülün kendisinden bağımsız açıp kapatabilir.
Whitepaper'da kavram olarak duyurulan N+1 koruması artık gerçek bir Doctrine DBAL Middleware zincirinde çalışıyor: QueryCounterConnection, Driver, Statement ve TableParser birlikte, tablo bazlı sorgu sayacı tutar ve limiti aşınca MaxQueriesExceededException fırlatır.
symfony/messenger paketi kurulu ve AACP Sistem Monitörü'nde durumu görünür durumda. Gelecekteki e-posta, bildirim ve toplu işlem kuyrukları için temel şimdiden atıldı; henüz aktif bir transport bağlanmadı.
#[CpSetting] ile yönetilen ve veritabanından sadece talep edildiğinde tek bir sorguyla çekilen ayar altyapısı (SettingsRegistry). Performans bütçesine sadıktır.
Whitepaper'ın roadmap bölümünde vaat edilen Safe Mode / Kurtarma Konsolu artık gerçek: veritabanı tamamen çökse dahi ayakta kalan, token tabanlı bir kurtarma arayüzü dahil, AACP tam bir sistem yönetim merkezine dönüştü.
/aacp/recovery ucu security.yaml'da bilinçli olarak herkese açık (PUBLIC_ACCESS) bırakılmıştır; yetkilendirmeyi kendisi .env'deki AACP_RECOVERY_TOKEN ile hash_equals() (timing-safe) karşılaştırması yapar. Hiç Doctrine sorgusu çalıştırmaz — veritabanı tamamen çökmüşken bile devrededir. Token boşsa kapı tamamen kapalıdır (fail-safe).
/aacp/system ve /aacp/system/metrics JSON ucu; load average, memory, OPcache hit-rate, veritabanı bağlantı durumu ve Messenger kuyruk durumunu htop tarzı canlı olarak raporlar. Kurulu olmayan bileşenler için dürüstçe "kurulu değil" bilgisi döner.
/aacp/quarantine — module_quarantine.log dosyasını okuyup listeleyen salt-okunur panel. /aacp/system/cache-rebuild/* ise Symfony cache, OPcache reset ve Tailwind asset rebuild işlemlerini aynı CSRF token'ı paylaşan üç ayrı AJAX ucu üzerinden tetikler.
TranslationManager, çekirdek ve tüm modüllerin messages+intl-icu.{tr,en}.yaml dosyalarını web üzerinden düzenlemeyi, atomik dosya yazma garantisiyle (.tmp + rename()) sağlar. Ayrı bir Performans Yönetimi ekranı ise Redis, Memcached, Varnish ve Nginx PageSpeed için canlı bağlantı testleri çalıştırır — "aktif" bayrağı yalnızca test başarılıysa set edilir.
REST Gateway için anahtar üretimi ve yaşam döngüsü yönetimi.
DB + attribute + flat-file kaynaklı görevlerin birleşik listesi.
Tüm kanca noktalarını ve bağlı dinleyicileri keşfeden panel.
Aktif/pasif/varsayılan dil ayarları, tek doğruluk kaynağı.
Blog, Medya ve Menü modülleri, platformun her genişletme noktasını (API, Hook, Cron, Plugin, Settings) uçtan uca kullanan referans implementasyonlardır.
Node::type='post' üzerine kurulu tam blog sistemi. Kategori/etiket yönetimi, zamanlanmış yayınlama (PublishScheduledPostsTask), GET /api/blog/posts REST ucu, sidebar hook'u ve Schema.org (BlogPosting) JSON-LD üretimi bir arada.
AssetManager ve bağımsız Asset entity'si üzerine kurulu medya kütüphanesi + görsel seçici (picker) admin arayüzü. Flysystem depolama katmanı üzerinde sha256 tabanlı deduplikasyon.
WordPress tarzı sürükle-bırak frontend menü yönetimi. Menu/MenuItem entity'leri, soft-delete uyumu için Node'a gevşek referansla (FK değil) bağlanır.
Forum modülü, platformun tam bir topluluk paketini — hiyerarşik panolar, konu önekleri, moderasyon kuyruğu ve rütbe/rozet sistemi — CPalius'un geri kalanıyla aynı Node ağacı ve Capability modeli üzerinde taşıyabildiğini kanıtlar.
Panolar, içerik için kullanılan aynı Node ağacında istenen derinlikte iç içe geçer. Alt forumlar, kategoriler ve özel bölümler izinlerini üst öğeden devralır; her pano tek sorguluk indeks render'ı için kendi son-ileti önbelleğini tutar.
Pano bazında [Duyuru], [Çözüldü] ve [Soru] gibi kendi rengi, izinleri ve filtreleri olan önekler — konuda saklanır, başlığa ve liste çiplerine işlenir.
Üyeler iletileri bir gerekçeyle raporlar; raporlar, moderatörlerin taşıdığı, birleştirdiği, kilitlediği, yumuşak-sildiği veya reddettiği özel bir kuyruğa düşer. Her işlem bir Capability kontrolüdür ve tüm akış CSRF korumalıdır.
İleti sayısı ve itibar eşikleri üyeleri yapılandırılabilir rütbeler arasında terfi ettirir; manuel rozetler ve kullanıcı bazlı bir itibar defteri (gerekçeleriyle) profil kartını ve aktivite panelini besler.
İleti görünümü %20 yazar kartı / %80 ileti gövdesi olarak bölünür — CPalius genelinde kullanılan Altın Oran — böylece uzun konular sabit bir sidebar genişliği olmadan her ekranda okunabilir kalır.
Hiyerarşik panolar, konu önekleri ve moderasyon kuyruğu üretimde çalışır — vitrinden doğrudan Forum Engine'e geçin.
.forum-postbit { display: grid; grid-template-columns: 20% 80%; gap: var(--sp-md); }
.forum-postbit__author { /* rank, badges, reputation */ }
.forum-postbit__body { /* message + reactions */ }
GD tabanlı bir servis, yüklenen görselleri istenen her boyuta anında yeniden boyutlandırıp kırpar, her türevi public/uploads/cache/ altında önbelleğe alır ve tek bir Twig filtresiyle şablonlara sunar.
ImageProcessor::thumbnail($source, $width, $height, $mode); bir crop (kapla + ortadan kırp) veya fit (sığdır, büyütme yok) türevi üretir, PNG/GIF/WebP için şeffaflığı korur ve fail-soft'tur — işlenemeyen tek bir görsel sayfayı kırmak yerine orijinal URL'i döner.
Türevler public/uploads/cache/<g>x<y>-<mod>/ altına yazılır ve sonraki her istekte doğrudan web sunucusu tarafından servis edilir. Önbellek isabeti, kaynağa karşı tek bir filemtime() karşılaştırmasıdır; purge() bir asset değiştiğinde onun tüm boyutlarını temizler.
{# Herhangi bir Asset, asset id, depolama anahtari veya /uploads/... URL #}
<img src="{{ asset|cp_thumb(300, 200) }}" alt="{{ asset.originalName }}">
{# 'fit' goruntunun tamamini buyutmeden kutuya sigdirir #}
<img src="{{ featuredImageUrl|cp_thumb(800, 600, 'fit') }}" alt="">
cp_thumb Twig filtresi bir Asset, bir asset id'si, bir depolama anahtarı veya bir /uploads/... URL'i kabul eder ve yeniden boyutlandırılmış türev URL'ini döner — örneğin {{ asset|cp_thumb(300, 200) }} veya {{ url|cp_thumb(800, 600, 'fit') }}.
İçerikler translation_group_id UUID'si ile dikey bağlanır; LocaleSwitchService kardeş kayıt yoksa bile 404 vermez; dil dosyaları elektrik kesilse bile bozulmayan atomik .tmp + rename() yazma ile diske işlenir.
Her içerik satırı kendi dilinde dikey yaşar ve translation_group_id UUID'si ile kardeşlerine bağlanır. DB katmanında UNIQUE(translation_group_id, locale) kuralı eşzamanlı isteklerde bile 'bir grupta her dilden en fazla bir kayıt' garantisini zorlar.
Dil değiştirici mevcut sayfanın karşı dildeki URL'ini üretir. Kardeş slug yoksa veya rota üretimi başarısızsa hedef dilin ana sayfasına düşer — asla 404. AACP yolu öneksizdir; panel dili cp_locale çereziyle yönetilir.
TranslationManager YAML'i önce .tmp-* dosyasına yazar, ardından işletim sistemi seviyesinde rename() ile hedefi atomik olarak ezer. Elektrik kesilse bile çeviri dosyası yarım/bozuk kalamaz.
try {
$params = $this->withTranslatedParams($request, $params, $targetLocale);
$params['_locale'] = $targetLocale;
return $this->urlGenerator->generate($route, $params);
} catch (RoutingException|Throwable) {
// Missing sibling or broken route → locale home, never 404.
return $this->homeUrl($targetLocale);
}
$tmpPath = $filePath . '.tmp-' . bin2hex(random_bytes(4)); $this->filesystem->dumpFile($tmpPath, $yaml); // OS-level rename is atomic on the same filesystem. $this->filesystem->rename($tmpPath, $filePath, true);
Güvenlik ve performans, projenin son aşamasında "üzerine eklenen" bir cila değildir; sistemin en temel yapı taşlarıdır.
Standart ROLE_ADMIN yaklaşımı yerine dinamik olarak üretilen yetenekler kontrol edilir. Kodun hiçbir yerinde rol ismi kontrol edilmez.
denyAccessUnlessGranted('system.module.manage')
Roller = Config (YAML): Git ile taşınır.
Kullanıcılar = Content (DB): Asla dışa aktarılmaz.
Çok kiracılı (SaaS) sistemlerde en büyük güvenlik açığı: yazılımcının WHERE tenant_id = ? yazmayı unutması.
CPalius'ta bu ihtimal platform seviyesinde yok edilmiştir. Doctrine SQLFilter otomatik olarak her sorguya tenant kısıtını enjekte eder. Geliştiricinin müdahalesine gerek kalmaz.
Veritabanı yavaşlıklarının en yaygın sebebi olan N+1 sorgu hatalarını engelleyen Doctrine Listener. Dev ortamında tetiklenir.
Tek HTTP isteğinde aynı tabloya atılan sorgu sayısı limiti aşarsa MaxQueriesExceededException fırlatılır. Geliştirici bu hatayı lokalde çözmeden kodu canlıya alamaz.
Liste ekranlarındaki PHP tabanlı Voter kontrollerini (N+1 bellek krizini) ortadan kaldıran QueryScopeApplier.
Kullanıcının .own veya .any yetenekleri, sorgu veritabanına gitmeden önce doğrudan Doctrine QueryBuilder üzerinden SQL WHERE koşuluna çevrilir.
Dış dünyadan gelen hiçbir HTTP yüküne (payload) güvenmeyen strict-type DTO (Data Transfer Object) mimarisi. Veriler denetleyicilere (controllers) ulaşmadan önce Symfony Validator ile otonom olarak sterilize edilir.
Kötü niyetli manipülasyon girişimleri anında reddedilerek çekirdeğin bütünlüğü "Golden Ratio" kusursuzluğunda korunur.
Geleneksel sistemlerdeki tablo kilitleme (table-lock) krizlerini tarihe gömen Optimistic Locking omurgası. Aynı anda gerçekleşen binlerce veri mutasyonu, atomik transaksiyonlarla deadlock olmadan izole edilir.
YAGNI felsefesiyle karmaşadan arındırılan bu altyapı, sunucu darboğazlarını (bottleneck) saf donanımsal limitlere kadar erteler.
CPalius CMF'in kurumsal omurgasını oluşturan 5 temel mimari prensip ve kod seviyesindeki derin özellikleri.
Two-Class Entity ve JSON-Relational Hibrit Yapı: Geleneksel CMS'lerdeki hantal EAV (Entity-Attribute-Value) yapısını tamamen reddeden CPalius, alanları iki ayrı sınıfta yönetir. İş kayıtları (#[CpResource]) kesin strict-tip SQL kolonlarında tutulurken, içerik kayıtları (Node) esnekliği sağlamak adına tüm dinamik verilerini tek bir JSON kolonunda saklar.
Performans Dehası (Flat-Field Index Motoru): JSON kolonlarında WHERE koşulu ile arama yapmak yavaş olduğu için, CPalius Doctrine Event Listener tabanlı otonom bir düzleştirme (flattening) motoru kullanır. queryable: true işaretli alanlar node_field_index tablosuna yansıtılır. ProcessWire'dan ilham alan findNodesBySelector API'si ile karmaşık sorgular basitleşir.
// Süper akıcı (fluent) Selector API kullanımı
$nodes = $nodeRepository->findNodesBySelector(
'type=post, status=published, is_featured=1, limit=5, sort=createdAt:desc'
);
// Arka planda çalışan Flat-Field motoru kesiti
// JSON'daki dinamik 'is_featured' alanı, indeks tablosundaki
// 'value_int' üzerinden çok yüksek hızda JOIN'lenir.
Core Never Dies (Çökmeyen Çekirdek): Kullanıcı alanı (cp-content/modules) ile çekirdek (cp-core) arasına devasa bir izolasyon katmanı örülmüştür. Üçüncü parti hatalı bir modül tüm uygulamayı çökertemez.
Karantina Zırhı ve Acil Durum Vanası: Modül aktif edilirken symfony/process üzerinden izole bir alt süreçte lint:container ve lint:yaml testleri koşturulur. Çalışma anında ise giriş kapıları try/catch kalkanıyla donatılmıştır. Çöken modül anında yoksayılıp module_quarantine.log dosyasına yazılır.
// ApiGatewayController'daki gerçek zamanlı karantina izolasyonu
try {
$service = $this->serviceLocator->get($serviceId);
$result = $service->$methodName($request, ...$endpoint['pathParameters']);
return $result instanceof JsonResponse ? $result : new JsonResponse($result);
} catch (\Throwable $e) {
// Çöken modül tüm sistemi 500'e düşürmez.
// İzole edilip loglanır, Gateway ayakta kalmaya devam eder.
$this->quarantineApiFailure($serviceId, $methodName, $e);
return new JsonResponse(['error' => 'Internal API Error'], 500);
}
Kurumsal Çoklu Dil Topolojisi: Dil desteği çekirdeğin parçasıdır. Her içerik dikey bir tablo satırı (Node) olarak üretilir ve translationGroupId UUID'si ile birbirine bağlanır. DB katmanında fiziksel olarak korunur.
Plug-and-Play Çeviri Derlemesi: Modüller kendi çevirilerini kendi dizinlerinde barındırır. TranslationFileLocator bunları bulur ve Symfony Compiler Pass ile framework.translator.paths dizisine enjekte eder. Çeviriler atomik yazma algoritmasıyla diske işlenir.
// TranslationManager içerisindeki atomik dosya yazma garantisi
$dir = dirname($filePath);
if (!is_dir($dir)) {
$this->filesystem->mkdir($dir);
}
// 1. Önce .tmp uzantılı geçici bir dosyaya güvenlice yazılır
$yaml = Yaml::dump($data, 2, 2);
$tmpPath = $filePath . '.tmp-' . bin2hex(random_bytes(4));
$this->filesystem->dumpFile($tmpPath, $yaml);
// 2. İşletim sistemi seviyesindeki rename() ile hedef dosya anında ezilir.
// Elektrik dahi kesilse dosya asla yarım/bozuk kalamaz (Atomicity).
$this->filesystem->rename($tmpPath, $filePath, true);
Birleşik Cron Altyapısı: Eski tip veritabanı cronları ile modern mimari birleşmiştir. #[CpCronJob] özniteliği ile sanal görevler veya Hooks/cron.*.php dosyaları oluşturulabilir.
İzole Tetikleme ve Sistem Gözetimi: CronManager görevleri izole alt süreçler halinde (Process) çalıştırarak memory leak'leri önler. Yöneticiler /aacp/cron siber-konsolu üzerinden görevleri canlı izleyebilir ve "Şimdi Çalıştır" AJAX sinyalleriyle tetikleyebilir.
// cp-content/modules/Blog/Cron/PublishScheduledPostsTask.php
final class PublishScheduledPostsTask
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly NodeRepository $nodeRepository,
) {}
// Hiçbir DB kaydına ihtiyaç duymadan, saf öznitelik tabanlı cron kaydı
#[CpCronJob(schedule: '*/5 * * * *', name: 'blog.publish_scheduled')]
public function execute(): string
{
$dueNodes = $this->nodeRepository->findDueScheduledNodes();
if ($dueNodes === []) {
return 'Yayin zamani gelmis icerik yok.';
}
foreach ($dueNodes as $node) {
$node->publish($node->getPublishedAt());
}
$this->entityManager->flush();
return sprintf('%d icerik yayina alindi.', count($dueNodes));
}
}
Routing Karmaşasına Son: Modül geliştiricileri routing dosyaları yerine metodun üzerine #[CpApi] özniteliğini koyarak uç nokta açar. ApiGatewayController üzerinden merkezi olarak yönetilir.
Kriptografik Güvenlik Omurgası: X-CP-API-KEY başlığı cp_settings üzerinden kontrol edilir. ApiKeyService, zamanlama saldırısı (timing attack) korumalı hash_equals fonksiyonuyla SHA-256 doğrulamasını yapar.
// 1. Modül içerisindeki tertemiz uç nokta
#[CpApi(path: '/blog/posts', methods: ['GET'], public: false)]
public function getPosts(Request $request): JsonResponse
{
// Is mantigi...
}
// 2. ApiGatewayController'daki fail-closed zırhı
// public:false olan rotalarda API anahtari eksikse hedef metot
// KESINLIKLE çagrilmaz.
if (!$endpoint['definition']['public'] && !$this->hasValidApiKey($request)) {
return new JsonResponse(['error' => 'Unauthorized'], Response::HTTP_UNAUTHORIZED);
}
İlk whitepaper'da vaat edilen maddelerden Safe Mode, anlık görsel pipeline'ı ve audit log tamamlandı. Sıradaki geliştirme sprintlerinde aşağıdaki sistemler inşa edilecek.
Fatura, araç, rezervasyon gibi iş kayıtlarının geçiş süreçlerini (draft → preparation → sold) YAML tanımlarıyla yöneten ve her geçişi otomatik audit log'a bağlayan mekanizma. CpResource::$workflow alanı zaten deklare edilmiş durumda — sıradaki adım gerçek transition/guard motorunu bağlamak.
Teslim edildi. ImageProcessor (GD) anlık olarak yeniden boyutlandırır/kırpar ve public/uploads/cache/ altında önbelleğe alır; cp_thumb Twig filtresi bunu her temaya açar.
Teslim edildi. cp_audit_logs tablosu ve izole bir onFlush/postFlush dinleyicisi, denetlenebilir bir entity'nin her create/update/delete işlemini kaydeder. Herhangi bir entity'ye #[Auditable] eklemek onu devreye alır.
symfony/messenger kurulu ve AACP Sistem Monitörü'nde izlenebiliyor; sıradaki adım gerçek bir transport (Doctrine/Redis) bağlayıp e-posta ve bildirim işlemlerini asenkron kuyruğa taşımak.
CPalius, topluluğun gücüyle en sağlam uygulama framework'üne dönüşecek. Fikirlerinizi, eleştirilerinizi ve mimari önerilerinizi heyecanla bekliyoruz.