From 545bcc789bc4797ec69d51d1d8f5a6b4fbcb647f Mon Sep 17 00:00:00 2001 From: fs Date: Wed, 29 Apr 2026 09:57:22 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20replace=20ASCII=20umlaut=20fallbacks=20?= =?UTF-8?q?with=20proper=20=C3=A4=C3=B6=C3=BC=C3=9F=20across=20all=20.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most German docs were written with `ue`/`ae`/`oe`/`ss` ASCII fallbacks (`fuer`, `aenderung`, `koennen`, `gemaess`) — relic from older toolchain constraints. Replaced 237 occurrences across 38 .md files with proper umlauts and ß so the docs read naturally. Substitutions are constrained to plain prose: fenced code blocks (```...```), inline code spans (`...`), markdown link targets `[..](..)`, and HTML comments are preserved verbatim. Path references like `docs/howto-erste-aenderung.md` keep their original (umlaut-replaced) filenames — only the surrounding prose is normalised. Tool: bin/fix-md-umlauts.py (idempotent — no-op on already-clean files). Re-runnable if ASCII fallbacks creep back in via copy-paste. Doc-link-check + doc-drift-check stay green. Co-Authored-By: Claude Opus 4.7 (1M context) --- .agents/skills/core-guardrails/SKILL.md | 20 +- .../references/boundaries-core.md | 16 +- .../references/boundaries-ui.md | 48 ++-- .../references/quality-gates.md | 10 +- .../skills/starterkit-grid-standards/SKILL.md | 10 +- .../references/list-checklist.md | 8 +- .../references/page-size-standard.md | 2 +- .../references/row-interaction-standard.md | 6 +- .../skills/starterkit-php-style-ci/SKILL.md | 16 +- .../references/ci-dry-run.md | 4 +- .../references/style-workflow.md | 2 +- .agents/skills/starterkit-planner/SKILL.md | 14 +- .../references/tradeoff-matrix.md | 2 +- README.md | 4 +- bin/fix-md-umlauts.py | 262 ++++++++++++++++++ docs/explanation-architektur.md | 2 +- docs/explanation-di-container.md | 2 +- docs/explanation-einstellungen-speicherung.md | 2 +- docs/explanation-session-management.md | 20 +- docs/howto-anfragelimits.md | 2 +- docs/howto-betriebscheck-doctor.md | 8 +- docs/howto-dokumentation-erweitern.md | 4 +- docs/howto-gitea-required-checks.md | 14 +- docs/howto-globale-suche.md | 2 +- docs/howto-lokale-entwicklung.md | 12 +- docs/howto-modul-erstellen.md | 40 +-- docs/howto-request-input-validation.md | 6 +- docs/index.md | 32 +-- docs/reference-cli-commands.md | 28 +- docs/reference-codex-prompts.md | 2 +- docs/reference-entwickler-checkliste.md | 14 +- docs/reference-extension-readiness.md | 14 +- docs/reference-frontend-css.md | 2 +- docs/reference-frontend-javascript.md | 10 +- docs/reference-konfiguration.md | 2 +- docs/reference-konventionen.md | 4 +- docs/reference-module-manifest-contract.md | 28 +- docs/reference-notifications-module.md | 34 +-- tests/README.md | 28 +- 39 files changed, 499 insertions(+), 237 deletions(-) create mode 100755 bin/fix-md-umlauts.py diff --git a/.agents/skills/core-guardrails/SKILL.md b/.agents/skills/core-guardrails/SKILL.md index a4d2ea3..437aff8 100644 --- a/.agents/skills/core-guardrails/SKILL.md +++ b/.agents/skills/core-guardrails/SKILL.md @@ -1,6 +1,6 @@ --- name: core-guardrails -description: Verbindliche Guardrails fuer Architektur-, Refactor-, Zentralisierungs-, Standardisierungs- und Implementierungsaufgaben in diesem Starterkit. Verwenden, wenn Code geaendert, neu strukturiert oder gegen bestehende Layer-/UI-/Security-Standards geprueft werden soll. +description: Verbindliche Guardrails für Architektur-, Refactor-, Zentralisierungs-, Standardisierungs- und Implementierungsaufgaben in diesem Starterkit. Verwenden, wenn Code geändert, neu strukturiert oder gegen bestehende Layer-/UI-/Security-Standards geprüft werden soll. --- # Core Guardrails @@ -12,21 +12,21 @@ Durchgaengig dieselben technischen Grenzen durchsetzen, damit Core robust, wartb ## Verbindliche Regeln 1. MUST Layering einhalten (`pages` -> `Service` -> `Repository`, Templates nur Rendering). -2. MUST Request/Input/Validation-Contract einhalten (`requestInput()`, `FormErrors`, API-Validation ueber `ApiResponse::validationFromFormErrors(...)`, kein `ApiResponse::readJsonBody(...)` in `pages/api/v1/**`, keine direkten Superglobals in `pages/**`). -3. MUST AuthZ/RBAC serverseitig durchsetzen und im UI nur ueber `$viewAuth` steuern. -4. MUST Security-Guards einhalten (CSRF auf POST-Endpunkten, keine unredacted PII/Secrets in Logs/Audit-Meta, SQL nur vorbereitet ueber Repository). -5. MUST UI-Standards und Data-Contracts fuer Listen/Detailseiten nutzen (Wrapper, Partials, globaler Confirm-Dialog statt `window.confirm`, inklusive globaler Grid-Standards fuer rowInteraction/pageSize). -6. MUST Frontend-Hardcuts einhalten (keine inline ESM-Module in Templates/Pages, JS-`src` mit `assetVersion(...)`, zentrale Telemetrie fuer relevante Frontend-Warnings/Fetch-Fehler). -7. MUST Quality-Gates ausfuehren und Ergebnis transparent berichten. -8. MUST bei Konflikten den regelkonformen Weg waehlen oder den Konflikt als Blocker markieren. +2. MUST Request/Input/Validation-Contract einhalten (`requestInput()`, `FormErrors`, API-Validation über `ApiResponse::validationFromFormErrors(...)`, kein `ApiResponse::readJsonBody(...)` in `pages/api/v1/**`, keine direkten Superglobals in `pages/**`). +3. MUST AuthZ/RBAC serverseitig durchsetzen und im UI nur über `$viewAuth` steuern. +4. MUST Security-Guards einhalten (CSRF auf POST-Endpunkten, keine unredacted PII/Secrets in Logs/Audit-Meta, SQL nur vorbereitet über Repository). +5. MUST UI-Standards und Data-Contracts für Listen/Detailseiten nutzen (Wrapper, Partials, globaler Confirm-Dialog statt `window.confirm`, inklusive globaler Grid-Standards für rowInteraction/pageSize). +6. MUST Frontend-Hardcuts einhalten (keine inline ESM-Module in Templates/Pages, JS-`src` mit `assetVersion(...)`, zentrale Telemetrie für relevante Frontend-Warnings/Fetch-Fehler). +7. MUST Quality-Gates ausführen und Ergebnis transparent berichten. +8. MUST bei Konflikten den regelkonformen Weg wählen oder den Konflikt als Blocker markieren. 9. MUST NOT Extension-Architektur erfinden; dieses Thema ist aktuell Out of Scope. ## Vorgehen je Aufgabe 1. Scope bestimmen (`core`, `ui`, `api`, `mixed`). 2. Vorhandene Contracts zuerst suchen, dann wiederverwenden. -3. Aenderung minimal halten, keine Seiteneffekte ohne Grund. -4. Nach Aenderung die relevanten Gates ausfuehren. +3. Änderung minimal halten, keine Seiteneffekte ohne Grund. +4. Nach Änderung die relevanten Gates ausführen. 5. Rest-Risiken explizit benennen. ## Out of Scope diff --git a/.agents/skills/core-guardrails/references/boundaries-core.md b/.agents/skills/core-guardrails/references/boundaries-core.md index 9c9453f..31f6524 100644 --- a/.agents/skills/core-guardrails/references/boundaries-core.md +++ b/.agents/skills/core-guardrails/references/boundaries-core.md @@ -16,18 +16,18 @@ ## Input / Validation -1. MUST Input in `pages/**` ueber `requestInput()` lesen. +1. MUST Input in `pages/**` über `requestInput()` lesen. 2. MUST NOT `$_POST`, `$_GET`, `$_FILES`, `REQUEST_METHOD` in `pages/**` verwenden. 3. MUST NOT `$_SESSION`, `$_SERVER`, `$_COOKIE`, `$_ENV` in `pages/**` direkt verwenden. -4. MUST Form-Validation ueber `FormErrors` fuehren. -5. MUST API-Validation-Fehler ueber `ApiResponse::validationFromFormErrors(...)` ausgeben. +4. MUST Form-Validation über `FormErrors` führen. +5. MUST API-Validation-Fehler über `ApiResponse::validationFromFormErrors(...)` ausgeben. 6. MUST NOT `ApiResponse::readJsonBody(...)` in `pages/api/v1/**` verwenden. ## List-Data Endpoints 1. MUST `pages/**/data().php` als GET-only Endpunkte umsetzen (`gridRequireGetRequest()`). -2. MUST Query-Filter ueber `gridParseFilters(...)` + `filter-schema.php` normalisieren. -3. MUST NOT Query-Filter inline/parallele Alias-Parser in `data().php` neu einfuehren. +2. MUST Query-Filter über `gridParseFilters(...)` + `filter-schema.php` normalisieren. +3. MUST NOT Query-Filter inline/parallele Alias-Parser in `data().php` neu einführen. ## Security / API @@ -35,11 +35,11 @@ 2. MUST Tenant-Scope serverseitig erzwingen. 3. MUST CSRF auf POST-Endpunkten vor Body-Verarbeitung verifizieren. 4. MUST NOT PII/Secrets unredacted in Logs oder Audit-Metadata schreiben. -5. MUST SQL nur ueber Repository mit prepared statements ausfuehren. +5. MUST SQL nur über Repository mit prepared statements ausführen. 6. MUST extern UUID-first bleiben. 7. MUST API-Fehler konsistent halten (`error`, optional `errors`). -8. MUST OpenAPI im selben Merge aktualisieren, wenn API geaendert wird. +8. MUST OpenAPI im selben Merge aktualisieren, wenn API geändert wird. -## Pruef-Hinweis +## Prüf-Hinweis - Harte Repo-Gates: `tests/Architecture/CoreStarterkitContractTest.php` diff --git a/.agents/skills/core-guardrails/references/boundaries-ui.md b/.agents/skills/core-guardrails/references/boundaries-ui.md index 5994f51..c2b696c 100644 --- a/.agents/skills/core-guardrails/references/boundaries-ui.md +++ b/.agents/skills/core-guardrails/references/boundaries-ui.md @@ -2,69 +2,69 @@ ## Listen-Standard -1. MUST Listen ueber `initStandardListPage(...)` initialisieren. -2. MUST Filter-Toolbar ueber zentrale Helper/Partials rendern. -3. MUST aktive Chips/Drawer-Verhalten ueber Standard-Contracts laufen lassen. +1. MUST Listen über `initStandardListPage(...)` initialisieren. +2. MUST Filter-Toolbar über zentrale Helper/Partials rendern. +3. MUST aktive Chips/Drawer-Verhalten über Standard-Contracts laufen lassen. 4. MUST NOT direkt `gridFiltersFromSchema(...)` oder `initListFilterExperience(...)` in Listen-Templates verwenden. 5. MUST NOT Legacy-Filter-Toggle-Markup (`data-toolbar-toggle`, `data-filter-overflow`, `data-filter-toggle`) neu einbauen. -6. MUST rowInteraction-Standard fuer Listen mit Row-Navigation beibehalten (sichtbare Action-Spalte + Enter + Doppelklick-Fallback). +6. MUST rowInteraction-Standard für Listen mit Row-Navigation beibehalten (sichtbare Action-Spalte + Enter + Doppelklick-Fallback). 7. MUST pageSize-Standard beibehalten (10/25/50/100, Toolbar rechts, URL > localStorage > default). ## Detailseiten-Standard 1. MUST Hauptformular mit `data-standard-detail-form="1"` markieren. -2. MUST Unsaved/Shortcut/Dirty-State ueber `initStandardDetailPage(...)` nutzen. -3. MUST Detail-Aktionen ueber Action-Policy-Contract (`data-detail-action-policy`, `data-detail-action-kind`, `data-detail-confirm-message`) steuern. +2. MUST Unsaved/Shortcut/Dirty-State über `initStandardDetailPage(...)` nutzen. +3. MUST Detail-Aktionen über Action-Policy-Contract (`data-detail-action-policy`, `data-detail-action-kind`, `data-detail-confirm-message`) steuern. 4. MUST NOT inline `confirm(...)` (`onclick` / `onsubmit`) auf standardisierten Detailseiten nutzen. ## Confirm + Telemetry Standard -1. MUST Confirm-Dialoge zentral ueber den globalen Confirm-Service abwickeln. +1. MUST Confirm-Dialoge zentral über den globalen Confirm-Service abwickeln. 2. MUST NOT `window.confirm(...)` in App-JS oder inline HTML-Handlern verwenden. -3. MUST relevante Frontend-Warnpfade zentral ueber Frontend-Telemetrie erfassen. +3. MUST relevante Frontend-Warnpfade zentral über Frontend-Telemetrie erfassen. 4. MUST NOT relevante UX-/Fehlerpfade nur als Console-Warnung implementieren. ## Frontend Page-Module Hard Cut -1. MUST Seiteninitialisierung ueber dedizierte Module unter `web/js/pages/*` umsetzen. -2. MUST Page-Config ueber `script[type="application/json"]` + `readPageConfig(...)` bereitstellen/lesen. -3. MUST alle JS-`src` in `pages/**` und `templates/**` ueber `assetVersion('...js...')` laden. +1. MUST Seiteninitialisierung über dedizierte Module unter `web/js/pages/*` umsetzen. +2. MUST Page-Config über `script[type="application/json"]` + `readPageConfig(...)` bereitstellen/lesen. +3. MUST alle JS-`src` in `pages/**` und `templates/**` über `assetVersion('...js...')` laden. 4. MUST NOT inline `` in `pages/**` oder `templates/**` verwenden. ## Component Lifecycle Runtime -1. MUST migrierte Komponenten ueber `init(root, config)` + `destroy()` standardisieren. +1. MUST migrierte Komponenten über `init(root, config)` + `destroy()` standardisieren. 2. MUST NOT migrierte Komponenten per `DOMContentLoaded`/Module-Sideeffect selbst auto-initialisieren. 3. MUST Listener, Timer und Observer, die in `init(...)` entstehen, in `destroy()` wieder abbauen. -4. MUST Runtime-Konfiguration ueber Page-Config (`readPageConfig(...)`) beziehen, keine verteilten Ad-hoc-Globals. -5. MUST host-gebundene UI-Komponenten ueber explizite `data-app-component`-Hosts im Markup binden. -6. Global-Utilities ohne natuerliches Host-Element MAY via Runtime `scope: 'global'` registriert werden, MUESSEN aber denselben Lifecycle-Contract inkl. `destroy()` einhalten. +4. MUST Runtime-Konfiguration über Page-Config (`readPageConfig(...)`) beziehen, keine verteilten Ad-hoc-Globals. +5. MUST host-gebundene UI-Komponenten über explizite `data-app-component`-Hosts im Markup binden. +6. Global-Utilities ohne natürliches Host-Element MAY via Runtime `scope: 'global'` registriert werden, MÜSSEN aber denselben Lifecycle-Contract inkl. `destroy()` einhalten. ## Shared Partials -1. MUST Listen-Titlebar ueber `templates/partials/app-list-titlebar.phtml` rendern. -2. MUST List-Tabs ueber `templates/partials/app-list-tabs.phtml` rendern. -3. MUST Purge-Action ueber `templates/partials/app-list-purge-action.phtml` rendern. -4. MUST Detail-Validation-Summary ueber `templates/partials/app-details-validation-summary.phtml` rendern. +1. MUST Listen-Titlebar über `templates/partials/app-list-titlebar.phtml` rendern. +2. MUST List-Tabs über `templates/partials/app-list-tabs.phtml` rendern. +3. MUST Purge-Action über `templates/partials/app-list-purge-action.phtml` rendern. +4. MUST Detail-Validation-Summary über `templates/partials/app-details-validation-summary.phtml` rendern. ## RBAC in Templates -1. MUST UI-Capabilities nur ueber `$viewAuth` lesen. +1. MUST UI-Capabilities nur über `$viewAuth` lesen. 2. MUST NOT `can('...')` in Templates verwenden. ## CSS Boundaries -1. MUST Styles moeglichst lokal in `web/css/components`, `web/css/layout` oder `web/css/pages` halten. -2. MUST NOT globale unscoped Overrides ohne klaren Scope einfuehren. +1. MUST Styles möglichst lokal in `web/css/components`, `web/css/layout` oder `web/css/pages` halten. +2. MUST NOT globale unscoped Overrides ohne klaren Scope einführen. 3. MUST Vendor-Overrides nur in `web/css/vendor-overrides/**` pflegen. 4. MUST bestehende CSS-Variablen bevorzugen statt neue Inline-Farbwerte zu verteilen. ## Komponenten in Formularen -1. MUST Core-Button-Klassen (`secondary outline small`, `danger outline small`) verwenden statt Custom-Button-CSS. Custom-CSS nur fuer Layout (z.B. `border-radius: 50%`). +1. MUST Core-Button-Klassen (`secondary outline small`, `danger outline small`) verwenden statt Custom-Button-CSS. Custom-CSS nur für Layout (z.B. `border-radius: 50%`). 2. MUST `margin-bottom: 0` auf Buttons, Inputs, Selects und Labels innerhalb selbststaendiger Komponenten in Formularen resetten (Core setzt `margin-bottom: var(--app-spacing)` global). 3. MUST Checkboxen in Flex-Containern mit expliziter Groesse (`width: 1.25em; height: 1.25em`) und `flex-shrink: 0` versehen (Core nutzt `appearance: none` mit Custom-Sizing). 4. MUST `position: sticky` mit `top: calc(var(--app-topbar-height) + ...)` verwenden, nicht `top: 0` (Topbar ist sticky). 5. MUST Icon-Only-Buttons mit `data-tooltip` und `aria-label` versehen. 6. MUST bei `grid-template-columns` mit mehr als einer Spalte ein `@media`-Fallback auf Single-Column definieren. -7. MUST bestehende `--app-*` CSS-Variablen fuer Farben verwenden, nie Farbwerte hardcoden. +7. MUST bestehende `--app-*` CSS-Variablen für Farben verwenden, nie Farbwerte hardcoden. diff --git a/.agents/skills/core-guardrails/references/quality-gates.md b/.agents/skills/core-guardrails/references/quality-gates.md index ff543c9..b135352 100644 --- a/.agents/skills/core-guardrails/references/quality-gates.md +++ b/.agents/skills/core-guardrails/references/quality-gates.md @@ -29,18 +29,18 @@ Erwartung: jeweils `0`. ## JS-Scope -- Bei JS-Aenderungen Browser-Smoke mit DevTools-Console durchfuehren. +- Bei JS-Änderungen Browser-Smoke mit DevTools-Console durchführen. - Erwartung: keine neuen JS-Errors. ## Docs-/Skills-Gates (schnell) 1. `bin/docs-link-check.sh` - - prueft Doku-Links in `README.md`, `docs/**`, `.agents/skills/**` und `.agents/**` - - `.agents/runs/**` ist standardmaessig ausgeschlossen (historische Artefakte) + - prüft Doku-Links in `README.md`, `docs/**`, `.agents/skills/**` und `.agents/**` + - `.agents/runs/**` ist standardmäßig ausgeschlossen (historische Artefakte) 2. `bin/docs-drift-check.sh` - - prueft bekannte Legacy-Drifts (entfernte Config-Pfade/Constants, obsolete Search-Marker) + - prüft bekannte Legacy-Drifts (entfernte Config-Pfade/Constants, obsolete Search-Marker) 3. `bin/codex-skills-sync.sh --check` - - prueft Drift zwischen Repo-Skills und `~/.codex/skills` + - prüft Drift zwischen Repo-Skills und `~/.codex/skills` ## Berichtspflicht diff --git a/.agents/skills/starterkit-grid-standards/SKILL.md b/.agents/skills/starterkit-grid-standards/SKILL.md index 501ccfe..2a8dc0f 100644 --- a/.agents/skills/starterkit-grid-standards/SKILL.md +++ b/.agents/skills/starterkit-grid-standards/SKILL.md @@ -1,6 +1,6 @@ --- name: starterkit-grid-standards -description: Standardisierungs-Skill fuer GridJS-Listen im Starterkit. Verwenden, wenn Listen neu gebaut oder refactored werden sollen (rowInteraction, pageSize, filter drawer, URL-state, accessibility). +description: Standardisierungs-Skill für GridJS-Listen im Starterkit. Verwenden, wenn Listen neu gebaut oder refactored werden sollen (rowInteraction, pageSize, filter drawer, URL-state, accessibility). --- # Starterkit Grid Standards @@ -18,18 +18,18 @@ GridJS-Listen projektweit einheitlich, zuganglich und wartbar halten. ## Verbindliche Regeln 1. MUST `initStandardListPage(...)` als Standard nutzen (nur begruendete Ausnahmen direkt mit `createServerGrid(...)`). -2. MUST `rowDblClick.getUrl(...)` fuer zeilenbezogene Navigation setzen, wenn Row-Navigation vorgesehen ist. +2. MUST `rowDblClick.getUrl(...)` für zeilenbezogene Navigation setzen, wenn Row-Navigation vorgesehen ist. 3. MUST globale `rowInteraction`-Defaults respektieren (Action-Spalte, Enter, Doppelklick-Fallback). 4. MUST globale `pageSize`-Standards respektieren (`10/25/50/100`, Toolbar-Placement, URL > storage > default). -5. MUST Filter-Drawer/Chips ueber den Standard-Contract nutzen, keine parallelen Custom-Patterns. +5. MUST Filter-Drawer/Chips über den Standard-Contract nutzen, keine parallelen Custom-Patterns. 6. MUST NOT pro Seite eigene Row-Action-Hacks bauen, wenn der Factory-Contract ausreicht. ## Vorgehen -1. Ist-Liste gegen `references/list-checklist.md` pruefen. +1. Ist-Liste gegen `references/list-checklist.md` prüfen. 2. Fehlende Standards zuerst zentral in der Factory loesen, danach nur minimale Seitenanpassungen. 3. UI/CSS nur als additive Erweiterung zu bestehenden Komponenten. -4. Relevante Gates und Browser-Smoke (Keyboard + Console) ausfuehren. +4. Relevante Gates und Browser-Smoke (Keyboard + Console) ausführen. ## Referenzen diff --git a/.agents/skills/starterkit-grid-standards/references/list-checklist.md b/.agents/skills/starterkit-grid-standards/references/list-checklist.md index c196787..965b717 100644 --- a/.agents/skills/starterkit-grid-standards/references/list-checklist.md +++ b/.agents/skills/starterkit-grid-standards/references/list-checklist.md @@ -3,19 +3,19 @@ ## Bootstrap 1. `initStandardListPage({ grid, filters, hooks })` verwendet. -2. `filterSchema` aus Server-Config uebergeben. +2. `filterSchema` aus Server-Config übergeben. 3. `urlSync` bewusst gesetzt. ## Interaction 1. `rowDblClick.getUrl(...)` liefert stabile Ziel-URL oder leer. 2. Keine Doppel-Action-Spalte (Factory auto-action vs explizite actions). -3. Enter/Pointer/Focus fuer oeffnbare Rows funktionieren. +3. Enter/Pointer/Focus für öffnbare Rows funktionieren. ## Pagination + URL 1. Page-size Optionen nur `10/25/50/100`. -2. URL Sync pruefen (`page`, `order`, `dir`, `limit`). +2. URL Sync prüfen (`page`, `order`, `dir`, `limit`). 3. Default-Werte erzeugen saubere URL. ## Filter UX @@ -26,5 +26,5 @@ ## Regression -1. Sortierung, Selection/Bulk, Doppelklick unveraendert. +1. Sortierung, Selection/Bulk, Doppelklick unverändert. 2. Keine neuen Console Errors. diff --git a/.agents/skills/starterkit-grid-standards/references/page-size-standard.md b/.agents/skills/starterkit-grid-standards/references/page-size-standard.md index 2da7f2f..66cbbe7 100644 --- a/.agents/skills/starterkit-grid-standards/references/page-size-standard.md +++ b/.agents/skills/starterkit-grid-standards/references/page-size-standard.md @@ -15,6 +15,6 @@ ## Verhalten -1. Aenderung der Seitengroesse setzt Seite auf 1. +1. Änderung der Seitengroesse setzt Seite auf 1. 2. Sortierung/Filter bleiben erhalten. 3. LocalStorage-Key pro Tabelle (path + dataUrl + container). diff --git a/.agents/skills/starterkit-grid-standards/references/row-interaction-standard.md b/.agents/skills/starterkit-grid-standards/references/row-interaction-standard.md index 059bdfe..aec9c8b 100644 --- a/.agents/skills/starterkit-grid-standards/references/row-interaction-standard.md +++ b/.agents/skills/starterkit-grid-standards/references/row-interaction-standard.md @@ -8,7 +8,7 @@ Row-Navigation discoverable und keyboard-freundlich machen. 1. Konfigurierbares Link-Column: Die primaere Datenspalte (z.B. Name, Beschreibung) wird als klickbarer ``-Link gerendert. 2. Enter auf fokussierter Row loest dieselbe Navigation aus. -3. Doppelklick bleibt als Fallback fuer Power-User. +3. Doppelklick bleibt als Fallback für Power-User. 4. Nur Rows mit Ziel-URL erhalten `data-row-open-url` und den Link im Link-Column. 5. Rows ohne URL (z.B. fehlende Berechtigung) zeigen den Inhalt als Plain-Text ohne Link. @@ -40,6 +40,6 @@ rowInteraction: { ## Guardrails 1. Keine globale Tab-Stop-Flut auf allen Rows. -2. Fokusstil fuer Row und Link-Element sichtbar. -3. Explizite `actions.enabled: true` pro Seite darf Link-Column uebersteuern (eigene Action-Spalte). +2. Fokusstil für Row und Link-Element sichtbar. +3. Explizite `actions.enabled: true` pro Seite darf Link-Column übersteuern (eigene Action-Spalte). 4. Link-Column darf keine Spalte mit verschachtelten ``-Elementen umwickeln (z.B. Avatar mit Lightbox). diff --git a/.agents/skills/starterkit-php-style-ci/SKILL.md b/.agents/skills/starterkit-php-style-ci/SKILL.md index 2544d69..7ec1fb1 100644 --- a/.agents/skills/starterkit-php-style-ci/SKILL.md +++ b/.agents/skills/starterkit-php-style-ci/SKILL.md @@ -1,24 +1,24 @@ --- name: starterkit-php-style-ci -description: Standard-Skill fuer PHP Coding-Style im Starterkit (php-cs-fixer, dry-run in CI, lokaler fix/check workflow). Verwenden bei Style-Einfuehrung, CI-Checks oder grossen Format-Diffs. +description: Standard-Skill für PHP Coding-Style im Starterkit (php-cs-fixer, dry-run in CI, lokaler fix/check workflow). Verwenden bei Style-Einführung, CI-Checks oder grossen Format-Diffs. --- # Starterkit PHP Style CI ## Ziel -Coding-Style pruefbar, reproduzierbar und regressionsarm machen. +Coding-Style prüfbar, reproduzierbar und regressionsarm machen. ## Wann verwenden -1. Einfuehrung oder Nachschaerfung von Style-Regeln. -2. CI-Dry-Run fuer Style-Checks. +1. Einführung oder Nachschaerfung von Style-Regeln. +2. CI-Dry-Run für Style-Checks. 3. Aufraeumen grosser Style-Diff-Wellen. ## Verbindliche Regeln -1. MUST `vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose` fuer nicht-mutierende Pruefung nutzen (Convenience-Alias: `composer cs:check`). -2. MUST `composer cs:fix` nur bewusst und mit Diff-Kontrolle ausfuehren. +1. MUST `vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose` für nicht-mutierende Prüfung nutzen (Convenience-Alias: `composer cs:check`). +2. MUST `composer cs:fix` nur bewusst und mit Diff-Kontrolle ausführen. 3. MUST Style-Check vor Merge gruen halten (lokal und optional CI). 4. MUST nach groesseren Fixes mindestens `phpunit` und `phpstan` laufen lassen. 5. MUST NOT manuell Einzelstellen formatieren, wenn der Fixer sie zentral loesen kann. @@ -26,8 +26,8 @@ Coding-Style pruefbar, reproduzierbar und regressionsarm machen. ## Workflow 1. Baseline erfassen: `vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose`. -2. Falls noetig fixen: `composer cs:fix`. -3. Diff fokussiert pruefen (Imports, Braces, Nebenwirkungen). +2. Falls nötig fixen: `composer cs:fix`. +3. Diff fokussiert prüfen (Imports, Braces, Nebenwirkungen). 4. Qualitaetsgates laufen lassen. 5. CI-Dry-Run konfigurieren oder validieren. diff --git a/.agents/skills/starterkit-php-style-ci/references/ci-dry-run.md b/.agents/skills/starterkit-php-style-ci/references/ci-dry-run.md index 5da2163..665dcd9 100644 --- a/.agents/skills/starterkit-php-style-ci/references/ci-dry-run.md +++ b/.agents/skills/starterkit-php-style-ci/references/ci-dry-run.md @@ -2,7 +2,7 @@ ## Ziel -CI soll nur pruefen, nicht formatieren. +CI soll nur prüfen, nicht formatieren. ## Minimaler Check @@ -13,7 +13,7 @@ vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php - ## Erwartung 1. Exit Code 0: Style konform. -2. Exit Code != 0: Diff ausgeben, Entwickler fuehrt lokal `composer cs:fix` aus. +2. Exit Code != 0: Diff ausgeben, Entwickler führt lokal `composer cs:fix` aus. ## Hinweise diff --git a/.agents/skills/starterkit-php-style-ci/references/style-workflow.md b/.agents/skills/starterkit-php-style-ci/references/style-workflow.md index e794ddd..9154d1c 100644 --- a/.agents/skills/starterkit-php-style-ci/references/style-workflow.md +++ b/.agents/skills/starterkit-php-style-ci/references/style-workflow.md @@ -11,7 +11,7 @@ composer cs:fix 1. Erst Style-Check laufen lassen (`vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose`). 2. Danach `cs:fix`. -3. Nur relevante Diffs uebernehmen, grosse Misch-Diffs vermeiden. +3. Nur relevante Diffs übernehmen, grosse Misch-Diffs vermeiden. 4. Anschliessend: ```bash diff --git a/.agents/skills/starterkit-planner/SKILL.md b/.agents/skills/starterkit-planner/SKILL.md index 0b890ef..359ac2b 100644 --- a/.agents/skills/starterkit-planner/SKILL.md +++ b/.agents/skills/starterkit-planner/SKILL.md @@ -1,13 +1,13 @@ --- name: starterkit-planner -description: Planungs-Skill fuer Architektur-, Rollout-, Refactor- und Standardisierungsaufgaben im Starterkit. Verwenden, wenn ein decision-complete Plan mit klaren Interfaces, Tests, Risiken und Annahmen benoetigt wird. +description: Planungs-Skill für Architektur-, Rollout-, Refactor- und Standardisierungsaufgaben im Starterkit. Verwenden, wenn ein decision-complete Plan mit klaren Interfaces, Tests, Risiken und Annahmen benötigt wird. --- # Starterkit Planner ## Ziel -Planungen so strukturieren, dass Implementierung ohne offene Entscheidungen moeglich ist. +Planungen so strukturieren, dass Implementierung ohne offene Entscheidungen möglich ist. Bei Agent-Workflows muss der Plan maschinenlesbar in die Projekt-Contracts passen. ## Verbindliches Ausgabeformat @@ -23,9 +23,9 @@ Bei Agent-Workflows muss der Plan maschinenlesbar in die Projekt-Contracts passe Wenn `.agents/` verwendet wird: 1. Plan muss dem Schema `.agents/contracts/planner.schema.json` entsprechen. -2. Success Criteria muessen stabile IDs tragen (`SC-001`, `SC-002`, ...). -3. Success Criteria muessen so formuliert sein, dass Reviewer Acceptance sie direkt gegen `criterion_id` pruefen kann. -4. Guard- und Quality-Gate-IDs muessen aus den Katalogen kommen (`GR-*`, `QG-*`). +2. Success Criteria müssen stabile IDs tragen (`SC-001`, `SC-002`, ...). +3. Success Criteria müssen so formuliert sein, dass Reviewer Acceptance sie direkt gegen `criterion_id` prüfen kann. +4. Guard- und Quality-Gate-IDs müssen aus den Katalogen kommen (`GR-*`, `QG-*`). ## Vorgehen @@ -33,7 +33,7 @@ Wenn `.agents/` verwendet wird: 2. Entscheidungen mit Tradeoffs transparent machen. 3. Oeffentliche Contracts explizit benennen. 4. Success Criteria frueh mit stabilen IDs (`SC-*`) definieren. -5. Reihenfolge und Rollout so planen, dass Rueckbau moeglich bleibt. +5. Reihenfolge und Rollout so planen, dass Rueckbau möglich bleibt. 6. Teststrategie nach Risiko priorisieren. ## Qualitaetskriterien @@ -42,7 +42,7 @@ Wenn `.agents/` verwendet wird: 2. Jeder betroffene Bereich hat klare Akzeptanzkriterien mit stabiler ID (`SC-*`). 3. Risiken sind priorisiert und beobachtbar. 4. Ungeklaerte Themen stehen explizit unter Annahmen. -5. Guard-/Gate-Referenzen sind vollstaendig und pruefbar (`GR-*`, `QG-*`). +5. Guard-/Gate-Referenzen sind vollstaendig und prüfbar (`GR-*`, `QG-*`). ## Out of Scope diff --git a/.agents/skills/starterkit-planner/references/tradeoff-matrix.md b/.agents/skills/starterkit-planner/references/tradeoff-matrix.md index 081833e..871efde 100644 --- a/.agents/skills/starterkit-planner/references/tradeoff-matrix.md +++ b/.agents/skills/starterkit-planner/references/tradeoff-matrix.md @@ -19,7 +19,7 @@ ### Option B: Shared Partial/Helper - Vorteile: Schneller Nutzen, moderates Risiko -- Nachteile: Teilweise Restduplikate moeglich +- Nachteile: Teilweise Restduplikate möglich - Geeignet wenn: Wiederkehrendes UI-/Glue-Muster mit klaren Datencontracts ### Option C: Lokal belassen diff --git a/README.md b/README.md index 73cef37..edafd5a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ docker compose exec php php bin/console module:sync # 3. Modul-Migrationen + A App: · phpMyAdmin: -> `APP_CRYPTO_KEY` aus `.env.example` nicht aendern — sonst lassen sich die geseeded Microsoft-SSO- und BC-Test-Secrets nicht entschluesseln. +> `APP_CRYPTO_KEY` aus `.env.example` nicht ändern — sonst lassen sich die geseeded Microsoft-SSO- und BC-Test-Secrets nicht entschlüsseln. ### Login @@ -28,7 +28,7 @@ Alle Demo-User haben das Passwort `Demo123`: | `hilde@user.com` | Support | Plus der Live-User `fs@breadcrumb-solutions.de` (alle Rollen, Passwort nur per Reset). -Microsoft SSO ist fuer den Tenant `breadcrumb mediasolutions GmbH` vorkonfiguriert (Domain `breadcrumb-solutions.de`). +Microsoft SSO ist für den Tenant `breadcrumb mediasolutions GmbH` vorkonfiguriert (Domain `breadcrumb-solutions.de`). ## Quality Gates diff --git a/bin/fix-md-umlauts.py b/bin/fix-md-umlauts.py new file mode 100755 index 0000000..4ef699d --- /dev/null +++ b/bin/fix-md-umlauts.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 +""" +Replace ASCII-fallback German umlauts (ue, ae, oe, ss) with proper umlauts +inside .md prose, while preserving: + - fenced code blocks (``` ... ```) + - inline code spans (` ... `) + - markdown link targets ([label](path)) — only the (path) part is preserved + - HTML comments () + +Usage: python3 bin/fix-md-umlauts.py [ ...] + --dry-run print proposed changes per file (default: write in place) + --check exit 1 if any file would change (CI mode) +""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path + +# Order matters: longer patterns first to prevent partial matches +# (e.g. "aenderung" must be tried before "aender" so prose-ending stays clean). +SUBSTITUTIONS: list[tuple[str, str]] = [ + # ß / ss + ("massgeblich", "maßgeblich"), + ("Massgeblich", "Maßgeblich"), + ("gemaess", "gemäß"), + ("Gemaess", "Gemäß"), + ("regelmaessig", "regelmäßig"), + ("Regelmaessig", "Regelmäßig"), + ("groesst", "größt"), + ("Groesst", "Größt"), + # ä – longer first + ("aenderung", "änderung"), + ("Aenderung", "Änderung"), + ("aenderbar", "änderbar"), + ("aendert", "ändert"), + ("aendern", "ändern"), + ("Aender", "Änder"), + ("aender", "änder"), + ("naechst", "nächst"), + ("Naechst", "Nächst"), + ("naemlich", "nämlich"), + ("Naemlich", "Nämlich"), + ("waehrend", "während"), + ("Waehrend", "Während"), + ("waehl", "wähl"), + ("Waehl", "Wähl"), + ("haeufig", "häufig"), + ("Haeufig", "Häufig"), + ("spaeter", "später"), + ("Spaeter", "Später"), + ("aufzaehl", "aufzähl"), + ("Aufzaehl", "Aufzähl"), + ("gefaehr", "gefähr"), + ("Gefaehr", "Gefähr"), + ("erlaeut", "erläut"), + ("Erlaeut", "Erläut"), + ("bestaetig", "bestätig"), + ("Bestaetig", "Bestätig"), + ("Geschaeft", "Geschäft"), + ("geschaeft", "geschäft"), + # ü – longer first + ("ausfuehr", "ausführ"), + ("Ausfuehr", "Ausführ"), + ("durchfuehr", "durchführ"), + ("Durchfuehr", "Durchführ"), + ("einfuehr", "einführ"), + ("Einfuehr", "Einführ"), + ("fuehrun", "führun"), + ("Fuehrun", "Führun"), + ("fuehrt", "führt"), + ("fuehren", "führen"), + ("Fuehren", "Führen"), + ("verfuegb", "verfügb"), + ("Verfuegb", "Verfügb"), + ("unterstuetz", "unterstütz"), + ("Unterstuetz", "Unterstütz"), + ("nuetzlich", "nützlich"), + ("Nuetzlich", "Nützlich"), + ("Schluess", "Schlüss"), + ("schluess", "schlüss"), + ("wuerde", "würde"), + ("Wuerde", "Würde"), + ("wuerden", "würden"), + ("MUESSEN", "MÜSSEN"), + ("muessen", "müssen"), + ("Muessen", "Müssen"), + ("muess", "müss"), + ("Muess", "Müss"), + ("KOENNEN", "KÖNNEN"), + ("koennen", "können"), + ("Koennen", "Können"), + ("koenn", "könn"), + ("Koenn", "Könn"), + ("natuerli", "natürli"), + ("Natuerli", "Natürli"), + ("tatsaechli", "tatsächli"), + ("Tatsaechli", "Tatsächli"), + ("aehnlich", "ähnlich"), + ("Aehnlich", "Ähnlich"), + ("standardmaessig", "standardmäßig"), + ("Standardmaessig", "Standardmäßig"), + ("gleichmaessig", "gleichmäßig"), + ("Gleichmaessig", "Gleichmäßig"), + ("zugaengli", "zugängli"), + ("Zugaengli", "Zugängli"), + ("uebersicht", "übersicht"), + ("Uebersicht", "Übersicht"), + ("uebersetzun", "übersetzun"), + ("Uebersetzun", "Übersetzun"), + ("uebernahme", "übernahme"), + ("Uebernahme", "Übernahme"), + ("uebernehm", "übernehm"), + ("Uebernehm", "Übernehm"), + ("hoeher", "höher"), + ("Hoeher", "Höher"), + ("pruefen", "prüfen"), + ("Pruefen", "Prüfen"), + ("prueft", "prüft"), + ("Prueft", "Prüft"), + ("Pruefung", "Prüfung"), + ("pruefung", "prüfung"), + ("pruef", "prüf"), + ("Pruef", "Prüf"), + ("ueber", "über"), + ("Ueber", "Über"), + ("fuer", "für"), + # ö + ("oeffn", "öffn"), + ("Oeffn", "Öffn"), + ("loescht", "löscht"), + ("Loescht", "Löscht"), + ("loeschen", "löschen"), + ("Loeschen", "Löschen"), + ("loesung", "lösung"), + ("Loesung", "Lösung"), + ("moegli", "mögli"), + ("Moegli", "Mögli"), + ("moeglich", "möglich"), + ("Moeglich", "Möglich"), + ("noetig", "nötig"), + ("Noetig", "Nötig"), + ("hoer", "hör"), # gehör, höher + ("Hoer", "Hör"), +] + +# Regex that splits a line into "preserve" tokens and replaceable text. +# Order matters: longer / more specific tokens first. +TOKENIZER = re.compile( + r""" + ( `[^`\n]*` ) # inline code: `...` + | ( !?\[[^\]]*\]\([^)]*\) ) # full markdown link [label](target) + | ( ) # HTML comment + """, + re.VERBOSE | re.DOTALL, +) + + +def transform_text(text: str) -> str: + """Apply substitutions to non-preserved spans only.""" + for needle, replacement in SUBSTITUTIONS: + text = text.replace(needle, replacement) + return text + + +def transform_line(line: str) -> str: + """Tokenise a line into [preserved | text | preserved | text | ...] and replace only text segments.""" + out: list[str] = [] + pos = 0 + for match in TOKENIZER.finditer(line): + # Replaceable run before the preserved span + if match.start() > pos: + out.append(transform_text(line[pos : match.start()])) + out.append(match.group(0)) # keep preserved span verbatim + pos = match.end() + # Tail after last preserved span + if pos < len(line): + out.append(transform_text(line[pos:])) + return "".join(out) + + +def transform_file(content: str) -> str: + """Walk lines, skip fenced code blocks, transform the rest line-by-line.""" + out_lines: list[str] = [] + in_fence = False + fence_marker = "" + + for line in content.splitlines(keepends=True): + stripped = line.lstrip() + + if in_fence: + out_lines.append(line) + if stripped.startswith(fence_marker): + in_fence = False + fence_marker = "" + continue + + # Detect fenced code start (``` or ~~~) + if stripped.startswith("```"): + in_fence = True + fence_marker = "```" + out_lines.append(line) + continue + if stripped.startswith("~~~"): + in_fence = True + fence_marker = "~~~" + out_lines.append(line) + continue + + out_lines.append(transform_line(line)) + + return "".join(out_lines) + + +def main(argv: list[str]) -> int: + args = list(argv[1:]) + dry_run = False + check = False + while args and args[0].startswith("--"): + flag = args.pop(0) + if flag == "--dry-run": + dry_run = True + elif flag == "--check": + check = True + elif flag == "--": + break + else: + print(f"Unknown flag: {flag}", file=sys.stderr) + return 2 + + if not args: + print(__doc__.strip(), file=sys.stderr) + return 2 + + changed_files: list[Path] = [] + for raw in args: + path = Path(raw) + if not path.is_file(): + print(f"Skipping (not a file): {path}", file=sys.stderr) + continue + original = path.read_text(encoding="utf-8") + transformed = transform_file(original) + if transformed != original: + changed_files.append(path) + if dry_run or check: + # Brief summary; full diff is what `git diff` shows after a real run. + added = sum(1 for c in transformed if c in "äöüÄÖÜß") - sum( + 1 for c in original if c in "äöüÄÖÜß" + ) + print(f"WOULD CHANGE {path} (+{added} umlauts)") + else: + path.write_text(transformed, encoding="utf-8") + print(f"updated {path}") + + if check and changed_files: + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/docs/explanation-architektur.md b/docs/explanation-architektur.md index 8ede343..f646ea2 100644 --- a/docs/explanation-architektur.md +++ b/docs/explanation-architektur.md @@ -115,7 +115,7 @@ flowchart TD - In `pages/**` und `templates/**` sind inline `` ohne `src` verboten. - Seiteninitialisierung liegt in dedizierten ESM-Page-Modulen unter `web/js/pages/*`. - Pro Seite wird Konfiguration per `` bereitgestellt und im Modul über `readPageConfig(...)` gelesen. -- In `pages/**` und `templates/**` muessen alle JS-`src` (eigene und Vendor) ueber `assetVersion('...js...')` laufen. +- In `pages/**` und `templates/**` müssen alle JS-`src` (eigene und Vendor) über `assetVersion('...js...')` laufen. ## Mindestchecks vor Merge diff --git a/docs/explanation-di-container.md b/docs/explanation-di-container.md index 56cf648..4d61cb2 100644 --- a/docs/explanation-di-container.md +++ b/docs/explanation-di-container.md @@ -103,6 +103,6 @@ $meinService = app(\MintyPHP\Service\MeinNeuerService::class); den konkreten Service direkt registrieren und per `app()` holen. - Der Container lebt **pro HTTP-Anfrage** — er wird in `web/index.php` initialisiert und über `setAppContainer()` im globalen State abgelegt. -- In CLI-Commands wird der Container separat initialisiert (ueber die Runtime-Bootstrap-Klassen unter `core/Console/Support/`). +- In CLI-Commands wird der Container separat initialisiert (über die Runtime-Bootstrap-Klassen unter `core/Console/Support/`). - In `core/Service/**` außerhalb von `*Factory.php` niemals `new ...Factory()`, `new ...Service()` oder `new ...Repository()` direkt instanziieren. diff --git a/docs/explanation-einstellungen-speicherung.md b/docs/explanation-einstellungen-speicherung.md index 2c97545..eaaa3a0 100644 --- a/docs/explanation-einstellungen-speicherung.md +++ b/docs/explanation-einstellungen-speicherung.md @@ -53,7 +53,7 @@ Das ist oft erwartbar, solange es um nicht-gecachte Keys geht. Prüfregel: - Geht es um `appSetting(...)`-Keys? Dann Datei-Cache relevant. -- Geht es um SMTP/SSO/API-Details? Dann DB ist massgeblich. +- Geht es um SMTP/SSO/API-Details? Dann DB ist maßgeblich. ## Betriebs-Hinweis diff --git a/docs/explanation-session-management.md b/docs/explanation-session-management.md index f95ddee..18d43a1 100644 --- a/docs/explanation-session-management.md +++ b/docs/explanation-session-management.md @@ -6,7 +6,7 @@ Letzte Aktualisierung: 2026-03-14 Vollstaendige Erklaerung des Session-Lifecycle: Wann wird ein User abgemeldet, wann greift der Remember-Token, wie bleiben Frontend und Server synchron. -## Session-Lifecycle (Uebersicht) +## Session-Lifecycle (Übersicht) ``` Login (Passwort / SSO) @@ -35,7 +35,7 @@ Jeder Request (web/index.php) | Idle | 30 Min | 5 Min – 24 Std | Ja, bei jeder Aktivitaet | `session_idle_timeout_minutes` | | Absolute | 8 Std | 1 Std – 72 Std | Nein, nie | `session_absolute_timeout_hours` | -Pruefung in `web/index.php` (bei jedem Request): +Prüfung in `web/index.php` (bei jedem Request): ``` Idle: (now - last_activity) > idle_timeout → Timeout @@ -67,7 +67,7 @@ Quelle: `web/js/components/app-session-warning.js` Problem ohne Keepalive: User scrollt 29 Min auf einer Seite → JS zeigt "aktiv", Server sagt "idle". -Loesung: Alle 5 Minuten prueft ein Intervall ob seit dem letzten Sync Interaktion stattfand. Falls ja → `POST /admin/session-ping/data` → Server-Timer zurueckgesetzt. +Lösung: Alle 5 Minuten prüft ein Intervall ob seit dem letzten Sync Interaktion stattfand. Falls ja → `POST /admin/session-ping/data` → Server-Timer zurueckgesetzt. | Szenario | Keepalive-Ping? | |----------|-----------------| @@ -100,12 +100,12 @@ DB: user_remember_tokens └─ last_used ``` -Selector und Token sind getrennt: Selector fuer schnellen DB-Lookup, Token-Hash fuer timing-sichere Validierung. Kein Klartext-Token in der DB. +Selector und Token sind getrennt: Selector für schnellen DB-Lookup, Token-Hash für timing-sichere Validierung. Kein Klartext-Token in der DB. ### Auto-Login-Ablauf 1. Kein aktiver Session-User → Remember-Cookie lesen -2. Rate-Limit pruefen (IP nicht blockiert?) +2. Rate-Limit prüfen (IP nicht blockiert?) 3. Selector → DB-Lookup 4. Token → `hash_equals(SHA256)` Verify 5. User aktiv? Token nicht abgelaufen? @@ -125,7 +125,7 @@ Quelle: `core/Service/Auth/RememberMeRateLimiter.php` - Fail-open: Bei Memcached-Ausfall wird nicht blockiert - Erfolgreicher Auto-Login setzt Counter zurueck -Siehe `/docs/howto-anfragelimits.md` fuer alle Rate-Limits. +Siehe `/docs/howto-anfragelimits.md` für alle Rate-Limits. ## Zusammenspiel Absolute Timeout + Remember-Token @@ -137,7 +137,7 @@ Login → 8h Absolute Timeout → Session endet └─ NEIN → Login-Seite ``` -Solange der Remember-Token lebt (Default 30 Tage), bekommt der User nach Ablauf des Absolute-Timeout automatisch eine neue Session. Der Uebergang ist nahtlos (kein Flash, kein Login-Screen). +Solange der Remember-Token lebt (Default 30 Tage), bekommt der User nach Ablauf des Absolute-Timeout automatisch eine neue Session. Der Übergang ist nahtlos (kein Flash, kein Login-Screen). Das bedeutet: Mit aktivem Remember-Token ist die effektive Session-Dauer nicht 8 Stunden, sondern bis zu 30 Tage. Das ist by-design, sollte aber bei Compliance-Anforderungen (z. B. echte Re-Authentifizierung nach X Stunden) beruecksichtigt werden. @@ -148,9 +148,9 @@ Das bedeutet: Mit aktivem Remember-Token ist die effektive Session-Dauer nicht 8 | `httponly` | `true` | Kein JS-Zugriff (XSS-Schutz) | | `samesite` | `Lax` | CSRF-Schutz bei Cross-Site-Navigation | | `secure` | dynamisch | `true` bei HTTPS, `false` bei HTTP (Dev) | -| `path` | `/` | Gueltig fuer gesamte Domain | +| `path` | `/` | Gueltig für gesamte Domain | -Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime::isSecure()`). In Produktion muss HTTPS ueber Nginx erzwungen werden (Redirect 80→443 + HSTS). +Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime::isSecure()`). In Produktion muss HTTPS über Nginx erzwungen werden (Redirect 80→443 + HSTS). ## Audit-Events @@ -165,7 +165,7 @@ Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime: | Komponente | Pfad | |------------|------| -| Timeout-Pruefung | `web/index.php` | +| Timeout-Prüfung | `web/index.php` | | AuthService | `core/Service/Auth/AuthService.php` | | RememberMeService | `core/Service/Auth/RememberMeService.php` | | RememberMeRateLimiter | `core/Service/Auth/RememberMeRateLimiter.php` | diff --git a/docs/howto-anfragelimits.md b/docs/howto-anfragelimits.md index 75006df..0307153 100644 --- a/docs/howto-anfragelimits.md +++ b/docs/howto-anfragelimits.md @@ -78,4 +78,4 @@ Unterschied zu den DB-basierten Limits oben: Memcached statt `request_rate_limit 1. API ohne Token >120 Requests/min gegen `/api/v1/*` -> `429` erwartet. 2. Web-Login mit falschem Passwort >5 pro E-Mail+IP -> `429` erwartet. 3. API-Login mit falschen Credentials wiederholt -> `429` erwartet. -4. Remember-Cookie mit falschem Token >5 pro IP -> Auto-Login blockiert, Cookie geloescht. +4. Remember-Cookie mit falschem Token >5 pro IP -> Auto-Login blockiert, Cookie gelöscht. diff --git a/docs/howto-betriebscheck-doctor.md b/docs/howto-betriebscheck-doctor.md index 52a1282..48c48e5 100644 --- a/docs/howto-betriebscheck-doctor.md +++ b/docs/howto-betriebscheck-doctor.md @@ -4,9 +4,9 @@ Letzte Aktualisierung: 2026-03-19 ## Ziel -`php bin/console doctor` ist der schnelle Gesundheitscheck fuer eine Instanz. +`php bin/console doctor` ist der schnelle Gesundheitscheck für eine Instanz. -Er prueft unter anderem: +Er prüft unter anderem: - ENV-Validierung (Pflichtkeys + Formate) - AppContainer-Bootstrap @@ -35,13 +35,13 @@ docker compose exec php php bin/console doctor - `0`: keine harten Fehler - `1`: mindestens ein `FAIL`-Check -`WARN` fuehrt nicht zu Exit `1`, sollte aber geprueft werden. +`WARN` führt nicht zu Exit `1`, sollte aber geprüft werden. ## Typischer Einsatz im Betrieb 1. Direkt nach Neuinstallation / Deployment. 2. Bei 4xx/5xx-Symptomen als erster Schritt. -3. Nach Konfigurations- oder RBAC-Aenderungen. +3. Nach Konfigurations- oder RBAC-Änderungen. ## Beispielausgabe diff --git a/docs/howto-dokumentation-erweitern.md b/docs/howto-dokumentation-erweitern.md index 4205d4f..1b1625c 100644 --- a/docs/howto-dokumentation-erweitern.md +++ b/docs/howto-dokumentation-erweitern.md @@ -16,8 +16,8 @@ Neue Seiten schnell, konsistent und langfristig wartbar ergänzen. Die Dokumentation folgt dem Diataxis-Modell mit genau vier Quadranten in dieser Reihenfolge: -1. **Tutorials** — Lernorientierte Schritt-fuer-Schritt-Anleitungen -2. **How-to Guides** — Aufgabenorientierte Anleitungen fuer konkrete Ziele +1. **Tutorials** — Lernorientierte Schritt-für-Schritt-Anleitungen +2. **How-to Guides** — Aufgabenorientierte Anleitungen für konkrete Ziele 3. **Explanation** — Verstaendnisorientierte Hintergrunderklaerungen 4. **Reference** — Informationsorientierte Fakten und Nachschlagewerke diff --git a/docs/howto-gitea-required-checks.md b/docs/howto-gitea-required-checks.md index 7eac6d7..11eae38 100644 --- a/docs/howto-gitea-required-checks.md +++ b/docs/howto-gitea-required-checks.md @@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-04-01 ## Ziel -QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-Blocker zu aktivieren. +QA-Pflichtchecks für CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-Blocker zu aktivieren. ## Enthaltene Basis @@ -14,7 +14,7 @@ QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-B ## Was `qa-required` abdeckt -`bin/qa-required.sh` fuehrt die aktuell blockenden Gates aus: +`bin/qa-required.sh` führt die aktuell blockenden Gates aus: - `QG-001` PHPUnit - `QG-002` PHPStan @@ -25,14 +25,14 @@ QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-B ## Phase-1 Setup (noch nicht blockend) -1. Sicherstellen, dass der Gitea-Runner Docker + Docker Compose ausfuehren darf. -2. Workflow-Datei nach `.gitea/workflows/qa-required.yaml` uebernehmen. -3. PR gegen `main` oeffnen und pruefen, dass Job `qa-required` gruen laeuft. +1. Sicherstellen, dass der Gitea-Runner Docker + Docker Compose ausführen darf. +2. Workflow-Datei nach `.gitea/workflows/qa-required.yaml` übernehmen. +3. PR gegen `main` öffnen und prüfen, dass Job `qa-required` gruen laeuft. 4. Branch Protection noch **nicht** auf "required" setzen. ## Phase-2 Aktivierung (blockend) -1. Branch-Protection fuer `main` aktivieren. +1. Branch-Protection für `main` aktivieren. 2. Statuscheck `qa-required` als required markieren. 3. Optional: weitere Jobs ergaenzen (z. B. nightly/extended Checks), aber nur `qa-required` blockend setzen. @@ -40,4 +40,4 @@ QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-B - `QG-005` (Browser-Smoke) bleibt manuell/non-blocking. - `QG-007` (composer-unused) bleibt periodisch/non-blocking. -- Fuer lokale Ausfuehrung: `bin/dev qa-required` bzw. `bin/dev qa-extended`. +- Fuer lokale Ausführung: `bin/dev qa-required` bzw. `bin/dev qa-extended`. diff --git a/docs/howto-globale-suche.md b/docs/howto-globale-suche.md index bc7112f..bd4041d 100644 --- a/docs/howto-globale-suche.md +++ b/docs/howto-globale-suche.md @@ -47,7 +47,7 @@ Provider: - `mapPreviewItem()` - `mapResultItem()` 5. Bei Modul-Resources: Provider-Klasse in `module.php` unter `search_resources` registrieren. -6. i18n-Labels pruefen. +6. i18n-Labels prüfen. ## Wichtige Regeln diff --git a/docs/howto-lokale-entwicklung.md b/docs/howto-lokale-entwicklung.md index 51546b0..816ad86 100644 --- a/docs/howto-lokale-entwicklung.md +++ b/docs/howto-lokale-entwicklung.md @@ -12,7 +12,7 @@ Kompakter Tagesworkflow für Entwicklung, Tests und schema-nahe Änderungen. bin/dev init ``` -`bin/dev init` ist nicht-destruktiv und fuehrt aus: +`bin/dev init` ist nicht-destruktiv und führt aus: 1. `.env` aus `.env.example` erstellen (falls fehlend) 2. `docker compose up --build -d` @@ -36,17 +36,17 @@ docker compose restart php nginx ## Module-Sync -Nach Aenderungen an Modulen, Manifesten oder `APP_ENABLED_MODULES`: +Nach Änderungen an Modulen, Manifesten oder `APP_ENABLED_MODULES`: ```bash docker compose exec php php bin/console module:sync ``` -Dieser Befehl fuehrt automatisch aus: `migrate` → `permissions-sync` → `build` → `assets-sync`. +Dieser Befehl führt automatisch aus: `migrate` → `permissions-sync` → `build` → `assets-sync`. -Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist der Sync noetig. +Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist der Sync nötig. -Alle verfuegbaren CLI-Kommandos: `php bin/console list` (siehe `/docs/reference-cli-commands.md`). +Alle verfügbaren CLI-Kommandos: `php bin/console list` (siehe `/docs/reference-cli-commands.md`). Alle Dev-Orchestrator-Kommandos: `bin/dev --help`. ## Schema-Stand @@ -70,7 +70,7 @@ docker compose exec php vendor/bin/phpunit docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress ``` -Bei Modul-/Manifest-Aenderungen zusaetzlich: +Bei Modul-/Manifest-Änderungen zusaetzlich: ```bash docker compose exec php php bin/console module:sync diff --git a/docs/howto-modul-erstellen.md b/docs/howto-modul-erstellen.md index 2501315..f9ab516 100644 --- a/docs/howto-modul-erstellen.md +++ b/docs/howto-modul-erstellen.md @@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-26 ## Ziel -Schritt-fuer-Schritt Anleitung: vom leeren Verzeichnis zum lauffaehigen Modul mit Route, Permission, UI-Slot und Test. +Schritt-für-Schritt Anleitung: vom leeren Verzeichnis zum lauffaehigen Modul mit Route, Permission, UI-Slot und Test. ## Voraussetzungen @@ -54,7 +54,7 @@ return [ ]; ``` -Alternative: `APP_ENABLED_MODULES` Umgebungsvariable (ueberschreibt die Datei). +Alternative: `APP_ENABLED_MODULES` Umgebungsvariable (überschreibt die Datei). ## Schritt 3: Manifest konfigurieren @@ -138,7 +138,7 @@ final class MeinModulContainerRegistrar implements ContainerRegistrar } ``` -Ohne diese Registrierung wird die Policy von `ModuleClassResolver` ignoriert und die Permission-Pruefung fuer UI-Slots schlaegt fehl (Slot wird nicht angezeigt). +Ohne diese Registrierung wird die Policy von `ModuleClassResolver` ignoriert und die Permission-Prüfung für UI-Slots schlaegt fehl (Slot wird nicht angezeigt). ## Schritt 5: Erste Seite anlegen @@ -171,14 +171,14 @@ Datei `modules/mein-modul/pages/mein-modul/index(default).phtml`: docker compose exec php php bin/console module:sync ``` -Dieser Befehl fuehrt automatisch aus: +Dieser Befehl führt automatisch aus: 1. `module:migrate` — SQL-Migrationen anwenden 2. `module:permissions-sync` — Permissions registrieren 3. `module:build` — Seiten-Symlinks erstellen 4. `module:assets-sync` — CSS/JS-Assets veroeffentlichen -Nach jedem Manifest-Aenderung erneut ausfuehren. +Nach jedem Manifest-Änderung erneut ausführen. ## Schritt 7: Validieren @@ -186,7 +186,7 @@ Nach jedem Manifest-Aenderung erneut ausfuehren. docker compose exec php php bin/console module:validate mein-modul ``` -Prueft: Manifest-Syntax, Klassen-Existenz, Namespace-Konventionen, Verzeichnisstruktur. +Prüft: Manifest-Syntax, Klassen-Existenz, Namespace-Konventionen, Verzeichnisstruktur. ## Schritt 8: Testen @@ -195,7 +195,7 @@ docker compose exec php vendor/bin/phpunit --filter=MeinModul docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon modules/mein-modul/ ``` -Architektur-Tests (pruefen automatisch Namespace-Isolation, Session-Key-Prefix, Manifest-Contract): +Architektur-Tests (prüfen automatisch Namespace-Isolation, Session-Key-Prefix, Manifest-Contract): ```bash docker compose exec php vendor/bin/phpunit tests/Architecture/ @@ -203,7 +203,7 @@ docker compose exec php vendor/bin/phpunit tests/Architecture/ --- -## Erweitern: Haeufige Erweiterungspunkte +## Erweitern: Häufige Erweiterungspunkte ### UI-Slot: Sidebar-Tab @@ -278,11 +278,11 @@ Fuer globale Assets (auf jeder Seite) stattdessen `layout.head_style` oder `runt Interface: `core/App/Module/Contracts/SessionProvider.php` (Methoden: `populate()`, `clear()`). -**Session-Key-Konvention:** `module.mein-modul.*` (wird per Architektur-Test geprueft). +**Session-Key-Konvention:** `module.mein-modul.*` (wird per Architektur-Test geprüft). ### Layout-Kontext -`LayoutContextProvider` implementieren — liefert Daten fuer Templates bei jedem Page-Render: +`LayoutContextProvider` implementieren — liefert Daten für Templates bei jedem Page-Render: ```php 'layout_context_providers' => [ @@ -292,7 +292,7 @@ Interface: `core/App/Module/Contracts/SessionProvider.php` (Methoden: `populate( Interface: `core/App/Module/Contracts/LayoutContextProvider.php` (Methode: `provide()`). -**Key-Konvention:** Top-Level-Keys muessen namespaced sein: `mein-modul.nav`, nicht `nav`. +**Key-Konvention:** Top-Level-Keys müssen namespaced sein: `mein-modul.nav`, nicht `nav`. ### Event-Listener @@ -308,7 +308,7 @@ Interface: `core/App/Module/Contracts/EventListener.php` (Methode: `handle(strin ### Scheduler-Job -Siehe `/docs/howto-geplante-aufgaben.md` und `modules/audit/module.php` fuer Beispiele. +Siehe `/docs/howto-geplante-aufgaben.md` und `modules/audit/module.php` für Beispiele. ### Modul-eigene Datenbank @@ -317,16 +317,16 @@ Siehe `/docs/howto-geplante-aufgaben.md` und `modules/audit/module.php` fuer Bei ``` SQL-Dateien unter `modules/mein-modul/db/updates/` — idempotent (IF NOT EXISTS, ON DUPLICATE KEY). -Ausgefuehrt ueber `php bin/console module:migrate`. +Ausgeführt über `php bin/console module:migrate`. -### Uebersetzungen +### Übersetzungen ```php 'i18n_path' => 'i18n', ``` Dateien: `modules/mein-modul/i18n/default_de.json`, `modules/mein-modul/i18n/default_en.json`. -Schluessel werden per `t('key')` aufgeloest — identisch zu Core-Translations. +Schlüssel werden per `t('key')` aufgeloest — identisch zu Core-Translations. ### Abhaengigkeit von anderem Modul @@ -334,7 +334,7 @@ Schluessel werden per `t('key')` aufgeloest — identisch zu Core-Translations. 'requires' => ['notifications'], ``` -Nicht-deklarierte Cross-Module-Imports sind verboten und werden per Architektur-Test geprueft. +Nicht-deklarierte Cross-Module-Imports sind verboten und werden per Architektur-Test geprüft. --- @@ -351,13 +351,13 @@ Nicht-deklarierte Cross-Module-Imports sind verboten und werden per Architektur- - [ ] Session-Keys verwenden `module..*` Prefix - [ ] Keine Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`) im Modul-Code -## Haeufige Fehler +## Häufige Fehler -| Problem | Ursache | Loesung | +| Problem | Ursache | Lösung | |---|---|---| | Sidebar-Tab/UI-Slot wird nicht angezeigt | AuthorizationPolicy nicht im Container registriert | Policy in ContainerRegistrar mit `PermissionService` registrieren | -| 404 auf Modul-Route | `module:sync` nicht ausgefuehrt | `php bin/console module:sync` | +| 404 auf Modul-Route | `module:sync` nicht ausgeführt | `php bin/console module:sync` | | Permission existiert nicht | Permission nicht in Manifest deklariert | `permissions`-Array in `module.php` ergaenzen, dann `module:sync` | | CSS/JS werden nicht geladen | Assets nicht veroeffentlicht | `php bin/console module:assets-sync` oder `module:sync` | -| RuntimeException: fingerprint mismatch | Build veraltet nach Manifest-Aenderung | `php bin/console module:sync` | +| RuntimeException: fingerprint mismatch | Build veraltet nach Manifest-Änderung | `php bin/console module:sync` | | Namespace-Fehler in Tests | Modul-Klasse in Core-Namespace | Alle Klassen unter `MintyPHP\Module\\*` | diff --git a/docs/howto-request-input-validation.md b/docs/howto-request-input-validation.md index f425299..4a1063c 100644 --- a/docs/howto-request-input-validation.md +++ b/docs/howto-request-input-validation.md @@ -2,15 +2,15 @@ Letzte Aktualisierung: 2026-03-06 -Kurzstandard fuer neue Actions/Endpoints. +Kurzstandard für neue Actions/Endpoints. ## Regeln -- Input immer ueber `requestInput()`. +- Input immer über `requestInput()`. - Validierungsfehler intern immer als `FormErrors`. - API-Validation immer mit `ApiResponse::validationFromFormErrors(...)`. - Web-Templates bekommen kompakte Fehlerlisten (`$errors`) aus `toFlatList()`. -- `Flash` ist fuer Redirect-/Outcome-Meldungen (z. B. Success) gedacht, nicht als primaerer Validation-Container. +- `Flash` ist für Redirect-/Outcome-Meldungen (z. B. Success) gedacht, nicht als primaerer Validation-Container. - Bei Redirect-POST-Formen: `FormErrors` intern sammeln und erst am Redirect-Rand transportieren (z. B. `flashFormErrors(...)`). ## Web-Beispiel (Action) diff --git a/docs/index.md b/docs/index.md index 2935500..f2ecda0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,20 +15,20 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert: 4. `/docs/tutorial-04-architektur-request-flow.md` - Request-Flow, Schichtmodell, Do/Don't. 5. `/docs/tutorial-05-erste-aenderung-ui.md` - - Erste sichere UI-Aenderung im Admin-Bereich. + - Erste sichere UI-Änderung im Admin-Bereich. 6. `/docs/tutorial-06-erste-aenderung-backend.md` - - Erste Backend-/Service-/Repository-Aenderung. + - Erste Backend-/Service-/Repository-Änderung. 7. `/docs/tutorial-07-security-tenant-scope.md` - Sicherheitsgrundlagen, Tenant-Scope, Pflichtchecks. 8. `/docs/tutorial-08-api-erweitern.md` - - API-Aenderung sauber mit OpenAPI und Tests umsetzen. + - API-Änderung sauber mit OpenAPI und Tests umsetzen. 9. `/docs/tutorial-09-advanced-scheduler-sso.md` - Fortgeschrittene Themen: Scheduler, Lifecycle, SSO. ## How-to Guides - `/docs/howto-erste-aenderung.md` - - Schritt-fuer-Schritt durch die erste Codeaenderung. + - Schritt-für-Schritt durch die erste Codeänderung. - `/docs/howto-globale-suche.md` - Neue Resource in der globalen Suche integrieren. - `/docs/howto-importe.md` @@ -44,7 +44,7 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert: - `/docs/howto-rbac-permissions-playbook.md` - RBAC-Rechte sauber erweitern (neue Permission, neue Ability, UI/API-Faelle). - `/docs/howto-request-input-validation.md` - - Einheitliches Request/Input- und Validation-Muster fuer Web + API. + - Einheitliches Request/Input- und Validation-Muster für Web + API. - `/docs/howto-docker-lokal.md` - Lokaler Docker-Betrieb. - `/docs/howto-docker-produktiv.md` @@ -52,15 +52,15 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert: - `/docs/howto-betriebscheck-doctor.md` - Schneller Systemcheck mit `php bin/console doctor`. - `/docs/howto-fehlerbehebung.md` - - Haeufige Fehler und schnelle Loesungen. + - Häufige Fehler und schnelle Lösungen. - `/docs/howto-lokale-entwicklung.md` - - Tages-Workflow fuer Entwicklung und Checks. + - Tages-Workflow für Entwicklung und Checks. - `/docs/howto-modul-erstellen.md` - Neues Modul erstellen: Scaffold, Manifest, Route, Permission, UI-Slot, Test. - `/docs/howto-gitea-required-checks.md` - - Gitea-Workflow fuer `qa-required` vorbereiten (Phase 1 enforcement-ready). + - Gitea-Workflow für `qa-required` vorbereiten (Phase 1 enforcement-ready). - `/docs/howto-dokumentation-erweitern.md` - - Regeln fuer konsistente, wachsende Doku. + - Regeln für konsistente, wachsende Doku. ## Explanation @@ -75,7 +75,7 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert: - `/docs/explanation-einstellungen-speicherung.md` - Warum Settings in DB + Datei-Cache koexistieren. - `/docs/explanation-docker-betrieb.md` - - Uebersicht und Entscheidungshilfe fuer Dev/Prod. + - Übersicht und Entscheidungshilfe für Dev/Prod. ## Reference @@ -88,9 +88,9 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert: - `/docs/reference-konventionen.md` - Projektweite Konventionen (kurz und verbindlich). - `/docs/reference-core-standards.md` - - Regeln speziell fuer `core/**`. + - Regeln speziell für `core/**`. - `/docs/reference-benutzer-lifecycle-policy.md` - - Policy- und Laufzeitreferenz fuer User Lifecycle. + - Policy- und Laufzeitreferenz für User Lifecycle. - `/docs/reference-frontend-css.md` - CSS-Schichtsystem und Namenskonventionen. - `/docs/reference-frontend-javascript.md` @@ -98,13 +98,13 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert: - `/docs/reference-entwickler-checkliste.md` - Definition of Done vor Merge. - `/docs/reference-codex-prompts.md` - - Standard-Prompts fuer Skill-basierte Planung und Implementierung. + - Standard-Prompts für Skill-basierte Planung und Implementierung. - `/docs/reference-extension-readiness.md` - - Freigabe-Checkliste fuer weitere Module auf Basis des bestehenden Modul-Contracts. + - Freigabe-Checkliste für weitere Module auf Basis des bestehenden Modul-Contracts. - `/docs/reference-cli-commands.md` - Alle CLI-Kommandos (`php bin/console`), Bootstrap-Helfer, Anleitung neue Kommandos. - `/docs/reference-module-manifest-contract.md` - - Verbindlicher Runtime- und Manifest-Contract fuer Module (V1.1). + - Verbindlicher Runtime- und Manifest-Contract für Module (V1.1). - `/docs/reference-notifications-module.md` - - Verbindliche Referenz fuer Notifications (Events, Guardrails, Dedupe, Bell-Vertrag, Tests). + - Verbindliche Referenz für Notifications (Events, Guardrails, Dedupe, Bell-Vertrag, Tests). - Agent-Workflow (Rollen, State-Machine, Contracts): siehe `/.agents/workflow.md` diff --git a/docs/reference-cli-commands.md b/docs/reference-cli-commands.md index eec0a51..1ab83ce 100644 --- a/docs/reference-cli-commands.md +++ b/docs/reference-cli-commands.md @@ -4,13 +4,13 @@ Letzte Aktualisierung: 2026-04-01 ## Einstiegspunkt -Alle CLI-Kommandos laufen ueber einen einzigen Einstiegspunkt: +Alle CLI-Kommandos laufen über einen einzigen Einstiegspunkt: ```bash php bin/console [argumente] [optionen] ``` -Uebersicht aller verfuegbaren Kommandos: +Übersicht aller verfügbaren Kommandos: ```bash php bin/console list @@ -32,9 +32,9 @@ Fuehrt den vollstaendigen Runtime-Sync aus: `db-migrate` → `migrate` → `perm docker compose exec php php bin/console module:sync ``` -Noetig nach jeder Aenderung an Modulen, Manifesten, Routen oder `APP_ENABLED_MODULES` — und nach jedem `git pull`, der Schema-Updates unter `db/updates/*.sql` mitbringt. +Nötig nach jeder Änderung an Modulen, Manifesten, Routen oder `APP_ENABLED_MODULES` — und nach jedem `git pull`, der Schema-Updates unter `db/updates/*.sql` mitbringt. -Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist dieser Befehl die Loesung. +Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist dieser Befehl die Lösung. Maschinenlesbar: @@ -52,7 +52,7 @@ Jede `db/updates/*.sql` MUSS idempotent sein (`CREATE TABLE IF NOT EXISTS`, `INS docker compose exec php php bin/console db:migrate ``` -`module:sync` ruft den Befehl als ersten Schritt automatisch auf. Direktaufruf nuetzlich, wenn nur DB-Updates gewuenscht sind ohne Module-Build. +`module:sync` ruft den Befehl als ersten Schritt automatisch auf. Direktaufruf nützlich, wenn nur DB-Updates gewuenscht sind ohne Module-Build. Status-Anzeige (kein Schreibzugriff): @@ -60,7 +60,7 @@ Status-Anzeige (kein Schreibzugriff): docker compose exec php php bin/console db:migrate --status ``` -Listet `applied:` und `pending:` separat — nuetzlich beim Debugging veralteter Schemata. +Listet `applied:` und `pending:` separat — nützlich beim Debugging veralteter Schemata. ### module:migrate @@ -103,7 +103,7 @@ docker compose exec php php bin/console module:deactivate --confirm docker compose exec php php bin/console module:deactivate --dry-run ``` -Das Modul muss nicht in der Aktivliste stehen. `--dry-run` validiert den Handler ohne Ausfuehrung. +Das Modul muss nicht in der Aktivliste stehen. `--dry-run` validiert den Handler ohne Ausführung. ### scheduler:run @@ -117,7 +117,7 @@ Der Docker-Scheduler-Service ruft dieses Kommando automatisch alle 60 Sekunden a ### module:validate -Validiert Manifest, Klassen und Struktur eines Moduls. Prueft JSON-Schema-Compliance des `module.php`, Namespace-Konventionen, Interface-Implementierungen, Permission-Key-Formate und Verzeichnisstruktur. +Validiert Manifest, Klassen und Struktur eines Moduls. Prüft JSON-Schema-Compliance des `module.php`, Namespace-Konventionen, Interface-Implementierungen, Permission-Key-Formate und Verzeichnisstruktur. ```bash docker compose exec php php bin/console module:validate @@ -128,7 +128,7 @@ docker compose exec php php bin/console module:validate --all ### make:module -Erzeugt die vollstaendige Verzeichnisstruktur fuer ein neues Modul inkl. Manifest, ContainerRegistrar-Stub, AuthorizationPolicy-Stub und leeren Verzeichnissen. +Erzeugt die vollstaendige Verzeichnisstruktur für ein neues Modul inkl. Manifest, ContainerRegistrar-Stub, AuthorizationPolicy-Stub und leeren Verzeichnissen. ```bash docker compose exec php php bin/console make:module @@ -144,7 +144,7 @@ Fuehrt System-Gesundheitschecks aus (ENV, DB, RBAC, Scheduler-Heartbeat). docker compose exec php php bin/console doctor ``` -Siehe `/docs/howto-betriebscheck-doctor.md` fuer Details. +Siehe `/docs/howto-betriebscheck-doctor.md` für Details. Maschinenlesbar: @@ -168,15 +168,15 @@ bin/dev qa-extended ``` `bin/dev console ...` delegiert intern auf `docker compose exec -T php php bin/console ...`. -`bin/dev qa` ist ein Alias fuer `bin/dev qa-required`. +`bin/dev qa` ist ein Alias für `bin/dev qa-required`. ## Neue Kommandos anlegen 1. Klasse in `core/Console/Commands/` erstellen, die `MintyPHP\Console\Command` erweitert. 2. `name()`, `description()` und `execute()` implementieren. -3. Optional: `usage()` fuer `--help`-Ausgabe ueberschreiben. +3. Optional: `usage()` für `--help`-Ausgabe überschreiben. -Das Kommando wird automatisch erkannt — kein manuelles Registrieren noetig. +Das Kommando wird automatisch erkannt — kein manuelles Registrieren nötig. Beispiel: @@ -204,5 +204,5 @@ Die `Command`-Basisklasse stellt Helfer bereit: | Methode | Zweck | |---|---| -| `$this->bootstrapApp($channel)` | App-Bootstrap fuer Nicht-Modul-Kommandos | +| `$this->bootstrapApp($channel)` | App-Bootstrap für Nicht-Modul-Kommandos | | `$this->projectRoot()` | Gibt den absoluten Projekt-Root-Pfad zurueck | diff --git a/docs/reference-codex-prompts.md b/docs/reference-codex-prompts.md index 619eb2c..c1741ef 100644 --- a/docs/reference-codex-prompts.md +++ b/docs/reference-codex-prompts.md @@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-09 ## Ziel -Wiederverwendbare Prompt-Muster fuer konsistente Planung und Implementierung mit den Skills `core-guardrails` und `starterkit-planner`. +Wiederverwendbare Prompt-Muster für konsistente Planung und Implementierung mit den Skills `core-guardrails` und `starterkit-planner`. ## Prompt: Implementierung (strict) diff --git a/docs/reference-entwickler-checkliste.md b/docs/reference-entwickler-checkliste.md index f933e71..43d42bb 100644 --- a/docs/reference-entwickler-checkliste.md +++ b/docs/reference-entwickler-checkliste.md @@ -45,9 +45,9 @@ Kurze Definition of Done vor Merge. - [ ] Runtime-Komponenten folgen Contract `init(root, config) -> { destroy() }` - [ ] Runtime-Komponenten enthalten keinen eigenen `DOMContentLoaded`-/Sideeffect-Auto-Init - [ ] Listener/Timer/Observer aus Runtime-Komponenten werden in `destroy()` sauber abgebaut -- [ ] Runtime-Konfiguration liegt in `page-config-app-components` (default) bzw. `page-config-login-components` (login) und wird ueber `readPageConfig(...)` gelesen +- [ ] Runtime-Konfiguration liegt in `page-config-app-components` (default) bzw. `page-config-login-components` (login) und wird über `readPageConfig(...)` gelesen - [ ] Host-gebundene Runtime-Komponenten haben explizite `data-app-component`-Hosts im Markup -- [ ] Global-Utilities ohne natuerliches Host-Element sind explizit runtime-global registriert (`scope: 'global'`) +- [ ] Global-Utilities ohne natürliches Host-Element sind explizit runtime-global registriert (`scope: 'global'`) - [ ] Service-Auflösung in `pages/**`/`templates/**`/`core/Support/**` nur via `app(Foo::class)` - [ ] Keine `new ...Factory()` in `core/Service/**` außerhalb `*Factory.php` - [ ] Keine direkten `new ...Service()`, `new ...Gateway()`, `new ...Repository()` in `core/Service/**` außerhalb `*Factory.php` @@ -74,12 +74,12 @@ Kurze Definition of Done vor Merge. - [ ] `docker compose exec php vendor/bin/phpunit` zweimal hintereinander in identischer Umgebung (beide Runs gruen) - [ ] `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress` - [ ] `docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php` -- [ ] bei Modul-/Manifest-/Routen-Aenderungen: `APP_ENABLED_MODULES='' php bin/console module:sync` -- [ ] bei Modul-/Manifest-/Routen-Aenderungen: `APP_ENABLED_MODULES='addressbook,bookmarks' php bin/console module:sync` +- [ ] bei Modul-/Manifest-/Routen-Änderungen: `APP_ENABLED_MODULES='' php bin/console module:sync` +- [ ] bei Modul-/Manifest-/Routen-Änderungen: `APP_ENABLED_MODULES='addressbook,bookmarks' php bin/console module:sync` - [ ] Runtime-Sync erzeugt Step-Summary (`migrate`, `permissions-sync`, `build`, `assets-sync`) und `vendor_warnings_ignored=` -- [ ] Keine First-party CLI-Warnings/Notices/Deprecations im Runtime-Sync (Vendor-Warnings sind nur temporaer toleriert und muessen gezaehlt sichtbar sein) -- [ ] bei Docs-/Skills-Aenderungen: `docker compose exec php vendor/bin/phpunit tests/Architecture/CodexSkillReferenceContractTest.php` -- [ ] `bin/docs-link-check.sh` (QG-008, scannt standardmaessig ohne `.agents/runs/**`) +- [ ] Keine First-party CLI-Warnings/Notices/Deprecations im Runtime-Sync (Vendor-Warnings sind nur temporaer toleriert und müssen gezaehlt sichtbar sein) +- [ ] bei Docs-/Skills-Änderungen: `docker compose exec php vendor/bin/phpunit tests/Architecture/CodexSkillReferenceContractTest.php` +- [ ] `bin/docs-link-check.sh` (QG-008, scannt standardmäßig ohne `.agents/runs/**`) - [ ] `bin/docs-drift-check.sh` (QG-008-Zusatz, blockt Legacy-Referenzen + fehlenden Setup-Vertrag) - [ ] `bin/codex-skills-sync.sh --check` (QG-009) - [ ] bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors) diff --git a/docs/reference-extension-readiness.md b/docs/reference-extension-readiness.md index a9a1bc2..df334c5 100644 --- a/docs/reference-extension-readiness.md +++ b/docs/reference-extension-readiness.md @@ -4,13 +4,13 @@ Letzte Aktualisierung: 2026-03-18 ## Ziel -Verbindliche Vorbedingungen fuer weitere eigenstaendige Module auf dem bestehenden Modul-System festhalten. +Verbindliche Vorbedingungen für weitere eigenstaendige Module auf dem bestehenden Modul-System festhalten. ## Kanonische Quelle Normativer Manifest- und Runtime-Contract: `/docs/reference-module-manifest-contract.md`. -Diese Readiness-Doku ist bewusst kurz und verweist fuer Felddefinitionen/Guards immer auf den Manifest-Contract. +Diese Readiness-Doku ist bewusst kurz und verweist für Felddefinitionen/Guards immer auf den Manifest-Contract. ## Readiness-Checkliste vor Modul 2+ @@ -21,17 +21,17 @@ Diese Readiness-Doku ist bewusst kurz und verweist fuer Felddefinitionen/Guards - `module.php` validiert gegen den kanonischen Contract (`permissions`, `scheduler_jobs`, `ui_slots`, `routes`). - Route-/Slot-/Layout-Guards laufen fail-fast. 3. **Security + Scope absichern** - - AuthZ/RBAC serverseitig pruefen. - - Tenant-Scope serverseitig pruefen. + - AuthZ/RBAC serverseitig prüfen. + - Tenant-Scope serverseitig prüfen. - POST-Mutationen mit CSRF absichern. 4. **Runtime-Hygiene absichern** - `php bin/console module:sync` laeuft reproduzierbar mit standardisierter Step-Summary. - Keine First-party CLI-Warnings/Notices/Deprecations; Vendor-Rauschen wird nur gezaehlt/reportet. 5. **Testbarkeit und Gates** - - Architektur- und Domain-Tests fuer neue Logik ergaenzen. + - Architektur- und Domain-Tests für neue Logik ergaenzen. - `phpunit` und `phpstan` als Pflicht-Gates gruen. 6. **Daten- und Betriebsfaehigkeit** - - Schema-/Datenaenderungen fuer Bestandsinstallationen idempotent in `db/updates/*.sql`. + - Schema-/Datenänderungen für Bestandsinstallationen idempotent in `db/updates/*.sql`. - Logs/Audit ohne unredacted PII/Secrets. ## Derzeit Out of Scope @@ -39,7 +39,7 @@ Diese Readiness-Doku ist bewusst kurz und verweist fuer Felddefinitionen/Guards - Eigener DB-Server oder Netzwerk-Microservice je Modul. - Externe Drittanbieter-Module mit Legacy-Kompatibilitaet. -## Verfuegbare Core-Services fuer Module +## Verfügbare Core-Services für Module JS-seitig: diff --git a/docs/reference-frontend-css.md b/docs/reference-frontend-css.md index 8317ec1..58f7c4e 100644 --- a/docs/reference-frontend-css.md +++ b/docs/reference-frontend-css.md @@ -88,6 +88,6 @@ Regel: Vendor-Overrides nur für Bibliotheks-Selektoren; projektspezifische UI-S ## Module-CSS Token-Regel 1. Modul-CSS nutzt primär Core-Tokens (`--app-*`) statt eigener Farbwerte. -2. Modul-spezifische Variablen sind als Alias erlaubt, muessen aber auf Core-Tokens mappen. +2. Modul-spezifische Variablen sind als Alias erlaubt, müssen aber auf Core-Tokens mappen. 3. Keine Legacy-/Phantom-Tokens (`--app-text`, `--app-hover`, `--app-border-light`) neu einführen. 4. Harte Hex-Fallbacks nur als Ausnahmefall, nicht als Standard. diff --git a/docs/reference-frontend-javascript.md b/docs/reference-frontend-javascript.md index 84931b1..786ce45 100644 --- a/docs/reference-frontend-javascript.md +++ b/docs/reference-frontend-javascript.md @@ -48,14 +48,14 @@ Empfohlenes Muster: - `destroy()` muss alle Listener/Timer/Observer abbauen. - Hybrid Host-Policy: - Host-gebundene UI-Komponenten nutzen explizite `data-app-component`-Hosts im Markup. - - Tabs sind host-gebunden und laufen ausschliesslich ueber `data-app-component="tabs"`. - - Globale Utilities ohne natuerliches Host-Element werden runtime-global (`scope: 'global'`) registriert, aber mit demselben Lifecycle-Contract. - - Root-Strict gilt fuer host-gebundene Komponenten: keine `document.querySelector`-Fallback-Pfade. - - Projektseitige Custom-Globals auf `window.*` sind verboten; Komponenten kommunizieren ueber Core-Channels. + - Tabs sind host-gebunden und laufen ausschliesslich über `data-app-component="tabs"`. + - Globale Utilities ohne natürliches Host-Element werden runtime-global (`scope: 'global'`) registriert, aber mit demselben Lifecycle-Contract. + - Root-Strict gilt für host-gebundene Komponenten: keine `document.querySelector`-Fallback-Pfade. + - Projektseitige Custom-Globals auf `window.*` sind verboten; Komponenten kommunizieren über Core-Channels. ## UI Storage Contract -- Persistente UI-States laufen fuer Runtime-Komponenten ueber `web/js/core/app-ui-storage.js`. +- Persistente UI-States laufen für Runtime-Komponenten über `web/js/core/app-ui-storage.js`. - Storage-Keys sind namespaced (`namespace:version:scope:*`) statt ungeordnet verteilt. - Hard-Cut-Policy: keine Legacy-Key-Fallbacks und kein Legacy-Key-Sync in migrierten Runtime-Komponenten/Core-Modulen. diff --git a/docs/reference-konfiguration.md b/docs/reference-konfiguration.md index 911f38f..f97362e 100644 --- a/docs/reference-konfiguration.md +++ b/docs/reference-konfiguration.md @@ -5,7 +5,7 @@ Letzte Aktualisierung: 2026-04-01 Alle Konfiguration erfolgt über Umgebungsvariablen in der `.env`-Datei. Vorlage: `.env.example` — niemals echte Credentials committen. -Setup-Vertrag (Source of Truth): `config/config.php` ist im Repository getrackt und liest alle Werte über `$envString()`/`$envInt()`/`$envBool()` aus den ENV-Variablen. Diese Seite und `web/index.php` sind die massgeblichen Referenzen dafuer. +Setup-Vertrag (Source of Truth): `config/config.php` ist im Repository getrackt und liest alle Werte über `$envString()`/`$envInt()`/`$envBool()` aus den ENV-Variablen. Diese Seite und `web/index.php` sind die maßgeblichen Referenzen dafür. --- diff --git a/docs/reference-konventionen.md b/docs/reference-konventionen.md index b90c435..1e3405d 100644 --- a/docs/reference-konventionen.md +++ b/docs/reference-konventionen.md @@ -53,7 +53,7 @@ Letzte Aktualisierung: 2026-03-24 - 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.). +- UI-Integration nur über 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. @@ -63,5 +63,5 @@ Letzte Aktualisierung: 2026-03-24 - `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/console module:sync` +- bei Modul-/Manifest-Änderungen: `docker compose exec php php bin/console module:sync` - bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors) diff --git a/docs/reference-module-manifest-contract.md b/docs/reference-module-manifest-contract.md index b130059..ce58a0b 100644 --- a/docs/reference-module-manifest-contract.md +++ b/docs/reference-module-manifest-contract.md @@ -4,11 +4,11 @@ Letzte Aktualisierung: 2026-03-25 ## Ziel -Verbindlicher Contract fuer `modules/*/module.php`, damit Module zur Runtime deterministisch geladen und validiert werden. +Verbindlicher Contract für `modules/*/module.php`, damit Module zur Runtime deterministisch geladen und validiert werden. ## Status -Dieses Dokument ist die kanonische (normative) Quelle fuer Manifest-, Runtime- und Guard-Regeln des Modul-Systems. +Dieses Dokument ist die kanonische (normative) Quelle für Manifest-, Runtime- und Guard-Regeln des Modul-Systems. `/docs/reference-extension-readiness.md` referenziert diesen Contract und dupliziert keine Felddefinitionen. ## JSON-Schema-Enforcement @@ -25,8 +25,8 @@ Ein Manifest muss sowohl: ## Namespace-Konvention -Alle PHP-Klassen eines Moduls muessen den Namespace `MintyPHP\Module\\*` verwenden. -Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`, `MintyPHP\Support\*`) sind fuer Modul-Code verboten. +Alle PHP-Klassen eines Moduls müssen den Namespace `MintyPHP\Module\\*` verwenden. +Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`, `MintyPHP\Support\*`) sind für Modul-Code verboten. Verzeichnis-Layout: @@ -75,8 +75,8 @@ Der `ModuleAutoloader` registriert daraus den absoluten Pfad `modules//i18n/ ``` - `key` und `description` sind Pflichtfelder. -- Runtime-Sync erfolgt ueber `php bin/console module:sync`. -- `module:sync` fuehrt diesen Sync automatisch aus. +- Runtime-Sync erfolgt über `php bin/console module:sync`. +- `module:sync` führt diesen Sync automatisch aus. ## `scheduler_jobs` Contract @@ -101,8 +101,8 @@ Der `ModuleAutoloader` registriert daraus den absoluten Pfad `modules//i18n/ ], ``` -- Manifest ist Source of Truth fuer Job-Metadaten und Defaults. -- Handler werden zur Laufzeit container-resolvable fuer `execute(...)` geladen. +- Manifest ist Source of Truth für Job-Metadaten und Defaults. +- Handler werden zur Laufzeit container-resolvable für `execute(...)` geladen. ## `ui_slots` Contract (V1.2) @@ -118,15 +118,15 @@ Neue generische Slot-Typen: Abgrenzung CSS: - `layout.head_style` = global auf allen Seiten. -- `asset_groups` = seiten-/kontextbezogen ueber `style_groups`. +- `asset_groups` = seiten-/kontextbezogen über `style_groups`. ## Guard-Regeln - Route-Kollisionen sind fail-fast: - Modul vs Modul auf `target` und `path`. - Modul vs Core auf `path` beim Router-Boot. -- Layout-Provider duerfen reservierte Core-Keys nicht ueberschreiben (`moduleSlots`, `csrfKey`, `currentTenant`, ...). -- Layout-Provider-Top-Level-Keys muessen namespaced sein (`.`). +- Layout-Provider duerfen reservierte Core-Keys nicht überschreiben (`moduleSlots`, `csrfKey`, `currentTenant`, ...). +- Layout-Provider-Top-Level-Keys müssen namespaced sein (`.`). ## Runtime-Fingerprint @@ -141,16 +141,16 @@ Methoden: `ModuleRuntimePageBuilder::expectedFingerprint()`, `readFingerprint()` ## API-Channel-Isolation -API-Requests (`api/`-Prefix) ueberspringen den gesamten Web-Session-Flow: +API-Requests (`api/`-Prefix) überspringen den gesamten Web-Session-Flow: - Kein `Session::start()`, kein Cookie-Setting, kein CSRF-Token - Kein Remember-Me, kein Session-Timeout, kein Tenant-UI-Refresh -- API-Auth erfolgt ueber `ApiBootstrap.php` (Bearer-Token) +- API-Auth erfolgt über `ApiBootstrap.php` (Bearer-Token) - `AccessControl` listet `api/` als always-public ## Standard-Runbook -`php bin/console module:sync` fuehrt in fester Reihenfolge aus: +`php bin/console module:sync` führt in fester Reihenfolge aus: 1. `module:migrate` 2. `module:permissions-sync` diff --git a/docs/reference-notifications-module.md b/docs/reference-notifications-module.md index a228631..bbfebed 100644 --- a/docs/reference-notifications-module.md +++ b/docs/reference-notifications-module.md @@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-25 ## Ziel -Referenz fuer das Modul `notifications`: Event-Registrierung, Erzeugungsregeln, Guardrails, Frontend-Vertrag und Testbarkeit. +Referenz für das Modul `notifications`: Event-Registrierung, Erzeugungsregeln, Guardrails, Frontend-Vertrag und Testbarkeit. ## Scope v1 @@ -15,7 +15,7 @@ Referenz fuer das Modul `notifications`: Event-Registrierung, Erzeugungsregeln, - `user.activated` - `user.deactivated` - `user.assignment_changed` -- Dedupe fuer diese Typen mit 30 Minuten Fenster. +- Dedupe für diese Typen mit 30 Minuten Fenster. ## Modul-Verkabelung @@ -25,7 +25,7 @@ Kanonische Quelle: `modules/notifications/module.php` - mappt Eventtyp -> Listenerklasse + Methode `handle`. - `ui_slots` - `topbar.right_item`: Bell-Template - - `layout.head_style`: Modul-CSS fuer Topbar + Dropdown + - `layout.head_style`: Modul-CSS für Topbar + Dropdown - `runtime.component`: Bell-JS (`initNotificationBell`) - `permissions` - `notifications.view` @@ -45,9 +45,9 @@ Kanonische Quelle: `modules/notifications/module.php` 5. `NotificationRepository` persistiert in `user_notifications`. 6. Bell-Endpunkte lesen tenant-scoped Daten und aktualisieren den Session-`unread_count`. -## Producer-Contract (fuer Core + andere Module) +## Producer-Contract (für Core + andere Module) -Stabile Erzeugung erfolgt ueber: +Stabile Erzeugung erfolgt über: - `MintyPHP\Module\Notifications\Service\NotificationMessage` - `MintyPHP\Module\Notifications\Service\NotificationService::createFromMessage(...)` @@ -78,7 +78,7 @@ $notificationService->createForTenantAdminUsersFromMessage( ); ``` -Plain/Fallback-Erzeugung bleibt moeglich mit `NotificationMessage::plain(...)`. +Plain/Fallback-Erzeugung bleibt möglich mit `NotificationMessage::plain(...)`. ## Datenvertrag Notification @@ -90,7 +90,7 @@ Persistierter Kernvertrag: - `link` (nullable string) - `data` (nullable JSON) -Erweiterung fuer locale-neutrale Texte: +Erweiterung für locale-neutrale Texte: - `data.__message.title_key` (string) - `data.__message.title_params` (array) @@ -111,20 +111,20 @@ Dedupe-Metadaten (intern): - Alle Bell-Endpunkte erzwingen: - Login - Ability `notifications.view` -- POST-Endpunkte (`mark-read`, `delete`) pruefen CSRF. +- POST-Endpunkte (`mark-read`, `delete`) prüfen CSRF. - Tenant-Scope wird serverseitig aus `current_tenant` erzwungen. - SQL ausschliesslich im Repository (`NotificationRepository`), Service nur Orchestrierung. ## Guardrails (Frontend) - Endpunkte werden mit App-Base-URL gebaut (kein harter Root-Pfad). -- Fehlerpfade laufen ueber zentrale Telemetrie (`warn_once`). +- Fehlerpfade laufen über zentrale Telemetrie (`warn_once`). - A11y-Klickzeilen im Dropdown sind lokal gestylt, damit globale `[role="button"]` Regeln nicht durchschlagen. -- Default-`details/summary`-Chevron wird pro Komponente ueber `data-summary-chevron="none"` deaktiviert. +- Default-`details/summary`-Chevron wird pro Komponente über `data-summary-chevron="none"` deaktiviert. ## Template/Partial Best Practice -- Core-Partials immer ueber `templatePath('partials/...')` einbinden. +- Core-Partials immer über `templatePath('partials/...')` einbinden. - Keine fragilen relativen Tiefenpfade auf Core-Templates verwenden. - Modulinterne Templates bleiben lokal relativ zum Modul. @@ -138,22 +138,22 @@ Dedupe-Metadaten (intern): ### Unit -- Listener-Tests fuer alle Core-5 Typen: +- Listener-Tests für alle Core-5 Typen: - Empfaengerregeln - Actor-Exclusion - ungultige/leere Payloads -- Service-Tests fuer Dedupe (created vs suppressed) -- Policy-Tests fuer `notifications.view` +- Service-Tests für Dedupe (created vs suppressed) +- Policy-Tests für `notifications.view` ### Integration/Flow -- End-to-End fuer create/delete/activate/deactivate/assignment-change. -- Bell-Endpunkte mit Tenant-Scope und Permission-Pruefung. +- End-to-End für create/delete/activate/deactivate/assignment-change. +- Bell-Endpunkte mit Tenant-Scope und Permission-Prüfung. - Bulk-Flows dispatchen konsistent. ### Manueller Smoke 1. Zwei Admins im selben Tenant, einer als Actor. -2. Actor fuehrt User-Aktion aus. +2. Actor führt User-Aktion aus. 3. Zweiter Admin sieht Bell-Badge + Listeneintrag. 4. Wiederholung innerhalb 30 Minuten erzeugt kein Duplikat. diff --git a/tests/README.md b/tests/README.md index 8dd80d7..475cced 100644 --- a/tests/README.md +++ b/tests/README.md @@ -3,8 +3,8 @@ ## Ziel Die Tests sind nach Schutzwirkung organisiert, nicht nur nach technischer Ebene. -Wichtige Architektur- und Security-Invarianten sollen schnell gezielt laufen koennen, -ohne dass jede Aenderung immer die komplette Suite im Kopf behalten muss. +Wichtige Architektur- und Security-Invarianten sollen schnell gezielt laufen können, +ohne dass jede Änderung immer die komplette Suite im Kopf behalten muss. ## PHPUnit-Suiten @@ -16,42 +16,42 @@ ohne dass jede Aenderung immer die komplette Suite im Kopf behalten muss. - `Architecture`: alle Architektur-Contracts unter `tests/Architecture/`. - `ArchitectureCore`: Core-Boundaries, Module-/Repository-Contracts, Taxonomie- und Sync-Contracts. - `ArchitectureSecurity`: CSRF, PRG, File-Storage, Crypto, Logging sowie AuthZ-nahe Contracts. -- `ArchitectureUI`: UI-Contracts fuer Listen, Detailseiten, Runtime-Komponenten und A11y. +- `ArchitectureUI`: UI-Contracts für Listen, Detailseiten, Runtime-Komponenten und A11y. - `ArchitectureModules`: modulbezogene Struktur- und Isolations-Contracts. -- `ArchitectureMeta`: Agent-/Skill-/Meta-Contracts fuer das Repository-Setup. +- `ArchitectureMeta`: Agent-/Skill-/Meta-Contracts für das Repository-Setup. -## Regeln fuer neue Architecture-Tests +## Regeln für neue Architecture-Tests - Nur stabile Invarianten testen, keine einmaligen Migrationsdetails. - Guards oder Risiken explizit abdecken, zum Beispiel `GR-CORE-*`, `GR-SEC-*`, `GR-TEST-*`. - Keine Duplikate neben bereits breiten Contracts anlegen. -- String-Assertions nur verwenden, wenn kein robusterer Contract moeglich ist. +- String-Assertions nur verwenden, wenn kein robusterer Contract möglich ist. - Monolithische Sammeltests vermeiden; lieber kleine thematische Contracts. ## Delete vs. Refactor vs. Keep - `keep`: testet einen echten plattformweiten Contract oder Security-Guard. - `refactor`: Schutz ist wichtig, aber der Test ist zu datei-, markup- oder implementation-detailnah. -- `delete`: dupliziert bestehende Schutzwirkung oder prueft nur historische Altlasten. +- `delete`: dupliziert bestehende Schutzwirkung oder prüft nur historische Altlasten. -## Regeln fuer neue Service-Tests +## Regeln für neue Service-Tests - Services auf Guards, Orchestrierung, Normalisierung, Fehlerpfade und Seiteneffekte testen. -- Keine eigenen Tests fuer reine `find/list/get/set`-Delegation ohne zusaetzliche Regel. +- Keine eigenen Tests für reine `find/list/get/set`-Delegation ohne zusaetzliche Regel. - Thin Wrapper auf gemeinsame Primitive zentral testen, nicht pro Gateway erneut. - Mockability-, Reflection- und Interface-Existenz-Tests ohne Risiko-Schutz vermeiden. - Kleine Normalisierungs-Matrizen mit DataProvidern oder zusammengezogenen Contract-Dateien verdichten. ## Typische Low-Value-Muster -- Gateway-Test prueft nur `encrypt/decrypt` erneut, obwohl das Basisverhalten schon zentral abgesichert ist. -- Test bestaetigt nur, dass ein Service eins zu eins an Repository oder Gateway weiterreicht. -- Test prueft nur Methodensignatur, Reflection oder dass eine Klasse mockbar ist. +- Gateway-Test prüft nur `encrypt/decrypt` erneut, obwohl das Basisverhalten schon zentral abgesichert ist. +- Test bestätigt nur, dass ein Service eins zu eins an Repository oder Gateway weiterreicht. +- Test prüft nur Methodensignatur, Reflection oder dass eine Klasse mockbar ist. - Mehrere Minidateien decken denselben Settings-/Fallback-Mechanismus mit identischem Mock-Muster ab. -## Naechste Audit-Kandidaten +## Nächste Audit-Kandidaten - methodenweiser Low-value-Pass in `tests/Service/User/UserAccountServiceTest.php` - methodenweiser Low-value-Pass in `tests/Service/Org/DepartmentServiceTest.php` - methodenweiser Low-value-Pass in `tests/Service/Access/RoleServiceTest.php` -- verbleibende kleine Settings-Gateway-Tests auf weitere Verdichtung pruefen +- verbleibende kleine Settings-Gateway-Tests auf weitere Verdichtung prüfen