Skip to main content

Documentation

No results found.
Features

Modern Stack

WebProCMS is built on a deliberately small, modern stack: Laravel 13 on the server, Livewire 4 for reactive UI, Alpine 3 for in-browser interactivity, Flux 2 for dashboard components, and Tailwind 4 for styling. There is no React, no Vue, n...

WebProCMS is built on a deliberately small, modern stack: Laravel 13 on the server, Livewire 4 for reactive UI, Alpine 3 for in-browser interactivity, Flux 2 for dashboard components, and Tailwind 4 for styling. There is no React, no Vue, no separate front-end build pipeline to babysit, and no API layer stitched between a JavaScript SPA and the database. The whole application is one codebase, in one language, with one mental model.


The stack at a glance

Layer Technology Role
Language PHP 8.4+ Single language for the entire application
Framework Laravel 13 Routing, ORM, queues, auth, the lot
Reactive UI Livewire 4 Server-rendered components that update over the wire
Browser interactivity Alpine 3 Lightweight client-side behavior, no build step
Dashboard components Flux 2 Buttons, modals, forms, tables for the admin UI
Styling Tailwind 4 Utility-first CSS, JIT-compiled
Auth Fortify 1 Login, registration, 2FA, password reset

That's it. A developer who knows PHP and a little HTML can be productive across every layer of the application on day one.

The problem with the typical "modern" CMS stack

The industry default for an ambitious CMS or web app in 2026 is a split-brain architecture: a JavaScript SPA (React/Next, Vue/Nuxt) talking to a separate backend API. That design carries costs that compound over the life of a project:

  1. Two languages, two codebases, two skill sets. Business logic gets duplicated — validation rules live once in the API and again in the client; types are defined on the server and re-declared in TypeScript. Every feature touches both halves, and the two halves drift.
  2. A heavy build pipeline you have to maintain forever. Bundlers, transpilers, polyfills, hydration, code-splitting config. The tooling needs upgrading on its own schedule, breaks on its own schedule, and is the part of the project most likely to be broken on a fresh git clone.
  3. Hiring gets harder and more expensive. You're no longer hiring "a web developer." You're hiring someone fluent in React and the backend framework and the API contract between them. The pool is smaller and the salaries are higher.
  4. State lives in two places and has to be kept in sync. The server has the truth; the client has a copy; an API sits between them marshalling JSON back and forth. A large fraction of SPA bugs are synchronization bugs — the client showing something the server no longer believes.

None of this is necessary for the vast majority of websites and web applications. It's accidental complexity that the industry has normalized.

The fix: server-first, with islands of interactivity

WebProCMS keeps state on the server and ships HTML to the browser. Livewire makes that interactive without a SPA, and Alpine handles the small client-side touches that don't need a server round-trip. The result is a reactive, modern-feeling application with a fraction of the moving parts.

Livewire: reactive UI written entirely in PHP

A Livewire component is a PHP class (or a Volt single-file component) plus a Blade view. The properties are PHP properties; the actions are PHP methods; validation is Laravel validation. When a user interacts with the page, Livewire sends the change to the server, re-runs the component, and patches just the changed HTML back into the DOM — no full page reload, no hand-written fetch calls, no JSON contract to design and version.

// A complete, reactive search box. No JavaScript, no API endpoint.
$query = '';

with(fn () => ['results' => Post::search($this->query)->get()]);
<input type="search" wire:model.live="query" placeholder="Search posts…">
@foreach ($results as $post)
    <a href="{{ route('blog.show', $post) }}">{{ $post->title }}</a>
@endforeach

That is the entire feature. The same person who wrote the Eloquent query wrote the UI, in the same file, in the same language. There is no separate front-end developer, no API route, and no client-side state to keep in sync — the server is the state.

What this unlocks:

  • PHP developers ship front-end features without writing JavaScript. Reactive forms, live validation, modals, tables, infinite scroll, drag-and-drop reordering — all expressed as PHP properties and methods plus wire: directives in Blade. The barrier to "I want this to update without a reload" is a one-line directive, not a new toolchain.
  • One source of truth. Validation rules, authorization, types, and business logic live once, on the server. There is no client-side copy to drift out of sync, because there is no client-side copy.
  • The whole app is debuggable with PHP tools. Stack traces, dd(), Xdebug, Laravel's exception page, the query log — they all work, because the logic that renders the page runs in PHP on the server. You're never bisecting a minified client bundle to find out why a button did the wrong thing.
  • Hiring is "do you know Laravel?" — not "do you know Laravel and React and the contract between them." The pool is larger and the onboarding is shorter.

Alpine: the right tool for the genuinely client-side parts

Some interactions shouldn't make a server round-trip at all — toggling a dropdown, opening a mobile menu, flipping an accordion, showing/hiding a password, tracking which tab is active. Sending those to the server would add latency for no benefit. That's exactly where Alpine fits, and where it beats reaching for a full JavaScript framework:

  • No build step. Alpine is a script tag's worth of behavior expressed as attributes directly in your HTML. There's no component to register, no bundle to rebuild, no JSX to compile. You write x-data, x-show, @click inline and it just works.
  • It reads like the HTML it enhances. Behavior lives next to the markup it controls, so you see what an element does without jumping to a separate .js file. For the small, local interactions Alpine is meant for, that co-location is far more maintainable than a component tree.
  • It's tiny and fast for its job. Alpine is purpose-built for sprinkling interactivity onto server-rendered HTML. There's no virtual DOM to diff, no hydration step, no framework runtime measured in hundreds of kilobytes — just the immediate, local reactivity the use case calls for.
  • It composes cleanly with Livewire. Livewire owns server state and anything that needs the database; Alpine owns ephemeral, in-browser UI state. The division is natural: if it needs data or persistence, it's Livewire; if it's purely visual and local, it's Alpine. You reach for the heavier tool (a server round-trip) only when you actually need the server.

The guiding principle: use the server for things the server should own, and use Alpine for things the browser should own. Most websites need a great deal of the former and only a little of the latter — which is exactly the balance this stack is tuned for.

Flux + Tailwind: a polished UI without a component library treadmill

The dashboard is built from Flux components (buttons, modals, forms, tables, date pickers) styled with Tailwind 4. Flux gives the admin UI a consistent, accessible baseline out of the box; Tailwind's utility-first, JIT-compiled approach means styling happens in the markup with no separate stylesheet to keep in sync and no unused CSS shipped to the browser. Both are first-party to the Livewire ecosystem, so they share the same conventions as everything else in the stack.

Why this matters for WebProCMS specifically

The stack isn't just an implementation detail — it's why WebProCMS can do things other CMSes can't:

  • File-based routing is possible because pages are real Laravel routes, not database rows behind a catch-all controller.
  • The page editor renders live previews by compiling the same Blade the public site uses — there's no separate React renderer to keep visually in sync with production.
  • AI-generated rows, the design library, and dynamic data binding all emit plain Blade + x-dl.* components, so what the editor produces is exactly what the server renders. No build step stands between "the AI generated this" and "the site shows this."
  • A single developer can own the entire product. Front-end, back-end, database, deploy — it's all PHP and Blade and a thin layer of Alpine. That's why the codebase stays small enough for one person to hold in their head.

Where this lives in the code

  • composer.json — pins Laravel, Livewire, Flux, and Fortify versions.
  • package.json — pins Alpine and Tailwind versions.
  • CLAUDE.md — the "Foundational Context" block lists every package and version the project is built against.
  • resources/js/ — the minimal JavaScript layer: Alpine registration and a handful of editor/public entry points. Note how little there is.
  • resources/views/pages/ — the public site, rendered as Volt + Blade. No JavaScript framework in sight.

For the editor's specific architecture — the three layers of Alpine store, page-editor Livewire component, and small modal children — see editor-architecture.md.