Real-estate CMS. Built with Laravel and Vue.

A CMS for a property consultancy. Block editor, listings, pages, blog, SEO. The demo runs as the fictional “Best Real Estate Consultant In Your City™”.

Live demo (opens in a new tab) Admin at /login: demo@example.com / password. Resets nightly.

Stack
Laravel 13, Inertia, Vue, Octane/FrankenPHP, Postgres
Results
231 automated tests. 22 domain models, running in production. Atomic release switches. No downtime.

Problem

Small real-estate businesses publish a lot of near-identical content: listings, area guides, blog posts. Site builders are slow to write in, poor for search, and take nothing from your own scripts.

The brief: a CMS the business runs day to day, that ranks, and that accepts drafts from elsewhere, including AI.

Built

  • Data model: 22 domain models behind listings, pages and blog.
  • Authoring: Editor.js. Content is stored as structured blocks and renders the same on every public page.
  • SEO: meta and JSON-LD on public pages.
  • Import API: scripts push AI-written posts, pages and listings. They land as drafts for review.
  • Zero-downtime deploys: release directories, atomic symlink switch.

Decisions

Inertia instead of a separate SPA and API
The admin is Vue. Routing, validation and auth stay in Laravel. One codebase, one deploy, no duplicated form rules. The import API is the only public JSON surface.
Structured blocks, not HTML
Editor.js stores JSON blocks. Rendering stays predictable, the import API can validate before saving, and AI drafts cannot inject arbitrary markup.
Octane on FrankenPHP
The app stays booted between requests. Public pages are fast with no page cache to invalidate on every save.
Drafts first for anything imported
Nothing from the API goes live on its own. Scripts create and update drafts. A person publishes.

Next time

Write the import API contract first, as a schema, and generate validation from it. It grew alongside the scripts that call it.

Add visual regression tests for public templates earlier. Unit and feature tests catch logic errors, not a broken layout.

chetan@chetan.cloud