Getting Started
Project layout, entry point, key ideas, and local development.
New here? Start with the Quickstart.
Key ideas
Pages are folders. A page lives at data/pages/{slug}/ and its URL is its folder path. Content is in data.json, structural metadata in index.json.
Views tie a page to its code. A page's view selects its template, router, controller and field declarations, all named after the view.
Hypermedia-first. Routes return HTML, not JSON. HTMX fetches fragments at clean URLs, so the URL pattern is the API.
Entry point
The web server's document root must be site/public/, whose index.php is the entry point:
<?php
// DOCUMENT_ROOT stays the logical path; __DIR__ resolves through a shared symlink on deploy
$public = $_SERVER['DOCUMENT_ROOT'];
require_once "{$public}/../../vendor/autoload.php";
Phlat::app(dirname($public))->execute();
Phlat::app() returns the singleton App for the project root. execute() resolves the URL to a page, runs the view's router and renders the response.
Directory structure
my-site/
phlat/ ← framework core (do not edit)
site/ ← your code and config
views/ ← templates, routers, and controllers (colocated per view)
fields/ ← global field definitions
fieldtypes/ ← custom field types
addons/ ← site-specific addons
public/ ← web document root
index.php
config.json ← site config, merged over phlat/config.json
data/ ← persistent state, survives redeploys
pages/ ← your content
users/ ← user accounts
git/ ← History's deploy key (gitignored)
storage/ ← registry, locks, rate limits (gitignored)
cache/ ← compiled views, thumbnails; delete any time (gitignored)
env.json ← deployment secrets and overrides (gitignored)
Config merges in order, later wins: phlat/config.json, site/config.json, data/env.json.
Creating pages
A page is a folder in data/pages/ with an index.json (holding a uuid) and a data.json. The root page is data/pages/ itself, served at /.
Create pages in the admin, with phlat make:page, or in code with $page->new($slug, $data). All three mint the uuid and write both files. A page made in the admin or with make:page is unpublished until you publish it; $page->new() publishes it unless $data says 'published' => false. See Publishing and access.
data/pages/
index.json ← root page
data.json ← renders at /
about/
index.json
data.json ← renders at /about/
blog/
index.json
data.json ← renders at /blog/
my-post/
index.json
data.json ← renders at /blog/my-post/
Local development
npm run watch # Tailwind watch, site theme
npm run watch:admin # Tailwind watch, admin theme
npm run sync # BrowserSync dev server
BrowserSync proxies the local server and reloads on template and content changes.