myproject/
├── .github/workflows/ # CI: lint on push, release zip on v*.*.* tags
├── assets/ # public static assets used by the default pages (css/js/img)
├── docs/ # documentation (this folder)
├── lf-app/ # application code — controllers, models, pipelines, jobs, ...
├── lf-boot/app.php # bootstrap, run before every request and every CLI command
├── lf-config/ # config files, one PHP array per file
├── lf-hooks/ # hook files — every *.php here is loaded at boot
├── lf-inc/const.php # DEBUG, MEMORY_LIMIT, CLI_MEMORY_LIMIT
├── lf-lang/ # language files (en.local.php, ...)
├── lf-logs/ # error logs, written only while DEBUG is true
├── lf-routes/ # route files — every *.php here is loaded on dispatch
├── lf-storage/ # generated runtime state (see below) — never served
├── template/ # Twig views, template/assets/, template/loader.php
├── uploads/ # user-uploaded files
├── vendor/ # Composer dependencies
├── public/ # the web server's document root
│ ├── index.php # the web entry point
│ └── .htaccess # Apache rewrite rules (generated by app:sync if missing)
├── .htaccess # deny-all, in case a vhost points at the project root
├── composer.json
├── laika # CLI executable (generated)
├── worker # queue worker executable (generated)
├── nginx.conf # nginx rules fragment, for your own server block (nginx:make)
├── LICENSE
└── README.md
lf-app/ — Application CodeEvery subdirectory maps to a PSR-4 namespace under App\, and each is a resource the framework discovers on its own — there is nothing to register.
| Directory | Namespace | Contains | Must extend / implement |
|---|---|---|---|
Controller/ |
App\Controller |
Route handlers | — |
Model/ |
App\Model |
Database models | Laika\Engine\Model\Model |
Schema/ |
App\Schema |
Table definitions, run by php laika app:migrate |
Laika\Engine\Model\Contract\SchemaAbstract |
Pipeline/ |
App\Pipeline |
Middleware that runs before the controller | Laika\Engine\Route\Contracts\PipelineInterface |
Filter/ |
App\Filter |
Middleware that runs after the controller | Laika\Engine\Route\Contracts\FilterInterface |
Job/ |
App\Job |
Queue jobs | Laika\Engine\Queue\Abstracts\Job |
Command/ |
App\Command |
Your own php laika commands |
Laika\Engine\Cli\Contracts\CommandInterface |
Relay/ |
App\Relay |
Relay providers — bind services into the container | Laika\Engine\Relay\RelayProvider |
Service/ |
App\Service |
Relay classes — the static proxies your code calls | Laika\Engine\Relay\Relay |
All of these can be scaffolded with the CLI — see CLI Reference.
lf-storage/ — Runtime StateEverything under lf-storage/ is created by the framework. It is git-ignored, the front controller never serves it, and app:sync drops a Deny from all .htaccess into it.
| Path | Holds |
|---|---|
keys/app.key |
The application secret — encryption, CSRF, JWT all derive from it |
cache/template/ |
Compiled Twig templates |
cache/resources.php |
The compiled resource manifest (used when DEBUG is false) |
queues/jobs.json, queues/failed.json |
The json queue driver |
json/ |
JsonStorage documents |
files/ |
LocalStorage’s default root |
sessions/ |
File sessions, if you point Init::file(['path' => ...]) here |
php laika app:sync deletes the contents of lf-storage/cache/ (templates included) and rebuilds the resource manifest.
lf-boot/app.php — the bootstrap sequence. Not meant to be edited. See Request Lifecycle.lf-config/ — one file per config domain, each returning a PHP array. See Configuration.lf-hooks/ — plain PHP files, loaded recursively at boot, before routing. Register hooks here and put code that must run on every request: session driver, CORS, timezone. See Hooks.lf-routes/ — plain PHP files that call Laika\Engine\Route\Url::get() and friends. They’re loaded when a request is dispatched, not at boot. See Routing.lf-logs/ — {Y}-{Mon}-{d}-error.log files. The error handler writes them only when DEBUG is true. See Errors & Logging.template/ — Twig views rendered via Laika\Engine\App\Template, the template’s own assets/, and loader.php for enqueueing styles and scripts. See Templates.uploads/ — user files. Served like any other directory, except that markup types (html, svg, xml) are refused there. See lf-config/assets.php.| File | Runs |
|---|---|
public/index.php |
Every web request: loads lf-boot/app.php, then calls Laika\Engine\Route\Url::dispatch() |
laika |
php laika <command> — the CLI, generated by laikait/laika-engine |
worker |
php worker [queue] — the queue worker, generated by laikait/laika-engine |
public/.htaccess / nginx.conf |
Rewrite every request to public/index.php. See Deployment |
The skeleton’s .gitignore already excludes vendor/, lf-logs/, lf-storage/, composer.lock, laika, worker and .htaccess — all of them are generated.
The web server user (and the user that runs php laika / php worker) must be able to write:
lf-storage/lf-logs/uploads/