How Convoro is built
The engine, the module system, and the ideas everything else follows.
How is Convoro organised?
engine/ is the framework, modules/ holds System and the applications, themes/ holds templates and assets, and public/ is the only directory a web server needs to see. There is no vendor directory and no build output.
Developers
How do I create a new module?
A directory under modules/ with a manifest.json and a class named after it extending Module, with register() and boot(). Routes, migrations, services and templates are found by convention from there.
Developers
What is the difference between register and boot in a module?
register() binds services and registers into registries; boot() does work that may depend on other modules. Every module registers before any module boots, which is why widget areas must be registered in register().
Developers
How do I add a database table or column?
Add a dated file to your module's Migrations/ returning an anonymous class extending Migration with up() and down(). Run php tools/convoro migrate. Make it re-runnable — check before you alter.
Developers
How do I add a page to Convoro?
Put it in your module's Routes/front.php or Routes/admin.php. Register literal paths before patterns, or a slug will shadow them.
Developers
What is the .cvr template syntax?
Templates are .cvr files compiled to PHP. {{ }} escapes, {! !} does not, and the directives are @layout, @section, @yield, @if, @each, @empty, @notempty, @include, @php, @hook, @csrf and @asset.
Developers
How do I use the database or another service in my code?
Everything is in the container. $this->app->make('db') for the query builder, and the same for anything a module bound in register(). Bind your own with $this->app->singleton().
Developers
How do I make my module's content respect permissions?
Add a <thing>_groups table, check the viewer's group ids against it in your service, and add the table to Groups::RESTRICTION_TABLES. Enforce it in the service, never in a template.
Developers
How should my module accept a file upload?
Sniff the type from the bytes, never the filename or Content-Type; store outside the document root and serve through a controller; and add the path to the nginx list or it will 404 only in production.
Developers
How do I run and write tests?
php tests/run.php, optionally with a filter. A test file returns an array of name => callable and passes if it does not throw. Clean up what you create, in a finally.
Developers