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