# Architecture **Analysis Date:** 2026-02-04 ## Pattern Overview **Overall:** Modular Layer-based MVC with Plugin System WinterCMS implements a **three-layer modular architecture** consisting of Core Modules (System, Backend, CMS) that form the framework foundation, with a Plugin system overlaid for extensibility. The framework uses Laravel 9.x as its base, with Winter's Storm library acting as a compatibility buffer. **Key Characteristics:** - Laravel-based HTTP kernel with module-level routing - CMS-first approach: frontend pages route through CMS module, backend admin routes through Backend module - Plugin dependency resolution with automatic component/controller/model discovery - Extensibility through plugin interdependencies and event-driven architecture - YAML/JSON configuration for models, forms, lists, and behaviors - Static theme system with file-based page, layout, and partial management ## Layers **Core Modules (modules/ directory):** - **System Module:** Base framework, plugin management, mail system, asset handling, error management - **Backend Module:** Admin interface, form/list widgets, user role management, controller behaviors - **CMS Module:** Frontend page rendering, theme management, component system, layout composition **Plugin Layer (plugins/ directory):** - Vendor-namespaced plugins (winter/, golem15/) - Each plugin extends and integrates with core modules - Plugin dependencies declared via `$require` arrays in Plugin.php - Core plugins: Apparatus (DI/scenarios), User (auth), PaymentGateway (commerce) - Domain plugins: Blog, Menu, Translate, AI, Chat, etc. **Frontend/Theme Layer (themes/ directory):** - Static theme files organized in theme directories - Pages, layouts, partials stored as .htm files with Twig syntax - Assets (CSS, JS, images) co-located with pages/layouts - URL routing to pages via Theme manager and CMS controller ## Data Flow **Frontend Request (Page View):** 1. HTTP request to any URL arrives at `index.php` 2. Bootstrap loads application (`bootstrap/app.php`) 3. HTTP Kernel processes request through middleware 4. Laravel Router evaluates all registered routes 5. Backend/System routes handled by their controllers 6. CMS module catch-all route `{slug?}` routes to `Cms\Classes\CmsController@run()` 7. CMS Controller delegates to `Cms\Classes\Controller` (primary frontend controller) 8. Primary Controller: - Looks up URL in Theme using `Cms\Classes\Router` - Resolves Page, Layout, and Component objects from theme files - Renders page through Twig template engine - Components injected into page output via ComponentManager 9. Response sent back to client **Backend Request (Admin Interface):** 1. HTTP request to `/backend/...` arrives 2. Backend Router matches `Backend\Classes\BackendController@run()` 3. BackendController parses remaining URL segments to determine target plugin/controller 4. Controller loaded from plugin (e.g., `Golem15\Blog\Controllers\Posts`) 5. Controller action determined by remaining URL parts 6. Behaviors attached (FormController, ListController, etc.) handle CRUD operations 7. Views rendered with form/list widgets 8. JSON/HTML response returned **Component Lifecycle:** 1. Page YAML/Twig specifies component code (`{% component 'componentName' %}`) 2. ComponentManager resolves code to fully-qualified class name via codeMap 3. Component class instantiated with properties from page markup 4. Component's `onRun()` method called by page renderer 5. Component renders its partial template (HTM file) in page context 6. AJAX handlers on component (e.g., `onUpdateCart`) handled by Snowboard framework **State Management:** - Models: Database-backed via Winter\Storm\Database\Model (extends Laravel Eloquent) - Sessions: Laravel session middleware, stored in `storage/framework/sessions/` - Cache: Laravel cache (configurable drivers: file, redis, memcached) - Parameters: System\Models\Parameter table for application-level configuration - Translation: Text keys cached in parameters, loaded by Translate plugin ## Key Abstractions **Plugin Architecture:** Purpose: Enables modular, independently-deployable features with dependency resolution - Each plugin is a Laravel ServiceProvider extending `System\Classes\PluginBase` - Plugin.php declares: `pluginDetails()`, `register()`, `boot()`, `registerComponents()`, `registerControllers()`, etc. - Examples: `golem15-wintercms-starter/plugins/golem15/blog/Plugin.php`, `golem15-wintercms-starter/plugins/golem15/user/Plugin.php` - Pattern: Plugins register services, components, controllers, and extend existing models **Component System:** Purpose: Reusable, composable page elements with their own controllers and views - Components extend `Cms\Classes\ComponentBase` - Register in plugin via `registerComponents()` returning [ClassName => 'code'] - ComponentManager loads all registered components into codeMap - Example: `golem15-wintercms-starter/modules/cms/components/SoftComponent.php` - Pattern: Component renders partial, handles AJAX, injects CSS/JS **Theme/Page System:** Purpose: File-based, non-database-backed content management - Theme directory contains pages/, layouts/, partials/ subdirectories - Page class `Cms\Classes\Page` extends `CmsCompoundObject` - represents page file as object - Page file format: URL metadata → YAML → Twig markup - Page references layout (inherited structure) and components (functional blocks) - Example page structure: `themes/demo/pages/home.htm` - Pattern: Page objects loaded on-demand from disk, cached in memory **Backend Form/List System:** Purpose: YAML-driven admin CRUD interfaces - Controllers use FormController and ListController behaviors - forms.yaml/fields.yaml define form structure and validation - lists.yaml/columns.yaml define table columns and filtering - FormController handles create/read/update/delete operations - Example files: `plugins/*/models/*/fields.yaml`, `plugins/*/models/*/columns.yaml` - Pattern: Behaviors parse YAML and generate HTML forms/tables dynamically **Service Providers & Dependency Injection:** Purpose: Central registration of services and extensibility hooks - Plugins register services in `register()` and `boot()` methods - Services bound to Laravel's DI container via `$this->app->singleton()` - Example: Apparatus framework registers DI container for component auto-wiring - Pattern: Late binding allows plugin A to extend plugin B's services ## Entry Points **Frontend (CMS Page Serving):** - Location: `golem15-wintercms-starter/modules/cms/classes/CmsController.php` (HTTP entry), `golem15-wintercms-starter/modules/cms/classes/Controller.php` (business logic) - Triggers: Any URL not matching backend or other routes - Responsibilities: - Routes URL to page via Theme manager - Loads Page, Layout, and Components - Renders through Twig with component injection - Returns HTML response **Backend (Admin Interface):** - Location: `golem15-wintercms-starter/modules/backend/classes/BackendController.php` - Triggers: URLs prefixed with `/backend/` - Responsibilities: - Parses plugin.controller.action URL pattern - Instantiates controller from plugin - Applies middleware and behaviors - Routes to controller action - Renders admin interface **System Initialization:** - Location: `golem15-wintercms-starter/bootstrap/app.php`, `golem15-wintercms-starter/index.php` - Triggers: Every HTTP request - Responsibilities: - Creates Laravel application instance - Binds kernel, console kernel, exception handler - Loads plugin manager and auto-discovers plugins - Registers module routes **CLI Commands:** - Location: `golem15-wintercms-starter/artisan` (entry point), `golem15-wintercms-starter/modules/*/console/` (command classes) - Triggers: `php artisan ` - Responsibilities: - Plugin scaffold commands - Database migrations - Asset management - Cache management - Payment gateway operations (via golem15/paymentgateway) ## Error Handling **Strategy:** Exception-driven with error page rendering **Patterns:** - All exceptions thrown as `SystemException`, `ApplicationException`, or Framework exceptions - HTTP exceptions converted to error pages by Exception Handler (`modules/system/classes/ErrorHandler.php`) - In production: Shows generic error page, logs details - In debug mode: Shows full stack trace and context - Model validation: Throws ApplicationException with validation messages - Frontend: 404 errors trigger Page not found response - Backend: 404 errors redirect to backend dashboard, show toast notifications ## Cross-Cutting Concerns **Logging:** - Uses Laravel's log facade (`Log::info()`, `Log::error()`) - Stored in `storage/logs/` - Configured in `config/app.php` and environment variables - EventLog model (`modules/system/models/EventLog.php`) tracks application events - RequestLog model tracks HTTP requests for debugging **Validation:** - Model-level via `$rules` property (Laravel validation rules) - Form widget validation via fields.yaml `validation` property - Backend behaviors apply validation before save - Errors returned as JSON validation responses in AJAX handlers **Authentication:** - Winter Backend: Database-backed user with role-based access control - Frontend API: JWT tokens (via golem15/user plugin) - Middleware: `Backend\Middleware\AuthenticateBackend`, `User\Middleware\JwtAuth` - Guards: `web` (session-based), `api` (JWT) ## Extensibility Mechanisms **Model Extension:** - Plugins extend models dynamically using `Model::extend(Closure)` - Example: `User::extend(function($model) { $model->hasMany['payments'] = ...; })` - Used for adding relationships, attributes, query scopes without modifying core **Event System:** - Global events via `Event::listen()` and `Event::fire()` - Module-level events: `system.route`, `cms.beforeRoute`, `cms.route`, `backend.beforeRoute` - Model events: `model.saveInternal`, `model.afterCreate`, `model.afterUpdate`, `model.afterDelete` - Custom events fired by plugins for extensibility **Behaviors:** - Controllers implement behaviors via `$implement` array - Backend behaviors: FormController, ListController, RelationController, ImportExportController - Each behavior adds methods (e.g., `create`, `update`, `index`) to controller - Example: `modules/backend/behaviors/FormController.php` --- *Architecture analysis: 2026-02-04*