ECMS9 for developers
ECMS9 is a modular e-commerce platform built on CodeIgniter 4 (PHP 8+). This section describes how the system is put together and how to write modules for it.
Where to start
- Architecture — core, modules, themes, data.
- Module structure — what a module consists of and which contracts it must honor.
- Releases and updates — how a module version reaches users.
- Update server API — catalog, version and package endpoints.
- Render points — theme-independent storefront extension points for module widgets.
- Profiler — the admin-only debug toolbar on a live site.
Stack
| Layer | Technology |
|---|---|
| Framework | CodeIgniter 4 |
| PHP | 8.1+ (production target — 8.5) |
| Data access | CI4 Query Builder / CodeIgniter\Model for all new code; Propel (App\Propel\*, legacy) remains in older core code |
| Templates | Twig (admin panel and storefront themes) |
| Database | MariaDB / MySQL |
| Events | CodeIgniter\Events (extended hooks: shopMakeOrder, shopAdminOrderEdit, render points storefront_render_point:*, etc.) |
| Module registries | Config\ModuleExtensions + per-module Config/Registrar.php (menu items, CSRF/cache exemptions, job handlers, scheduled tasks, admin translations) |
| Background jobs | internal scheduler (App\Libraries\Scheduler, /admin/scheduler) — no hosting crontab needed |
Principles
- A module is a self-contained directory in
app/Modules/<Name>/with its own controllers, models, views, routes and commands. - The core never depends on modules: a disabled or missing module must
not break the system. Integrate via events,
Config/Registrar.phpcontributions and auto-discovery, not by hand-editing core configs. - No Propel in new code: new modules and new files use the CI4 Query Builder or models only, so the legacy ORM can be retired step by step.
- Theme compatibility: a module must not hard-depend on a specific theme; storefront widgets go through render points, and client-side code is wired up so it works with any theme.
- Self-provisioned schema: a module creates its own tables idempotently
(
CREATE TABLE IF NOT EXISTSininstall()/ensureSchema()); core schema changes go throughspark migrate. - Updatability: every module version must pass the test gate and carry a correct version manifest.