For developers#
Documentation of the CoolCMS architecture — for whoever is going to extend the system.
Where to start#
If you are reading this for the first time, go through it in this order:
- Five-layer model — without it the rest makes no sense.
- Project structure — where things belong.
- Code conventions — what a file you write should look like.
- Manager lifecycle — where side effects belong.
- Identity map — when an entity is still managed and when it is detached.
I want to…#
| Task | Chapter |
|---|---|
| a new presenter in the administration | Admin presenter |
| a new listing with filters and sorting | Working with tables |
| a form | Forms |
| pick from thousands of items instead of a select | Picker |
| a component | Components |
| an entity and a manager | Code conventions |
| a recount or a notification after saving | Manager lifecycle |
| a new API endpoint | Calling the API + RBAC in the API |
| a scheduled task | Cron presenters |
| an email | Sending emails |
| a new front-end URL | Routing |
| to add a text or a language | Translations |
| to speed up reads | Cache |
| to allow an action only to the owner or receiver of a record | Conditional roles |
| an email link that works without signing in | A link with a key |
| to connect a third-party service (a key in the administration) | External connections |
to keep robots from actions, a sitemap, robots.txt |
Robots and sitemaps |
| to wire content into search | Elasticsearch |
| to change the appearance | Front-end themes → SCSS |
| to deploy onto an older database | Database check |
Sections#
| Section | Contents |
|---|---|
| Introduction | layers, structure, conventions, installation, deployment, scheduled tasks |
| Core | calling the API, cache, routing, hooks, hydrators, the identity map, column attributes, filters, emails, Elasticsearch |
| UI | the admin presenter, DataGrid, Picker, forms, components, Latte, cron |
| Security | authentication, RBAC, CORS and rate limiting, audit |
| Appearance | themes, SCSS, the design system |
| Modules | e-shop, warehouse, invoicing, classifieds, company catalogue, blog, discussion, private messages |
| Translations | the NEON layer and the database layer |
| Tests and tooling | PHPUnit, PHPStan, pre-commit, skills |
| API reference | classes and methods generated from docblocks (phpDocumentor), online only |
Six things you have to know#
- The five-layer model. Presenter → Manager → Service → Mapper → Repository. SQL lives exclusively in the repository.
- The front end does not touch the database. It calls the Api section through the bridge — which is why the same module has two sets of entities and what flows between them is an array, not an object.
- There are two hydrators.
OrmEntityHydratoron the Api side (built on Doctrine),EntityHydratoron the Front/Admin side (reflection and attributes only). Do not mix them up. - An entity does not cross an operation boundary. The identity map is not emptied on reads but at the start and end of an operation (one Api call, a Cron action, a script step) and after a rejected save. An entity held across that boundary is detached and saving it fails; values and IDs leave an operation, not entities. In detail: Identity map.
- Side effects belong in the manager's hooks, not in database triggers — and only the
reversible ones belong in
after*. - Saving an object graph replaces, it does not append. Whatever is missing from the payload gets deleted.
Do not develop against the production database
Development and experiments belong on your own copy of the database, not on the data of a running site. Try bulk data changes in a transaction with a rollback first.
The skills are binding, the manual is the explanation
The canonical way to write code lives in skills/ — this manual turns them into a
guide with the reasoning behind them. When the two diverge, the skill wins.