Knowledge Base
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
Extending Convoro
Registries, widgets, search, and how modules avoid knowing about each other.
How do I make two modules work together?
Through a registry in System, not a direct reference. A module that names another cannot be installed without it, and fatals on a site where it is switched off.
Developers
How do I get my module's content into search?
Register a content type with a find callback that takes the viewer's group ids and filters by them. A find that ignores the viewer is a leak.
Developers
How do I make my content work with OpenSearch?
Add documents and gates callbacks to your content type. documents yields what to index; gates says which containers a viewer may read. Provide both or your type is skipped entirely.
Developers
How do I add a widget other people can place?
Register a widget type in register() with a render callback returning HTML. Filter by the viewer's groups inside it — a widget renders on pages you are not thinking about.
Developers
How do I let people comment on something my module owns?
Use the discussions service. It gives your record a hidden topic and reuses posts, so comments get editing, reporting, reactions and moderation without you building any of it.
Developers
How do I make my module honour account deletion?
Register your tables with the personal_data service in boot(). One line per table naming the column that points at a member.
Developers
What is the difference between a module and an extension?
A module ships with Convoro; an extension is a package somebody installs into extensions/. The code is the same shape — the console can scaffold and package one for you.
Developers