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 — the landmine you will hit within a week.
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 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 |
| Translations | the NEON layer and the database layer |
| Tests and tooling | PHPUnit, PHPStan, pre-commit, skills |
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. - Every Api read empties the identity map. An object graph under construction loses its connection to the database and the next save fails.
- 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.
Production and development share one database
There is no "let me try it on dev first". Every write is live. Run experiments in a transaction with a rollback.
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.