winter/base
Winter/base is the core foundation package of Winter CMS, a free, open-source Laravel-based content management system. It provides the essential modules, helpers, and framework glue that power the platform, giving developers a solid base for building fast, extensible websites and applications.
Architecture fit. winter/base is not a library you composer require into an existing application — it is the application skeleton for Winter CMS, a full self-hosted CMS built on Laravel. That distinction drives the whole evaluation. The package decomposes into three layers: Winter core (modules/backend, modules/cms, modules/system), Winter Storm (vendor/winter/storm, the genuinely reusable primitives — filesystem, path resolution, class loading, Halcyon file-based config, asset pipeline), and Laravel/Symfony underneath. Only Storm is realistically consumable à la carte. Core is a monolith that owns routing, the admin backend, the Twig theme engine, media management, plugin lifecycle, and the asset pipeline. If the requirement is "a Laravel app with a content model," Winter is heavier than needed; if the requirement is "a self-hosted CMS our team can extend in PHP," it is a coherent fit.
Integration feasibility. Three viable modes, in ascending risk:
composer create-project wintercms/winter, run alongside existing systems, integrate via HTTP/API or a shared database view. Lowest risk, cleanest boundary.Author\Plugin packages against the documented extension points (backend form widgets, CMS components, Twig tags, console commands). This is the supported extension path and the one most integrations should take.themes_path(), plugins_path(), media_path(), temp_path()) and its own ClassLoader, which will collide with or shadow a host application's assumptions. Two Laravel boots in one process is a debugging tax with no upside.The Dependents: 0 figure should not be read as an adoption signal — the package is a project template, so Composer's dependent graph is structurally near-empty. Judge adoption by the plugin ecosystem and community size instead, and note that 1.5k stars is modest relative to October CMS, Drupal, or WordPress; this is a smaller ecosystem with correspondingly thinner third-party coverage.
Technical risk. Ranked:
ClassLoader lowercases directory segments to derive paths (System\Twig\Node → modules/system/twig/node/). This breaks PSR-4 mental models, trips static analysis and IDE indexing, and manifests as case-sensitivity failures that pass on macOS/Windows and fail only on Linux CI. Any team onboarding cost estimate should include this.public/ via winter:mirror public --relative. Skipping it produces 404s that browsers ORB-block into text/html, so JavaScript-driven backend UIs render blank with no console error. This is a genuinely expensive failure mode to diagnose cold.agents/AGENTS.md is contributor-grade and excellent; it also reveals that a meaningful portion of operational knowledge (mirroring, Vite workspace resolution, symlink handling) lives in contributor docs rather than consumer docs.Key questions for the team.
Verdict. Conditional go. Viable as a standalone, plugin-extended CMS for a team already fluent in Laravel. Not viable as an embedded dependency or as a "just add content" layer. The score of ~51/100 is consistent with that reading: decent architecture, real integration friction, materially underweight ecosystem.
Stack fit. PHP 8.x, Laravel, MySQL/Postgres/SQLite, Twig for front-end themes, a Vue-based admin backend, and three supported asset pipelines (Laravel Mix, Vite, and a legacy path). Composer for dependency management, php artisan for operations (winter:up, winter:mirror, winter:version). Fit is good for shops already on Laravel + Twig; poor for shops standardized on Node/Next or on a different PHP framework. If the broader platform is Python or Node, Winter becomes an isolated subsystem that must be operated by someone — account for that as a permanent, non-trivial ownership line.
Migration path. Greenfield first. For a brownfield move (WordPress, October, Drupal), plan on a bespoke importer writing through Winter's models rather than a SQL-level migration; the schema is Winter-specific and Halcyon-backed configuration lives in files, so a database-only cutover will produce a subtly broken site. Sequence content migration after the theme and plugin work is proven, and run it against a staging copy at least twice.
Compatibility. Two hard constraints:
plugins/<author>/<name> with Author\Plugin namespaces resolved by Storm's ClassLoader, not PSR-4. New sub-namespace directories must be lowercase on disk. Enforce this in review and in CI, or you will ship Linux-only failures.public/ docroot, and winter:mirror must be part of the deploy step, not a one-time setup task. Make it idempotent in the pipeline.Sequencing.
phpcs against changed files (the upstream CI does exactly this and fails the whole PR on style), plus phpunit with System\Tests\Bootstrap\PluginTestCase. Add a guard that fails on capitalized namespace directories.Do not parallelize steps 1–3 with content migration. The most common way this integration fails is committing content before the plugin boundary is validated.
Maintenance. Two repositories to track — Winter core and Winter Storm — with changes occasionally spanning both and the core's composer.json constraint waiting on a Storm tag. Pin exact versions; upgrade deliberately, not on composer update. Budget roughly 10–15% of one engineer's time for version tracking, security patches, and plugin upkeep, rising during Laravel major transitions. PHPCS is fast (~15s) and non-negotiable in CI; skipping it costs a round-trip per PR.
Support. Community channels (GitHub, Discord) with no commercial SLA behind winter/base itself. There is no equivalent of October's commercial backing to lean on. This must be internalized as an ownership cost, not a procurement line item: name a primary and a secondary maintainer, and treat the ability to read Winter core source as a hiring/assignment constraint.
Scaling. Inherits Laravel's story — horizontal app servers behind a load balancer, Redis for cache/session/queue, standard DB replication. Two Winter-specific caveats:
Failure modes (each has a known signature — capture these in the runbook):
winter:mirror → assets 404 → browser ORB-block → blank backend UI with a clean console. Check the network tab before suspecting code.Class not found on Linux only, green on Windows/macOS CI. Symptom: every Ubuntu job fails identically.vendor/ (especially Storm) → a failing test that will not reproduce on a fresh clone. Fix by updating Storm before declaring an environment issue.node_modules resolves from the symlink's real path and misses the project install. Requires a gitignored symlink bridge.vite:watch on an IPv6 host → writes an unreachable http://[::]:5173 hot file, backend serves unstyled. Fix with echo -n 'http://localhost:5173' > assets/dist/hot; verify the hot file is removed when the watcher stops.base_path() → asset package registration silently skipped. Prefer PathResolver::within()/resolve() over hand-rolled prefix checks in any code you add here.base_path() → Assetic "source is not in the root directory" failures. Use storage/framework/cache/<unique> and clean up in tearDown().Ramp-up. A competent Laravel developer reaches productivity in roughly two to four weeks: one week on the plugin/module conventions and Storm's helper surface (the substitution tables are a genuinely good accelerator — most "small utilities" already exist at the Storm/Laravel/Symfony layers), one week on the backend form/widget system, one week on theming and the asset pipelines, and one week absorbing the sharp edges above. Full independent ownership — able to upgrade a Laravel major or debug a classloader failure unaided — is closer to two to three months. The AGENTS.md contributor guide materially compresses this, and should be required reading on day one rather than treated as internal upstream documentation.
How can I help you explore Laravel packages today?