# 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(...)`.

### 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_<definition_uuid>` (scalar/select/bool)
  - `cfm_<definition_uuid>` (multiselect als CSV)
  - `cfd_<definition_uuid>_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).
- Nur dann in `SettingCacheService::update(...)` 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).
