Read this when changing PHP, Fat-Free Framework integration, plugins, or API controllers. # Backend Conventions ## Namespaces and Plugins - Composer maps `Core\` to `src/Core/` and `Modules\` to `src/Modules/`. - A discovered plugin lives in a directory containing `.php`; its derived class must extend `PluginStrategy`. - `ApplicationComposition` boots `System` before the remaining plugins. Register plugin initialization work in constructors. - Use `PluginStrategy::AddRoute()` for F3 route registration and `AddMenuItem()` for permission-filtered menu entries. ## API Controllers - API route declarations belong in `Core\Api\Api`; controllers extend `Controller`. - Use `sendJson()` / `sendError()` rather than emitting ad hoc response formats. They set JSON, status, and `Cache-Control: no-store`. - Decode request objects through `decodeJsonRequest()` and return 400 for invalid JSON or required-field failures. - Call `requireAuthentication()` for protected reads; call numeric `requireRole()` plus `validateCsrfToken()` before protected mutations. Role ID `1` is Administrator and role ID `2` is Inventory operator. - Return explicit DTOs, never a mapper or credential fields directly. Role DTOs contain `id`, `name`, and `description`; user DTOs contain role IDs; Inventory Monitor demo DTOs contain only safe item fields. See [api-routes.md](api-routes.md) and [role-and-inventory.md](role-and-inventory.md). ## Persistence and Errors - F3 globals (`$f3`, `$frameworkUtils`) are the established dependency access pattern; retain it where surrounding code does. - `User`, `Role`, `InventoryItem`, and `Notifications` are `DB\SQL\Mapper` classes. Use parameterized mapper predicates for request values. - Wrap multi-step user and role mutation checks and writes in a transaction; use row locks where final-admin or assignment-safe invariants require serialization. - Validate trimmed role names, SKUs, and item names at the controller boundary; enforce uniqueness and non-negative inventory values in the database as the final safeguard. - Unexpected controller failures are logged server-side and return a safe generic message. - API errors are JSON; `ErrorHandlers` identifies `/api/v1` requests before setting the status. ## Formatting Modern API/composition files use strict types, typed properties, trailing commas, and tabs. Older system files are mixed-style; make surgical changes and preserve their local style. See [rules/add-api-endpoint.md](rules/add-api-endpoint.md) and [rules/add-plugin.md](rules/add-plugin.md).