NEXT-GEN CONTENT MANAGEMENT FRAMEWORK

CPalius CMF

From a Content Management System
"Bulletproof" Enterprise Application Framework

A world-class, optimized, secure, and extensible foundation that bridges plugin-rich but cumbersome CMS platforms and frameworks that require starting everything from scratch.

PHP 8.2+ Symfony 7.4 LTS Doctrine ORM AssetMapper Open Source

Theory, Practice, and the Pain of Reinventing the Wheel

Every modern web project starts on a double-edged sword. CPalius was built to close the gap between these two worlds.

Current Challenges

Classic CMS Platforms (WordPress, Drupal)

Packed with plugins and themes, yet burdened by cumbersome database schemas, mountains of technical debt, and security weaknesses.

Pure Frameworks (Symfony, Laravel)

An approach that wastes time by rebuilding core components such as authentication, ACL, file management, and admin panels for every project.

The Romance of Building MVC from Scratch

Writing your own framework may sound romantic, but it hides a massive iceberg of security (CSRF, XSS, SQLi), dependency injection, and HTTP-layer concerns.

The CPalius Solution

World-Class Foundation

An architecture built on Symfony 7.4 LTS's proven security and performance foundation, free from technical debt.

Ready-Made Enterprise Components

Core components such as authentication, ACL, file management, localization, and an admin panel are included from day one. No more reinventing the wheel.

Modular and Extensible

More than a CMS: an application platform for car dealerships, travel agencies, CRM, and ERP systems — all running on the same foundation.

An Unbreakable Core

Errors from user modules never bring down the system. Four layers of active defense and quarantine keep the core running.

"Pristine Root" and Folder Architecture

As third-party packages and recipes accumulate, a standard Symfony project root becomes cluttered. CPalius follows a "Pristine Root" policy.

pristine-root
CPalius/
│
├── cp-core/          # KERNEL & SYSTEM SPACE
│   ├── bin/          # Console command tools
│   ├── config/       # Core configuration
│   ├── migrations/   # Database migrations
│   ├── src/          # PHP classes (App\)
│   └── var/          # Cache, logs, SQLite
│
├── cp-includes/      # DEPENDENCIES SPACE
│   └── vendor/       # Composer packages
│
├── cp-content/       # USER & DEVELOPER SPACE
│   ├── config/       # Config Sync area
│   ├── modules/      # Independent modules
│   ├── themes/       # UI themes
│   └── translations/ # Translations (tr, en)
│
├── public/           # WEB ROOT
│   ├── index.php     # Front Controller
│   └── assets/       # Frontend assets
│
├── .env
└── composer.json
cp-core/ Kernel & System Space

Core PHP classes, configuration, console tools, and database migrations. Symfony Flex recipes are guaranteed to install directly here.

cp-includes/ Dependencies Space

Composer packages and Symfony libraries live in this isolated space. The vendor-dir has been reconfigured.

cp-content/ User & Developer Space

Modules, themes, translations, and Config Sync live here. Developer code never mixes with framework system files.

public/ Web Root

The only public folder. The Front Controller (index.php) and compiled frontend assets live here. This is the security boundary.

"Core Never Dies" — An Unbreakable Core Architecture

A four-layer active defense and quarantine line that prevents bad or broken user code from locking down the entire system.

1
Defense Line 1

Solving the Chicken-and-Egg Problem

When Symfony boots, it reads config/bundles.php. At this stage the database connection, service container, and autoloader are not fully ready. Trying to read module status from the database would lock the system before it can boot.

Solution: When a module is activated or deactivated, CPalius generates a static, PHP opcache-friendly array file named active_modules.php. bundles.php only reads that file — it never touches the database.

cp-core/config/bundles.php
// Core always stays up
$bundles = [
    FrameworkBundle::class => ['all' => true],
    TwigBundle::class      => ['all' => true],
    DoctrineBundle::class  => ['all' => true],
    CoreBundle::class      => ['all' => true],
];

// Load active modules from file
$activeModules = require 'active_modules.php';
foreach ($activeModules as $moduleClass) {
    if (class_exists($moduleClass)) {
        $bundles[$moduleClass] = ['all' => true];
    }
}
2
Defense Line 2

Runtime Isolation

A class existing on disk (class_exists) does not mean its code runs safely. A TypeError or RuntimeException thrown inside a module's boot() method can crash the entire system.

Solution: Kernel::boot() is overridden so every module-level boot process is wrapped in try/catch (\Throwable). Faulty modules are quarantined automatically while the core keeps running.

3
Defense Line 3

Compile-Time Lock Protection & Dry-Run

Invalid YAML syntax or a bad DI definition in a plugin can make the Symfony container uncompilable. In that state, even terminal commands fail.

Solution: Before activation, an isolated subprocess is started with symfony/process. It runs cache:clearlint:yamllint:container. On failure, activation is cancelled and the module is permanently quarantined. Broken state is never written to disk.

4
New — Defense Line 4

Isolated Route Loader

In standard Symfony, a syntax error in a module's routes.yaml file crashes the entire system.

Solution: SafeModuleRouteLoader loads each module's routes inside an isolated try/catch block. The faulty module is skipped while the rest of the system stays 100% available.

cp-core/src/Core/Routing/SafeModuleRouteLoader.php
foreach ($this->moduleRegistry->getHealthyModuleBundles() as $moduleClass) {
    try {
        $imported = $this->import($routesFile, 'yaml');
        $collection->addCollection($imported);
    } catch (\Throwable $e) {
        $this->logger?->error('Skipping broken module routes', [
            'module' => $moduleClass,
            'error' => $e->getMessage(),
        ]);
    }
}

Data Model and Platform Capabilities

A hybrid data model, high-performance indexing, and localization are built into the core from day one.

Hybrid Data Model

Frequently queried fields (ID, Title, Slug, Status) live in real columns; flexible fields (body, SEO, gallery) live in a single JSON column. Escape EAV JOIN hell and WordPress meta chaos.

Flat Field Index Engine

Query JSON data in a database-agnostic way. NodeFieldIndex plus a Doctrine Event Listener build a typed index table. The same DQL works on SQLite, MySQL, and Postgres.

Localization (i18n)

Multilingual support is baked into the core from day one. Composite uniqueness guarantees UNIQUE(slug, locale) and UNIQUE(translation_group_id, locale). Language is not a late polish layer.

Config Sync System

Drupal's config sync approach, combined with Symfony TreeBuilder. Roles and capability matrices live in YAML and travel with Git. User data stays in the database.

Modular Bundle Architecture

Every module runs as an independent Symfony Bundle with its own routes, services, templates, and migrations. Full isolation under the Modules\ namespace.

Zero Node.js Policy

Developer and admin panels use AssetMapper + Standalone Tailwind CSS. Zero Node.js dependency. No build step — develop and deploy directly.

Core-Level XSS Sanitization

Per Manifesto Law 5.3, every rich-text value destined for the database is sterilized at the core level via RichTextSanitizer.

Dynamic Semantic SEO

Automatic JSON-LD (Schema.org) generation (BlogPosting, WebPage) from hybrid JSON-based data through SchemaOrgBuilder.

Autonomous Event-Driven Topology

A reactive messaging backbone built without violating YAGNI — asynchronous and decoupling-focused. Cross-layer dependencies and hook triggers (event subscribers) are minimized with "Golden Ratio" precision.

Built on Proven Foundations

PHP 8.2+

Core Language

Symfony 7.4 LTS

Framework Foundation

Doctrine ORM

Database Layer

AssetMapper

Frontend Assets

Tailwind CSS

Standalone Binary

Two Entity Classes: Content vs Business

CPalius is more than a CMS; it is a flexible application platform for car dealerships, travel agencies, personnel management, and CRM/ERP systems.

Feature Content Entities (Node) Business Records (Resource)
Conceptual Equivalent Pages, Articles, Listing Showcases, Blogs Vehicles, Invoices, Reservations, Personnel
Slug Yes — SEO-friendly URL generation No — Internal management record
Localization Yes — with translation_group_id No — Monolingual record
Publication Status Yes — draft / published / archived No — State machine (workflow)
SEO Yes — Metadata in JSON data No — Not public
Common Ground The same Capability model, Twig components, CLI management, and Config Sync

#[CpResource] Revolution

To reduce business-process development to seconds, a custom PHP Attribute was designed. With a single annotation, a plain Doctrine class is connected to the full power of the platform.

With this single attribute:

  • Dynamic capabilities are registered automatically in the role matrix
  • CRUD forms and list screens are derived dynamically
  • SaaS multi-tenant isolation is applied automatically
  • All changes are recorded in the version history (audit log)
Example: Vehicle Entity
#[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] Audit Log — Who Changed What, When

Every insert, update, and delete of an entity marked #[CpResource(auditable: true)] or #[Auditable] is written automatically to the cp_audit_logs table by a fully isolated Doctrine listener that never touches the audited entity itself.

Isolated Change Capture

onFlush / postFlush Listener

Updates and deletes are captured in onFlush — identifiers are already known — and inserted into the same flush via UnitOfWork::computeChangeSet(). Creates are held until postFlush so the generated primary key can be recorded, then persisted with a single guarded re-flush.

The current user comes from TokenStorageInterface; the diff is stored as {field: [oldValue, newValue]} JSON. Creates use [null, newValue], deletes use [oldValue, null].

Append-Only History Table

cp_audit_logs

Columns: resource_name, resource_id (VARCHAR — composite and UUID keys fit too), user_id, action (create/update/delete), changes (JSON), and created_at.

AuditLogRepository exposes findForResource(), findRecent(), and findByUser(). Records are never edited or deleted through the application — append-only by design.

cp-core/src/Core/Audit/EventListener/AuditLogListener.php
#[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: [oldValue, newValue]} — computed into the same flush
            $changes = $this->buildUpdateChanges($unitOfWork, $entity);
        }
    }
}

Platform Extensibility Layer

Since the first whitepaper release, four new extension backbones have been added to the core: REST API Gateway, an isolated Hook System, a unified Cron/Automation Engine, and a module-independent Plugin layer. Each carries the same "Core Never Dies" armor.

#[CpApi] Gateway

Cryptographic REST API Gateway

A single /api/{path} wildcard route matches services annotated with #[CpApi] at compile time via ApiRegistrationPass. Authentication uses the X-CP-API-KEY header, verified with SHA-256 hashing and the timing-attack-safe hash_equals(), in a fail-closed manner — if the key is invalid, the target method is never called. Each endpoint is isolated in its own try/catch armor; a crashing endpoint only affects itself.

ApiKeyService::isValid()
$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;
Dual Lane

Dual-Track Isolated Hook Engine

Cotonti-style flat-file Hooks/{hook_point}.php files run inside an isolated Closure scope — variable leakage into outer scope is impossible. Symfony-style services annotated with #[CpHook] are collected via HookRegistrationPass. A crashing hook never turns the page into a 500; it is written to the quarantine log.

HookManager — flat-file Closure scope
// 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
Hybrid Engine

Unified Hybrid Cron / Automation Engine

CronManager merges three parallel sources — database cp_cron_jobs, services marked with #[CpCronJob], and flat-file Hooks/cron.{job}.php files — into a single list. Jobs run in isolated subprocesses allowed only for cp:*-prefixed commands via CronCommandWhitelist.

CronManager — unified sources
// 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);
}

Module-Independent Plugin Layer

A second extension point apart from modules: services marked with PluginInterface are collected by PluginRegistry, and activation state is stored in the database via PluginToggleRepository. A module can toggle optional sub-features such as widgets/sidebars independently of the module itself.

N+1 Guard at the DBAL Middleware Level

The N+1 protection announced as a concept in the whitepaper now runs as a real Doctrine DBAL Middleware chain: QueryCounterConnection, Driver, Statement, and TableParser together keep a per-table query counter and throw MaxQueriesExceededException when the limit is exceeded.

Async Queue Infrastructure (Prepared)

The symfony/messenger package is installed and its status is visible in the AACP System Monitor. The foundation for future email, notification, and bulk-processing queues is already in place; no active transport is wired yet.

Lazy-Load Settings Engine

A settings infrastructure managed with #[CpSetting] and loaded from the database in a single query only when requested (SettingsRegistry). It stays faithful to the performance budget.

AACP — Admin Control Panel & Recovery Mode

The Safe Mode / Recovery Console promised in the whitepaper roadmap is now real: including a token-based recovery interface that stays up even if the database is completely down, AACP has become a full system management center.

Completed — Manifesto Law 2.3

Safe Mode & Recovery Console (/aacp/recovery)

The /aacp/recovery endpoint is intentionally left public (PUBLIC_ACCESS) in security.yaml; it authorizes itself by comparing the AACP_RECOVERY_TOKEN from .env with hash_equals() (timing-safe). It runs no Doctrine queries — it remains operational even when the database is completely down. If the token is empty, the door stays fully closed (fail-safe).

New

Live System Monitor (htop-style)

The /aacp/system and /aacp/system/metrics JSON endpoints report load average, memory, OPcache hit-rate, database connection status, and Messenger queue status live in an htop-like fashion. For components that are not installed, it honestly returns "not installed".

New

Quarantine Screen & Cache Rebuild Console

/aacp/quarantine — a read-only panel that reads and lists the module_quarantine.log file. /aacp/system/cache-rebuild/* triggers Symfony cache, OPcache reset, and Tailwind asset rebuild operations through three separate AJAX endpoints that share the same CSRF token.

New

Localization Panel & Performance Management

TranslationManager lets you edit core and module messages+intl-icu.{tr,en}.yaml files from the web with an atomic write guarantee (.tmp + rename()). A separate Performance Management screen runs live connection tests for Redis, Memcached, Varnish, and Nginx PageSpeed — the "active" flag is set only when the test succeeds.

API Key Management

Key generation and lifecycle management for the REST Gateway.

Cron Management

A unified list of tasks from DB, attribute, and flat-file sources.

Hook Explorer

A panel that discovers all hook points and attached listeners.

Language (Locale) Management

Active/passive/default language settings — a single source of truth.

First-Party Modules: Proof of the Platform

The Blog, Media, and Menu modules are reference implementations that exercise every platform extension point (API, Hook, Cron, Plugin, Settings) end to end.

Blog Module

A full blog system built on Node::type='post'. Category/tag management, scheduled publishing (PublishScheduledPostsTask), a GET /api/blog/posts REST endpoint, a sidebar hook, and Schema.org (BlogPosting) JSON-LD generation — all together.

Media Module

A media library plus image picker admin UI built on AssetManager and an independent Asset entity. SHA-256-based deduplication on a Flysystem storage layer.

Menu Module

WordPress-style drag-and-drop frontend menu management. Menu/MenuItem entities bind to Node with a loose reference (not an FK) for soft-delete compatibility.

CPalius Forum Engine

The Forum module proves the platform can carry a full community suite — hierarchical boards, thread prefixes, a moderation queue, and a rank/badge system — on the same Node tree and Capability model as the rest of CPalius.

Hierarchical Node Tree

Boards nest to any depth on the same Node tree used for content. Sub-forums, categories, and private sections inherit permissions from their parent while each board keeps its own last-post cache for a single-query index render.

Thread Prefixes

Per-board prefixes such as [Announcement], [Solved], and [Question] with their own colour, permissions, and filters — stored on the topic and rendered into the title and the listing chips.

Report & Moderation Queue

Members report posts with a reason; reports land in a dedicated queue where moderators move, merge, lock, soft-delete, or dismiss. Every action is a Capability check, and the whole flow is CSRF-guarded.

Ranks & Badges

Post-count and reputation thresholds promote members through configurable ranks; manual badges and a per-user reputation ledger (with reasons) drive the profile card and the activity panel.

Golden-Ratio Fluid Layout

The post view splits 20% author card / 80% message body — the Golden Ratio proportion used across CPalius — so long threads stay readable on every viewport without a fixed sidebar width.

Live Forum

Hierarchical boards, thread prefixes, and the moderation queue are production-ready — jump from the showcase into the Forum Engine.

Join the Discussion

Postbit — 20% / 80% Golden Ratio
.forum-postbit { display: grid; grid-template-columns: 20% 80%; gap: var(--sp-md); }
.forum-postbit__author { /* rank, badges, reputation */ }
.forum-postbit__body { /* message + reactions */ }

Media & Image Processing Pipeline

A GD-based service resizes and crops uploaded images to any requested dimension on demand, caches every derivative under public/uploads/cache/, and exposes it to templates through a single Twig filter.

ImageProcessor (GD)

ImageProcessor::thumbnail($source, $width, $height, $mode) generates a crop (cover + centre-crop) or fit (contain, no upscale) derivative, preserves transparency for PNG/GIF/WebP, and is fail-soft — a single image that cannot be processed returns the original URL instead of breaking the page.

Persistent Disk Cache

Derivatives are written to public/uploads/cache/<w>x<h>-<mode>/ and served directly by the web server on every later request. A cache hit is a single filemtime() comparison against the source; purge() drops every size of one asset when it is replaced.

{{ asset|cp_thumb(300, 200) }}
{# Any Asset, asset id, storage key or /uploads/... URL #}
<img src="{{ asset|cp_thumb(300, 200) }}" alt="{{ asset.originalName }}">

{# 'fit' keeps the whole image inside the box without upscaling #}
<img src="{{ featuredImageUrl|cp_thumb(800, 600, 'fit') }}" alt="">

The cp_thumb Twig filter accepts an Asset, an asset id, a storage key, or a /uploads/... URL and returns the resized derivative URL — for example {{ asset|cp_thumb(300, 200) }} or {{ url|cp_thumb(800, 600, 'fit') }}.

Atomic Translation Safety & Smart Locale Switching

Content rows bind vertically through a translation_group_id UUID; LocaleSwitchService never 404s when a sibling is missing; translation files are written with atomic .tmp + rename() so a power cut cannot corrupt them.

translation_group_id UUID

Each content row lives in its own locale and links to siblings through a translation_group_id UUID. At the DB layer, UNIQUE(translation_group_id, locale) enforces at most one row per locale per group — even under concurrent requests.

LocaleSwitchService — Never-404 Switching

The language switcher builds the counterpart URL for the current page. If the sibling slug is missing or route generation fails, it falls back to that locale's homepage — never a 404. AACP has no URL prefix; panel locale uses the cp_locale cookie.

Atomic .tmp + rename() Writes

TranslationManager writes YAML to a .tmp-* file first, then atomically replaces the target with an OS-level rename(). Even a power cut cannot leave a half-written translation file.

LocaleSwitchService::urlFor()
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);
}
TranslationManager — atomic write
$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);

Security and Performance Principles

Security and performance are not a finishing polish added at the end of a project; they are the system's fundamental building blocks.

Capability-Based Access Control (CBAC)

Dynamically generated capabilities are checked instead of relying on the standard ROLE_ADMIN approach. Role names are never checked anywhere in the code.

denyAccessUnlessGranted('system.module.manage')

Roles = Config (YAML): Travel with Git.
Users = Content (DB): Never exported.

SaaS Tenant Leak Protection

The biggest security risk in multi-tenant (SaaS) systems is a developer forgetting to write WHERE tenant_id = ?.

In CPalius, this possibility has been eliminated at the platform level. Doctrine SQLFilter automatically injects a tenant constraint into every query. No developer intervention is required.

N+1 Query Guard

A Doctrine Listener that blocks N+1 query errors — one of the most common causes of database slowness — and triggers in development.

If the query count for the same table exceeds the limit in one HTTP request, MaxQueriesExceededException is thrown. Developers cannot ship until the error is fixed locally.

Voter-to-SQL Transformation

QueryScopeApplier eliminates PHP-based Voter checks on list screens (and the N+1 memory crisis they cause).

A user's .own or .any capabilities are converted into SQL WHERE conditions on the Doctrine QueryBuilder before the query ever hits the database.

Zero-Trust Payload Validation

A strict-type DTO (Data Transfer Object) architecture that trusts no HTTP payload from the outside world. Data is autonomously sterilized with Symfony Validator before it reaches controllers.

Malicious manipulation attempts are rejected immediately, protecting core integrity with "Golden Ratio" precision.

Lock-Free High Concurrency

An Optimistic Locking backbone that relegates traditional table-lock crises to history. Thousands of concurrent data mutations are isolated with atomic transactions without deadlocks.

Stripped of complexity through the YAGNI philosophy, this infrastructure defers server bottlenecks to pure hardware limits.

Technical Manifesto

Five foundational architectural principles and deep code-level features that form the enterprise backbone of CPalius CMF.

Block 1: Hybrid Data Architecture and Flat-Field Index Engine

Two-Class Entity and JSON-Relational Hybrid Structure: Completely rejecting the cumbersome EAV (Entity-Attribute-Value) model of traditional CMS platforms, CPalius manages fields in two separate classes. Business records (#[CpResource]) live in strict-typed SQL columns, while content records (Node) store all dynamic data in a single JSON column for flexibility.

Performance Genius (Flat-Field Index Engine): Because searching JSON columns with WHERE conditions is slow, CPalius uses an autonomous Doctrine Event Listener-based flattening engine. Fields marked queryable: true are reflected into the node_field_index table. The ProcessWire-inspired findNodesBySelector API simplifies complex queries.

// Super-fluent Selector API usage
$nodes = $nodeRepository->findNodesBySelector(
    'type=post, status=published, is_featured=1, limit=5, sort=createdAt:desc'
);

// Flat-Field engine snippet running in the background
// The dynamic 'is_featured' field from JSON is JOINed at high speed
// via 'value_int' in the index table.

Block 2: Military-Grade Isolation and Sandbox Layer

Core Never Dies (Unbreakable Core): A massive isolation layer sits between the user space (cp-content/modules) and the core (cp-core). A faulty third-party module cannot crash the entire application.

Quarantine Armor and Emergency Valve: When a module is activated, lint:container and lint:yaml tests run in an isolated subprocess via symfony/process. At runtime, entry points are armored with try/catch. A crashing module is immediately ignored and written to module_quarantine.log.

// Real-time quarantine isolation in ApiGatewayController
try {
    $service = $this->serviceLocator->get($serviceId);
    $result = $service->$methodName($request, ...$endpoint['pathParameters']);

    return $result instanceof JsonResponse ? $result : new JsonResponse($result);
} catch (\Throwable $e) {
    // A crashing module never takes the whole system down with a 500.
    // It is isolated, logged, and the Gateway keeps running.
    $this->quarantineApiFailure($serviceId, $methodName, $e);

    return new JsonResponse(['error' => 'Internal API Error'], 500);
}

Block 3: Deep-Localization and Dynamic Compiler-Pass

Enterprise Multilingual Topology: Language support is part of the core. Each piece of content is produced as a vertical table row (Node) and linked via a translationGroupId UUID. It is physically protected at the DB layer.

Plug-and-Play Translation Compilation: Modules keep their own translations in their own directories. TranslationFileLocator finds them and injects them into the framework.translator.paths array via a Symfony Compiler Pass. Translations are written to disk with an atomic write algorithm.

// Atomic file-write guarantee inside TranslationManager
$dir = dirname($filePath);
if (!is_dir($dir)) {
    $this->filesystem->mkdir($dir);
}

// 1. First write safely to a temporary .tmp file
$yaml = Yaml::dump($data, 2, 2);
$tmpPath = $filePath . '.tmp-' . bin2hex(random_bytes(4));
$this->filesystem->dumpFile($tmpPath, $yaml);

// 2. Atomically replace the target via OS-level rename().
// Even if power is cut, the file can never be left half-written.
$this->filesystem->rename($tmpPath, $filePath, true);

Block 4: Hybrid Automation and Cron Engine

Unified Cron Infrastructure: Legacy database crons meet modern architecture. Virtual jobs can be created with the #[CpCronJob] attribute, or via Hooks/cron.*.php files.

Isolated Triggering and System Oversight: CronManager runs jobs as isolated subprocesses (Process) to prevent memory leaks. Administrators can live-monitor jobs from the /aacp/cron cyber-console and trigger them with "Run Now" AJAX signals.

// cp-content/modules/Blog/Cron/PublishScheduledPostsTask.php
final class PublishScheduledPostsTask
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly NodeRepository $nodeRepository,
    ) {}

    // Pure attribute-based cron registration — no DB record required
    #[CpCronJob(schedule: '*/5 * * * *', name: 'blog.publish_scheduled')]
    public function execute(): string
    {
        $dueNodes = $this->nodeRepository->findDueScheduledNodes();

        if ($dueNodes === []) {
            return 'No content due for publication.';
        }

        foreach ($dueNodes as $node) {
            $node->publish($node->getPublishedAt());
        }
        $this->entityManager->flush();

        return sprintf('%d content items published.', count($dueNodes));
    }
}

Block 5: Modular REST API and Security Gateway

An End to Routing Chaos: Instead of routing files, module developers open endpoints by placing a #[CpApi] attribute on the method. Everything is managed centrally through ApiGatewayController.

Cryptographic Security Backbone: The X-CP-API-KEY header is checked via cp_settings. ApiKeyService performs SHA-256 verification with the timing-attack-safe hash_equals function.

// 1. A clean endpoint inside the module
#[CpApi(path: '/blog/posts', methods: ['GET'], public: false)]
public function getPosts(Request $request): JsonResponse
{
    // Business logic...
}

// 2. Fail-closed armor in ApiGatewayController
// On public:false routes, a missing API key means the target
// method is NEVER called.
if (!$endpoint['definition']['public'] && !$this->hasValidApiKey($request)) {
    return new JsonResponse(['error' => 'Unauthorized'], Response::HTTP_UNAUTHORIZED);
}
0
Defense Lines
0
N+1 Query Tolerance
0
Extension Layers
Module Capacity
0
Open Source

Future Roadmap

Of the items promised in the first whitepaper, Safe Mode, the on-demand image pipeline, and the audit log are complete. The following systems will be built in upcoming development sprints.

Sprint 1

Workflow & State Machine

A mechanism that manages transitions for business records such as invoices, vehicles, and reservations (draft → preparation → sold) through YAML definitions and connects each transition to an automatic audit log. The CpResource::$workflow field is already declared — the next step is wiring the real transition/guard engine.

Sprint 2 — Done

On-Demand Image Pipeline

Shipped. ImageProcessor (GD) resizes/crops on demand and caches under public/uploads/cache/; the cp_thumb Twig filter exposes it to every theme.

Sprint 3 — Done

#[CpResource] Audit Log

Shipped. The cp_audit_logs table and an isolated onFlush/postFlush listener record every create/update/delete of an auditable entity. Marking any entity #[Auditable] switches it on.

Sprint 4

Messenger Async Queue

symfony/messenger is installed and visible in the AACP System Monitor; the next step is wiring a real transport (Doctrine/Redis) and moving email and notification work onto an asynchronous queue.

Roadmap

Let's Perfect the Architecture Together

CPalius will become a stronger application framework through the power of its community. We look forward to your ideas, feedback, and architectural suggestions.