# Konventionen Letzte Aktualisierung: 2026-02-22 Diese Regeln sind projektweit verbindlich, um Lesbarkeit und Wartbarkeit stabil zu halten. ## 1) Allgemein - ASCII als Standard, außer bestehende Datei nutzt bereits Unicode. - Keine toten Pfade/Codezweige einbauen. - Wiederholung lieber zentralisieren (Partial/Helper/Utility) als kopieren. - Kleine, fokussierte Commits/Changesets bevorzugen. ## 2) PHP-Schichten ### Repository - Enthalten SQL und Filterlogik. - Keine HTTP-/Session-/Render-Logik. - Prepared Statements und bestehende Query-Utilities nutzen. ### Service - Geschäftsregeln, Validierung, Orchestrierung. - Keine HTML-Ausgabe. - Keine direkten View-Annahmen. - Bei globalen Settings bleibt DB die Quelle (`SettingService`); Datei-Cache nur gezielt für `appSetting(...)`. - Für neue oder refaktorierte Domain-Module Instanz-Services + Factory verwenden (z. B. `...ServicesFactory`) statt statischer Domain-Methoden. - Keine domain-spezifischen Service-Locator-Helper in `lib/Support/helpers/app.php`; Composition per Factory im Aufrufer. ### Action (`pages/**.php`) - Request lesen, Zugriff prüfen, Service aufrufen, Variablen für View setzen. - Redirects/Flash-Messages hier zentral steuern. ### Views (`*.phtml`) - Reines Rendering. - Keine DB-Calls. - HTML escapen (`e(...)`) außer bewusst gewünscht. ## 3) UI-Konventionen ### Edit-Seiten - Einheitliche Titelzeile mit `/templates/partials/app-details-titlebar.phtml`. - In der Titelzeile nur Primäraktionen halten (typisch: `Save`, `Save & close`). - Sekundäraktionen nicht im Drei-Punkte-Menü verstecken, sondern im Aside als einklappbarer Block `Actions` über `/templates/partials/app-details-aside-actions.phtml`. - Partial-Naming klar trennen: - linkes Haupt-Aside: `app-main-aside*` - rechtes Details-Aside: `app-details-aside*` - Tab-Reihenfolge: - erster Tab `Master data` - später `Visibility` - optional letzter Tab `Danger zone` - Statusfeld über `/templates/partials/app-visibility-status-field.phtml`. - Delete-Aktion über `/templates/partials/app-danger-zone-delete-field.phtml`. - Aside-Metadaten über: - `/templates/partials/app-details-aside-audit.phtml` - `/templates/partials/app-details-aside-ids.phtml` - Tenant-Zusatzfelder: - Definitionen werden im Tenant-Tab `Custom fields` über eigene POST-Actions gepflegt (nicht über Tenant-Hauptsave). - `field_key` wird nicht im UI gepflegt; serverseitig aus Label erzeugt und tenant-weit eindeutig gehalten. - `is_filterable` nur für `select`, `multiselect`, `boolean`, `date` anbieten. - User-Werte werden im User-Tab `Custom fields` tenantweise gruppiert gerendert. - User-Zusatzfelder sind optional; keine Pflichtvalidierung in V1. ### Listen - Grid.js als Standard. - Filter/Toolbar konsistent halten. - Aktionsspalten nur wenn wirklich nötig; sonst Double-Click/Row-Action nutzen. - Dynamische Address-Book-Filter für Zusatzfelder folgen festen Parametern: - `cf_` (scalar/select/bool) - `cfm_` (multiselect als CSV) - `cfd__from|to` (date range) ## 4) CSS - Prefix `app-` für eigene Klassen/Dateien. - Vendor-Anpassungen in `/web/css/vendor-overrides`. - Layering über `/web/css/app-layers.css`. - Theme-/Contrast-Werte über zentrale Variablen in `/web/css/base`. ## 5) JavaScript - Struktur: - `core/` für Basismodule - `components/` für wiederverwendbare UI-Module - `pages/` für seitenspezifische Logik - Initialisierung zentral in `app-init.js` bzw. `app-login-init.js`. - Defensive DOM-Checks (Element kann auf manchen Seiten fehlen). - Keine Business-Logik im Frontend verstecken. ## 6) i18n - Alle sichtbaren UI-Texte über `t('...')`. - Übersetzungs-Keys in `i18n/default_de.json` und `i18n/default_en.json` pflegen. - Test nutzen: `tests/I18n/TranslationKeysTest.php`. ## 7) Qualitätssicherung Vor Merge mindestens: - PHPUnit - PHPStan - ESLint (web/js) - Betroffene Kern-Userflows manuell testen Checkliste siehe: `/docs/entwickler-checkliste.md` ### Dependency-Hygiene (periodisch, nicht bei jedem Commit) Ungenutzte Composer-Pakete prüfen: ```bash docker compose exec php vendor/bin/composer-unused ``` Ausführen bei: Feature-Entfernung, größerem Refactoring oder vor Releases. Pakete die fälschlicherweise als unused gemeldet werden (z.B. dynamisch geladen), können in `composer.json` unter `extra.unused` ignoriert werden. ## 8) Settings-Konvention - Neue Settings immer zuerst sauber im `SettingService` modellieren (Validierung + Read/Write). - Aufrufer nutzen `SettingGateway` aus `SettingServicesFactory`; kein globaler `settingGateway()`-Helper. - Nur dann in den `SettingCacheService` aufnehmen, wenn der Key wirklich über `appSetting(...)` im Hot Path genutzt wird. - Keine Sicherheits-/Integrationssettings (SMTP, SSO-Secrets, API-Policies) als Pflicht in den Datei-Cache drücken. - Bei manuellen DB-Änderungen an gecachten Keys den Cache gezielt aktualisieren (z. B. über Settings-Save-Flow).