# Konventionen (kurz und verbindlich) Letzte Aktualisierung: 2026-03-18 ## 1) Code - Kleine, fokussierte Änderungen statt Misch-Commits. - Kein toter Code, keine ungenutzten Helpers. - ASCII als Standard, Unicode nur wenn Datei es bereits nutzt. ## 2) Schichten - SQL nur in `lib/Repository/**`. - Fachlogik nur in `lib/Service/**`. - `pages/**` bleibt dünn: Input, Auth/AuthZ, Service-Aufruf, Response. - Neue Domain-Logik als Instanz-Service mit Factory-Verdrahtung. - Service-Instanzen in Actions/Helpern nur via `app(Foo::class)`. - `new ...Factory()` nur im Composition Root (`web/index.php` + `lib/App/registerContainer.php`) oder in `*Factory.php`. - In `lib/Service/**` außerhalb von `*Factory.php` keine direkten `new ...Factory()`, `new ...Service()`, `new ...Gateway()` oder `new ...Repository()`. - Alte Service-Helper (`accessServicesFactory()`, `userServicesFactory()` usw.) nicht mehr verwenden. - `pages/**/data().php` nur GET (`gridRequireGetRequest()`), Query-Normalisierung ausschließlich über `gridParseFilters(...)`. - Für jede Liste ein `filter-schema.php` im selben Verzeichnis; `data().php`, `index().php` und `index(default).phtml` verwenden dieses Schema. - Filter-Toolbar nur über `renderGridFilterToolbar(...)`, keine manuellen Filter-Inputs/-Selects. - Client-Filterbindung nur über `gridFiltersFromSchema(...)` (kein inline `filters: [...]`). - Für Listen gilt Filter UX 2.0: Quick Search sichtbar, restliche Filter im Drawer, aktive Filter-Chips. - Search-only-Listen (nur Quick Search) verwenden keinen Drawer und bleiben im Live-Modus. - `data-filter-overflow`, `data-filter-toggle` und `data-toolbar-toggle` sind Legacy und in Listen-Templates nicht mehr erlaubt. - Listen-IDs nur als CSV-Parameter mit pluralem Key (`*_ids`), keine Alias-Fallbacks. ## 3) Autorisierung - Nur zentrale Policy-Abilities nutzen. - Keine verteilten `userHas(...)`-Checks als Hauptlogik. - Tenant-Scope nicht in Templates oder JavaScript nachbauen. ## 4) API - UUID-first für externe Ressourcen. - Interne IDs nicht nach außen geben. - Fehlerantworten einheitlich halten (`error`, optional `errors`). - OpenAPI bei jeder API-Änderung im selben Merge aktualisieren. ## 5) Frontend - Templates nur für Rendering. - UI-Texte über `t('...')`. - Strukturregeln in `/docs/reference-frontend-css.md` und `/docs/reference-frontend-javascript.md`. - Runtime-Komponenten nur über Lifecycle-Contract (`init(root, config)` + `destroy()`), ohne komponenteneigenen Auto-Init. - Host-gebundene Runtime-Komponenten über `data-app-component` markieren; nur echte Global-Utilities ohne Host als runtime-global registrieren. ## 7) Module - Namespace: `MintyPHP\Module\\*` — nie Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`). - Verzeichnis: `modules//lib/Module//` (Service, Repository, Providers, Support). - Session-Keys: Prefix `module..*`. - UI-Integration nur ueber Plattform-Slots (`aside.tab_panel`, `topbar.right_item`, `layout.head_style`, `runtime.component`, etc.). - Kein Modul-spezifisches Markup in Core-Templates. - Tests: `modules//tests/` (werden von `phpunit.xml` automatisch entdeckt via `modules/*/tests`). - Modul-Actions importieren nie `OperationsAuthorizationPolicy::ABILITY_*` — eigene Policy nutzen. - Manifest-Contract: `/docs/reference-module-manifest-contract.md`. ## 8) Mindestchecks vor Merge - `docker compose exec php vendor/bin/phpunit` - `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress` - bei Modul-/Manifest-Aenderungen: `docker compose exec php php bin/module-runtime-sync.php` - bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors)