forked from fa/breadcrumb-the-shire
docs: replace ASCII umlaut fallbacks with proper äöüß across all .md
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) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: core-guardrails
|
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
|
# Core Guardrails
|
||||||
@@ -12,21 +12,21 @@ Durchgaengig dieselben technischen Grenzen durchsetzen, damit Core robust, wartb
|
|||||||
## Verbindliche Regeln
|
## Verbindliche Regeln
|
||||||
|
|
||||||
1. MUST Layering einhalten (`pages` -> `Service` -> `Repository`, Templates nur Rendering).
|
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/**`).
|
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 ueber `$viewAuth` steuern.
|
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 ueber Repository).
|
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 fuer Listen/Detailseiten nutzen (Wrapper, Partials, globaler Confirm-Dialog statt `window.confirm`, inklusive globaler Grid-Standards fuer rowInteraction/pageSize).
|
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 fuer relevante Frontend-Warnings/Fetch-Fehler).
|
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 ausfuehren und Ergebnis transparent berichten.
|
7. MUST Quality-Gates ausführen und Ergebnis transparent berichten.
|
||||||
8. MUST bei Konflikten den regelkonformen Weg waehlen oder den Konflikt als Blocker markieren.
|
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.
|
9. MUST NOT Extension-Architektur erfinden; dieses Thema ist aktuell Out of Scope.
|
||||||
|
|
||||||
## Vorgehen je Aufgabe
|
## Vorgehen je Aufgabe
|
||||||
|
|
||||||
1. Scope bestimmen (`core`, `ui`, `api`, `mixed`).
|
1. Scope bestimmen (`core`, `ui`, `api`, `mixed`).
|
||||||
2. Vorhandene Contracts zuerst suchen, dann wiederverwenden.
|
2. Vorhandene Contracts zuerst suchen, dann wiederverwenden.
|
||||||
3. Aenderung minimal halten, keine Seiteneffekte ohne Grund.
|
3. Änderung minimal halten, keine Seiteneffekte ohne Grund.
|
||||||
4. Nach Aenderung die relevanten Gates ausfuehren.
|
4. Nach Änderung die relevanten Gates ausführen.
|
||||||
5. Rest-Risiken explizit benennen.
|
5. Rest-Risiken explizit benennen.
|
||||||
|
|
||||||
## Out of Scope
|
## Out of Scope
|
||||||
|
|||||||
@@ -16,18 +16,18 @@
|
|||||||
|
|
||||||
## Input / Validation
|
## 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.
|
2. MUST NOT `$_POST`, `$_GET`, `$_FILES`, `REQUEST_METHOD` in `pages/**` verwenden.
|
||||||
3. MUST NOT `$_SESSION`, `$_SERVER`, `$_COOKIE`, `$_ENV` in `pages/**` direkt verwenden.
|
3. MUST NOT `$_SESSION`, `$_SERVER`, `$_COOKIE`, `$_ENV` in `pages/**` direkt verwenden.
|
||||||
4. MUST Form-Validation ueber `FormErrors` fuehren.
|
4. MUST Form-Validation über `FormErrors` führen.
|
||||||
5. MUST API-Validation-Fehler ueber `ApiResponse::validationFromFormErrors(...)` ausgeben.
|
5. MUST API-Validation-Fehler über `ApiResponse::validationFromFormErrors(...)` ausgeben.
|
||||||
6. MUST NOT `ApiResponse::readJsonBody(...)` in `pages/api/v1/**` verwenden.
|
6. MUST NOT `ApiResponse::readJsonBody(...)` in `pages/api/v1/**` verwenden.
|
||||||
|
|
||||||
## List-Data Endpoints
|
## List-Data Endpoints
|
||||||
|
|
||||||
1. MUST `pages/**/data().php` als GET-only Endpunkte umsetzen (`gridRequireGetRequest()`).
|
1. MUST `pages/**/data().php` als GET-only Endpunkte umsetzen (`gridRequireGetRequest()`).
|
||||||
2. MUST Query-Filter ueber `gridParseFilters(...)` + `filter-schema.php` normalisieren.
|
2. MUST Query-Filter über `gridParseFilters(...)` + `filter-schema.php` normalisieren.
|
||||||
3. MUST NOT Query-Filter inline/parallele Alias-Parser in `data().php` neu einfuehren.
|
3. MUST NOT Query-Filter inline/parallele Alias-Parser in `data().php` neu einführen.
|
||||||
|
|
||||||
## Security / API
|
## Security / API
|
||||||
|
|
||||||
@@ -35,11 +35,11 @@
|
|||||||
2. MUST Tenant-Scope serverseitig erzwingen.
|
2. MUST Tenant-Scope serverseitig erzwingen.
|
||||||
3. MUST CSRF auf POST-Endpunkten vor Body-Verarbeitung verifizieren.
|
3. MUST CSRF auf POST-Endpunkten vor Body-Verarbeitung verifizieren.
|
||||||
4. MUST NOT PII/Secrets unredacted in Logs oder Audit-Metadata schreiben.
|
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.
|
6. MUST extern UUID-first bleiben.
|
||||||
7. MUST API-Fehler konsistent halten (`error`, optional `errors`).
|
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`
|
- Harte Repo-Gates: `tests/Architecture/CoreStarterkitContractTest.php`
|
||||||
|
|||||||
@@ -2,69 +2,69 @@
|
|||||||
|
|
||||||
## Listen-Standard
|
## Listen-Standard
|
||||||
|
|
||||||
1. MUST Listen ueber `initStandardListPage(...)` initialisieren.
|
1. MUST Listen über `initStandardListPage(...)` initialisieren.
|
||||||
2. MUST Filter-Toolbar ueber zentrale Helper/Partials rendern.
|
2. MUST Filter-Toolbar über zentrale Helper/Partials rendern.
|
||||||
3. MUST aktive Chips/Drawer-Verhalten ueber Standard-Contracts laufen lassen.
|
3. MUST aktive Chips/Drawer-Verhalten über Standard-Contracts laufen lassen.
|
||||||
4. MUST NOT direkt `gridFiltersFromSchema(...)` oder `initListFilterExperience(...)` in Listen-Templates verwenden.
|
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.
|
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).
|
7. MUST pageSize-Standard beibehalten (10/25/50/100, Toolbar rechts, URL > localStorage > default).
|
||||||
|
|
||||||
## Detailseiten-Standard
|
## Detailseiten-Standard
|
||||||
|
|
||||||
1. MUST Hauptformular mit `data-standard-detail-form="1"` markieren.
|
1. MUST Hauptformular mit `data-standard-detail-form="1"` markieren.
|
||||||
2. MUST Unsaved/Shortcut/Dirty-State ueber `initStandardDetailPage(...)` nutzen.
|
2. MUST Unsaved/Shortcut/Dirty-State über `initStandardDetailPage(...)` nutzen.
|
||||||
3. MUST Detail-Aktionen ueber Action-Policy-Contract (`data-detail-action-policy`, `data-detail-action-kind`, `data-detail-confirm-message`) steuern.
|
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.
|
4. MUST NOT inline `confirm(...)` (`onclick` / `onsubmit`) auf standardisierten Detailseiten nutzen.
|
||||||
|
|
||||||
## Confirm + Telemetry Standard
|
## 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.
|
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.
|
4. MUST NOT relevante UX-/Fehlerpfade nur als Console-Warnung implementieren.
|
||||||
|
|
||||||
## Frontend Page-Module Hard Cut
|
## Frontend Page-Module Hard Cut
|
||||||
|
|
||||||
1. MUST Seiteninitialisierung ueber dedizierte Module unter `web/js/pages/*` umsetzen.
|
1. MUST Seiteninitialisierung über dedizierte Module unter `web/js/pages/*` umsetzen.
|
||||||
2. MUST Page-Config ueber `script[type="application/json"]` + `readPageConfig(...)` bereitstellen/lesen.
|
2. MUST Page-Config über `script[type="application/json"]` + `readPageConfig(...)` bereitstellen/lesen.
|
||||||
3. MUST alle JS-`src` in `pages/**` und `templates/**` ueber `assetVersion('...js...')` laden.
|
3. MUST alle JS-`src` in `pages/**` und `templates/**` über `assetVersion('...js...')` laden.
|
||||||
4. MUST NOT inline `<script type="module">...</script>` in `pages/**` oder `templates/**` verwenden.
|
4. MUST NOT inline `<script type="module">...</script>` in `pages/**` oder `templates/**` verwenden.
|
||||||
|
|
||||||
## Component Lifecycle Runtime
|
## 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.
|
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.
|
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.
|
4. MUST Runtime-Konfiguration über Page-Config (`readPageConfig(...)`) beziehen, keine verteilten Ad-hoc-Globals.
|
||||||
5. MUST host-gebundene UI-Komponenten ueber explizite `data-app-component`-Hosts im Markup binden.
|
5. MUST host-gebundene UI-Komponenten über 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.
|
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
|
## Shared Partials
|
||||||
|
|
||||||
1. MUST Listen-Titlebar ueber `templates/partials/app-list-titlebar.phtml` rendern.
|
1. MUST Listen-Titlebar über `templates/partials/app-list-titlebar.phtml` rendern.
|
||||||
2. MUST List-Tabs ueber `templates/partials/app-list-tabs.phtml` rendern.
|
2. MUST List-Tabs über `templates/partials/app-list-tabs.phtml` rendern.
|
||||||
3. MUST Purge-Action ueber `templates/partials/app-list-purge-action.phtml` rendern.
|
3. MUST Purge-Action über `templates/partials/app-list-purge-action.phtml` rendern.
|
||||||
4. MUST Detail-Validation-Summary ueber `templates/partials/app-details-validation-summary.phtml` rendern.
|
4. MUST Detail-Validation-Summary über `templates/partials/app-details-validation-summary.phtml` rendern.
|
||||||
|
|
||||||
## RBAC in Templates
|
## 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.
|
2. MUST NOT `can('...')` in Templates verwenden.
|
||||||
|
|
||||||
## CSS Boundaries
|
## CSS Boundaries
|
||||||
|
|
||||||
1. MUST Styles moeglichst lokal in `web/css/components`, `web/css/layout` oder `web/css/pages` halten.
|
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 einfuehren.
|
2. MUST NOT globale unscoped Overrides ohne klaren Scope einführen.
|
||||||
3. MUST Vendor-Overrides nur in `web/css/vendor-overrides/**` pflegen.
|
3. MUST Vendor-Overrides nur in `web/css/vendor-overrides/**` pflegen.
|
||||||
4. MUST bestehende CSS-Variablen bevorzugen statt neue Inline-Farbwerte zu verteilen.
|
4. MUST bestehende CSS-Variablen bevorzugen statt neue Inline-Farbwerte zu verteilen.
|
||||||
|
|
||||||
## Komponenten in Formularen
|
## 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).
|
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).
|
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).
|
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.
|
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.
|
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.
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ Erwartung: jeweils `0`.
|
|||||||
|
|
||||||
## JS-Scope
|
## 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.
|
- Erwartung: keine neuen JS-Errors.
|
||||||
|
|
||||||
## Docs-/Skills-Gates (schnell)
|
## Docs-/Skills-Gates (schnell)
|
||||||
|
|
||||||
1. `bin/docs-link-check.sh`
|
1. `bin/docs-link-check.sh`
|
||||||
- prueft Doku-Links in `README.md`, `docs/**`, `.agents/skills/**` und `.agents/**`
|
- prüft Doku-Links in `README.md`, `docs/**`, `.agents/skills/**` und `.agents/**`
|
||||||
- `.agents/runs/**` ist standardmaessig ausgeschlossen (historische Artefakte)
|
- `.agents/runs/**` ist standardmäßig ausgeschlossen (historische Artefakte)
|
||||||
2. `bin/docs-drift-check.sh`
|
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`
|
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
|
## Berichtspflicht
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: starterkit-grid-standards
|
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
|
# Starterkit Grid Standards
|
||||||
@@ -18,18 +18,18 @@ GridJS-Listen projektweit einheitlich, zuganglich und wartbar halten.
|
|||||||
## Verbindliche Regeln
|
## Verbindliche Regeln
|
||||||
|
|
||||||
1. MUST `initStandardListPage(...)` als Standard nutzen (nur begruendete Ausnahmen direkt mit `createServerGrid(...)`).
|
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).
|
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).
|
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.
|
6. MUST NOT pro Seite eigene Row-Action-Hacks bauen, wenn der Factory-Contract ausreicht.
|
||||||
|
|
||||||
## Vorgehen
|
## 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.
|
2. Fehlende Standards zuerst zentral in der Factory loesen, danach nur minimale Seitenanpassungen.
|
||||||
3. UI/CSS nur als additive Erweiterung zu bestehenden Komponenten.
|
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
|
## Referenzen
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,19 @@
|
|||||||
## Bootstrap
|
## Bootstrap
|
||||||
|
|
||||||
1. `initStandardListPage({ grid, filters, hooks })` verwendet.
|
1. `initStandardListPage({ grid, filters, hooks })` verwendet.
|
||||||
2. `filterSchema` aus Server-Config uebergeben.
|
2. `filterSchema` aus Server-Config übergeben.
|
||||||
3. `urlSync` bewusst gesetzt.
|
3. `urlSync` bewusst gesetzt.
|
||||||
|
|
||||||
## Interaction
|
## Interaction
|
||||||
|
|
||||||
1. `rowDblClick.getUrl(...)` liefert stabile Ziel-URL oder leer.
|
1. `rowDblClick.getUrl(...)` liefert stabile Ziel-URL oder leer.
|
||||||
2. Keine Doppel-Action-Spalte (Factory auto-action vs explizite actions).
|
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
|
## Pagination + URL
|
||||||
|
|
||||||
1. Page-size Optionen nur `10/25/50/100`.
|
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.
|
3. Default-Werte erzeugen saubere URL.
|
||||||
|
|
||||||
## Filter UX
|
## Filter UX
|
||||||
@@ -26,5 +26,5 @@
|
|||||||
|
|
||||||
## Regression
|
## Regression
|
||||||
|
|
||||||
1. Sortierung, Selection/Bulk, Doppelklick unveraendert.
|
1. Sortierung, Selection/Bulk, Doppelklick unverändert.
|
||||||
2. Keine neuen Console Errors.
|
2. Keine neuen Console Errors.
|
||||||
|
|||||||
@@ -15,6 +15,6 @@
|
|||||||
|
|
||||||
## Verhalten
|
## Verhalten
|
||||||
|
|
||||||
1. Aenderung der Seitengroesse setzt Seite auf 1.
|
1. Änderung der Seitengroesse setzt Seite auf 1.
|
||||||
2. Sortierung/Filter bleiben erhalten.
|
2. Sortierung/Filter bleiben erhalten.
|
||||||
3. LocalStorage-Key pro Tabelle (path + dataUrl + container).
|
3. LocalStorage-Key pro Tabelle (path + dataUrl + container).
|
||||||
|
|||||||
@@ -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 `<a>`-Link gerendert.
|
1. Konfigurierbares Link-Column: Die primaere Datenspalte (z.B. Name, Beschreibung) wird als klickbarer `<a>`-Link gerendert.
|
||||||
2. Enter auf fokussierter Row loest dieselbe Navigation aus.
|
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.
|
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.
|
5. Rows ohne URL (z.B. fehlende Berechtigung) zeigen den Inhalt als Plain-Text ohne Link.
|
||||||
|
|
||||||
@@ -40,6 +40,6 @@ rowInteraction: {
|
|||||||
## Guardrails
|
## Guardrails
|
||||||
|
|
||||||
1. Keine globale Tab-Stop-Flut auf allen Rows.
|
1. Keine globale Tab-Stop-Flut auf allen Rows.
|
||||||
2. Fokusstil fuer Row und Link-Element sichtbar.
|
2. Fokusstil für Row und Link-Element sichtbar.
|
||||||
3. Explizite `actions.enabled: true` pro Seite darf Link-Column uebersteuern (eigene Action-Spalte).
|
3. Explizite `actions.enabled: true` pro Seite darf Link-Column übersteuern (eigene Action-Spalte).
|
||||||
4. Link-Column darf keine Spalte mit verschachtelten `<a>`-Elementen umwickeln (z.B. Avatar mit Lightbox).
|
4. Link-Column darf keine Spalte mit verschachtelten `<a>`-Elementen umwickeln (z.B. Avatar mit Lightbox).
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
---
|
---
|
||||||
name: starterkit-php-style-ci
|
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
|
# Starterkit PHP Style CI
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
Coding-Style pruefbar, reproduzierbar und regressionsarm machen.
|
Coding-Style prüfbar, reproduzierbar und regressionsarm machen.
|
||||||
|
|
||||||
## Wann verwenden
|
## Wann verwenden
|
||||||
|
|
||||||
1. Einfuehrung oder Nachschaerfung von Style-Regeln.
|
1. Einführung oder Nachschaerfung von Style-Regeln.
|
||||||
2. CI-Dry-Run fuer Style-Checks.
|
2. CI-Dry-Run für Style-Checks.
|
||||||
3. Aufraeumen grosser Style-Diff-Wellen.
|
3. Aufraeumen grosser Style-Diff-Wellen.
|
||||||
|
|
||||||
## Verbindliche Regeln
|
## 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`).
|
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 ausfuehren.
|
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).
|
3. MUST Style-Check vor Merge gruen halten (lokal und optional CI).
|
||||||
4. MUST nach groesseren Fixes mindestens `phpunit` und `phpstan` laufen lassen.
|
4. MUST nach groesseren Fixes mindestens `phpunit` und `phpstan` laufen lassen.
|
||||||
5. MUST NOT manuell Einzelstellen formatieren, wenn der Fixer sie zentral loesen kann.
|
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
|
## Workflow
|
||||||
|
|
||||||
1. Baseline erfassen: `vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose`.
|
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`.
|
2. Falls nötig fixen: `composer cs:fix`.
|
||||||
3. Diff fokussiert pruefen (Imports, Braces, Nebenwirkungen).
|
3. Diff fokussiert prüfen (Imports, Braces, Nebenwirkungen).
|
||||||
4. Qualitaetsgates laufen lassen.
|
4. Qualitaetsgates laufen lassen.
|
||||||
5. CI-Dry-Run konfigurieren oder validieren.
|
5. CI-Dry-Run konfigurieren oder validieren.
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
CI soll nur pruefen, nicht formatieren.
|
CI soll nur prüfen, nicht formatieren.
|
||||||
|
|
||||||
## Minimaler Check
|
## Minimaler Check
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php -
|
|||||||
## Erwartung
|
## Erwartung
|
||||||
|
|
||||||
1. Exit Code 0: Style konform.
|
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
|
## Hinweise
|
||||||
|
|
||||||
|
|||||||
@@ -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`).
|
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`.
|
2. Danach `cs:fix`.
|
||||||
3. Nur relevante Diffs uebernehmen, grosse Misch-Diffs vermeiden.
|
3. Nur relevante Diffs übernehmen, grosse Misch-Diffs vermeiden.
|
||||||
4. Anschliessend:
|
4. Anschliessend:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
---
|
---
|
||||||
name: starterkit-planner
|
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
|
# Starterkit Planner
|
||||||
|
|
||||||
## Ziel
|
## 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.
|
Bei Agent-Workflows muss der Plan maschinenlesbar in die Projekt-Contracts passen.
|
||||||
|
|
||||||
## Verbindliches Ausgabeformat
|
## Verbindliches Ausgabeformat
|
||||||
@@ -23,9 +23,9 @@ Bei Agent-Workflows muss der Plan maschinenlesbar in die Projekt-Contracts passe
|
|||||||
Wenn `.agents/` verwendet wird:
|
Wenn `.agents/` verwendet wird:
|
||||||
|
|
||||||
1. Plan muss dem Schema `.agents/contracts/planner.schema.json` entsprechen.
|
1. Plan muss dem Schema `.agents/contracts/planner.schema.json` entsprechen.
|
||||||
2. Success Criteria muessen stabile IDs tragen (`SC-001`, `SC-002`, ...).
|
2. Success Criteria müssen stabile IDs tragen (`SC-001`, `SC-002`, ...).
|
||||||
3. Success Criteria muessen so formuliert sein, dass Reviewer Acceptance sie direkt gegen `criterion_id` pruefen kann.
|
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 muessen aus den Katalogen kommen (`GR-*`, `QG-*`).
|
4. Guard- und Quality-Gate-IDs müssen aus den Katalogen kommen (`GR-*`, `QG-*`).
|
||||||
|
|
||||||
## Vorgehen
|
## Vorgehen
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Wenn `.agents/` verwendet wird:
|
|||||||
2. Entscheidungen mit Tradeoffs transparent machen.
|
2. Entscheidungen mit Tradeoffs transparent machen.
|
||||||
3. Oeffentliche Contracts explizit benennen.
|
3. Oeffentliche Contracts explizit benennen.
|
||||||
4. Success Criteria frueh mit stabilen IDs (`SC-*`) definieren.
|
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.
|
6. Teststrategie nach Risiko priorisieren.
|
||||||
|
|
||||||
## Qualitaetskriterien
|
## Qualitaetskriterien
|
||||||
@@ -42,7 +42,7 @@ Wenn `.agents/` verwendet wird:
|
|||||||
2. Jeder betroffene Bereich hat klare Akzeptanzkriterien mit stabiler ID (`SC-*`).
|
2. Jeder betroffene Bereich hat klare Akzeptanzkriterien mit stabiler ID (`SC-*`).
|
||||||
3. Risiken sind priorisiert und beobachtbar.
|
3. Risiken sind priorisiert und beobachtbar.
|
||||||
4. Ungeklaerte Themen stehen explizit unter Annahmen.
|
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
|
## Out of Scope
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
### Option B: Shared Partial/Helper
|
### Option B: Shared Partial/Helper
|
||||||
|
|
||||||
- Vorteile: Schneller Nutzen, moderates Risiko
|
- Vorteile: Schneller Nutzen, moderates Risiko
|
||||||
- Nachteile: Teilweise Restduplikate moeglich
|
- Nachteile: Teilweise Restduplikate möglich
|
||||||
- Geeignet wenn: Wiederkehrendes UI-/Glue-Muster mit klaren Datencontracts
|
- Geeignet wenn: Wiederkehrendes UI-/Glue-Muster mit klaren Datencontracts
|
||||||
|
|
||||||
### Option C: Lokal belassen
|
### Option C: Lokal belassen
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ docker compose exec php php bin/console module:sync # 3. Modul-Migrationen + A
|
|||||||
|
|
||||||
App: <http://localhost:8080> · phpMyAdmin: <http://localhost:8081>
|
App: <http://localhost:8080> · phpMyAdmin: <http://localhost:8081>
|
||||||
|
|
||||||
> `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
|
### Login
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ Alle Demo-User haben das Passwort `Demo123`:
|
|||||||
| `hilde@user.com` | Support |
|
| `hilde@user.com` | Support |
|
||||||
|
|
||||||
Plus der Live-User `fs@breadcrumb-solutions.de` (alle Rollen, Passwort nur per Reset).
|
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
|
## Quality Gates
|
||||||
|
|
||||||
|
|||||||
262
bin/fix-md-umlauts.py
Executable file
262
bin/fix-md-umlauts.py
Executable file
@@ -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 <file.md> [<file.md> ...]
|
||||||
|
--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))
|
||||||
@@ -115,7 +115,7 @@ flowchart TD
|
|||||||
- In `pages/**` und `templates/**` sind inline `<script type="module">...</script>` ohne `src` verboten.
|
- In `pages/**` und `templates/**` sind inline `<script type="module">...</script>` ohne `src` verboten.
|
||||||
- Seiteninitialisierung liegt in dedizierten ESM-Page-Modulen unter `web/js/pages/*`.
|
- Seiteninitialisierung liegt in dedizierten ESM-Page-Modulen unter `web/js/pages/*`.
|
||||||
- Pro Seite wird Konfiguration per `<script type="application/json" id="page-config-<page-key>">...</script>` bereitgestellt und im Modul über `readPageConfig(...)` gelesen.
|
- Pro Seite wird Konfiguration per `<script type="application/json" id="page-config-<page-key>">...</script>` 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
|
## Mindestchecks vor Merge
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,6 @@ $meinService = app(\MintyPHP\Service\MeinNeuerService::class);
|
|||||||
den konkreten Service direkt registrieren und per `app()` holen.
|
den konkreten Service direkt registrieren und per `app()` holen.
|
||||||
- Der Container lebt **pro HTTP-Anfrage** — er wird in `web/index.php` initialisiert
|
- Der Container lebt **pro HTTP-Anfrage** — er wird in `web/index.php` initialisiert
|
||||||
und über `setAppContainer()` im globalen State abgelegt.
|
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()`,
|
- In `core/Service/**` außerhalb von `*Factory.php` niemals `new ...Factory()`,
|
||||||
`new ...Service()` oder `new ...Repository()` direkt instanziieren.
|
`new ...Service()` oder `new ...Repository()` direkt instanziieren.
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Das ist oft erwartbar, solange es um nicht-gecachte Keys geht.
|
|||||||
Prüfregel:
|
Prüfregel:
|
||||||
|
|
||||||
- Geht es um `appSetting(...)`-Keys? Dann Datei-Cache relevant.
|
- 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
|
## Betriebs-Hinweis
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
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)
|
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` |
|
| 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` |
|
| 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
|
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".
|
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? |
|
| Szenario | Keepalive-Ping? |
|
||||||
|----------|-----------------|
|
|----------|-----------------|
|
||||||
@@ -100,12 +100,12 @@ DB: user_remember_tokens
|
|||||||
└─ last_used
|
└─ 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
|
### Auto-Login-Ablauf
|
||||||
|
|
||||||
1. Kein aktiver Session-User → Remember-Cookie lesen
|
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
|
3. Selector → DB-Lookup
|
||||||
4. Token → `hash_equals(SHA256)` Verify
|
4. Token → `hash_equals(SHA256)` Verify
|
||||||
5. User aktiv? Token nicht abgelaufen?
|
5. User aktiv? Token nicht abgelaufen?
|
||||||
@@ -125,7 +125,7 @@ Quelle: `core/Service/Auth/RememberMeRateLimiter.php`
|
|||||||
- Fail-open: Bei Memcached-Ausfall wird nicht blockiert
|
- Fail-open: Bei Memcached-Ausfall wird nicht blockiert
|
||||||
- Erfolgreicher Auto-Login setzt Counter zurueck
|
- 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
|
## Zusammenspiel Absolute Timeout + Remember-Token
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ Login → 8h Absolute Timeout → Session endet
|
|||||||
└─ NEIN → Login-Seite
|
└─ 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.
|
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) |
|
| `httponly` | `true` | Kein JS-Zugriff (XSS-Schutz) |
|
||||||
| `samesite` | `Lax` | CSRF-Schutz bei Cross-Site-Navigation |
|
| `samesite` | `Lax` | CSRF-Schutz bei Cross-Site-Navigation |
|
||||||
| `secure` | dynamisch | `true` bei HTTPS, `false` bei HTTP (Dev) |
|
| `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
|
## Audit-Events
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime:
|
|||||||
|
|
||||||
| Komponente | Pfad |
|
| Komponente | Pfad |
|
||||||
|------------|------|
|
|------------|------|
|
||||||
| Timeout-Pruefung | `web/index.php` |
|
| Timeout-Prüfung | `web/index.php` |
|
||||||
| AuthService | `core/Service/Auth/AuthService.php` |
|
| AuthService | `core/Service/Auth/AuthService.php` |
|
||||||
| RememberMeService | `core/Service/Auth/RememberMeService.php` |
|
| RememberMeService | `core/Service/Auth/RememberMeService.php` |
|
||||||
| RememberMeRateLimiter | `core/Service/Auth/RememberMeRateLimiter.php` |
|
| RememberMeRateLimiter | `core/Service/Auth/RememberMeRateLimiter.php` |
|
||||||
|
|||||||
@@ -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.
|
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.
|
2. Web-Login mit falschem Passwort >5 pro E-Mail+IP -> `429` erwartet.
|
||||||
3. API-Login mit falschen Credentials wiederholt -> `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.
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ Letzte Aktualisierung: 2026-03-19
|
|||||||
|
|
||||||
## Ziel
|
## 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)
|
- ENV-Validierung (Pflichtkeys + Formate)
|
||||||
- AppContainer-Bootstrap
|
- AppContainer-Bootstrap
|
||||||
@@ -35,13 +35,13 @@ docker compose exec php php bin/console doctor
|
|||||||
- `0`: keine harten Fehler
|
- `0`: keine harten Fehler
|
||||||
- `1`: mindestens ein `FAIL`-Check
|
- `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
|
## Typischer Einsatz im Betrieb
|
||||||
|
|
||||||
1. Direkt nach Neuinstallation / Deployment.
|
1. Direkt nach Neuinstallation / Deployment.
|
||||||
2. Bei 4xx/5xx-Symptomen als erster Schritt.
|
2. Bei 4xx/5xx-Symptomen als erster Schritt.
|
||||||
3. Nach Konfigurations- oder RBAC-Aenderungen.
|
3. Nach Konfigurations- oder RBAC-Änderungen.
|
||||||
|
|
||||||
## Beispielausgabe
|
## Beispielausgabe
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
Die Dokumentation folgt dem Diataxis-Modell mit genau vier Quadranten in dieser Reihenfolge:
|
||||||
|
|
||||||
1. **Tutorials** — Lernorientierte Schritt-fuer-Schritt-Anleitungen
|
1. **Tutorials** — Lernorientierte Schritt-für-Schritt-Anleitungen
|
||||||
2. **How-to Guides** — Aufgabenorientierte Anleitungen fuer konkrete Ziele
|
2. **How-to Guides** — Aufgabenorientierte Anleitungen für konkrete Ziele
|
||||||
3. **Explanation** — Verstaendnisorientierte Hintergrunderklaerungen
|
3. **Explanation** — Verstaendnisorientierte Hintergrunderklaerungen
|
||||||
4. **Reference** — Informationsorientierte Fakten und Nachschlagewerke
|
4. **Reference** — Informationsorientierte Fakten und Nachschlagewerke
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-04-01
|
|||||||
|
|
||||||
## Ziel
|
## 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
|
## Enthaltene Basis
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-B
|
|||||||
|
|
||||||
## Was `qa-required` abdeckt
|
## 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-001` PHPUnit
|
||||||
- `QG-002` PHPStan
|
- `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)
|
## Phase-1 Setup (noch nicht blockend)
|
||||||
|
|
||||||
1. Sicherstellen, dass der Gitea-Runner Docker + Docker Compose ausfuehren darf.
|
1. Sicherstellen, dass der Gitea-Runner Docker + Docker Compose ausführen darf.
|
||||||
2. Workflow-Datei nach `.gitea/workflows/qa-required.yaml` uebernehmen.
|
2. Workflow-Datei nach `.gitea/workflows/qa-required.yaml` übernehmen.
|
||||||
3. PR gegen `main` oeffnen und pruefen, dass Job `qa-required` gruen laeuft.
|
3. PR gegen `main` öffnen und prüfen, dass Job `qa-required` gruen laeuft.
|
||||||
4. Branch Protection noch **nicht** auf "required" setzen.
|
4. Branch Protection noch **nicht** auf "required" setzen.
|
||||||
|
|
||||||
## Phase-2 Aktivierung (blockend)
|
## Phase-2 Aktivierung (blockend)
|
||||||
|
|
||||||
1. Branch-Protection fuer `main` aktivieren.
|
1. Branch-Protection für `main` aktivieren.
|
||||||
2. Statuscheck `qa-required` als required markieren.
|
2. Statuscheck `qa-required` als required markieren.
|
||||||
3. Optional: weitere Jobs ergaenzen (z. B. nightly/extended Checks), aber nur `qa-required` blockend setzen.
|
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-005` (Browser-Smoke) bleibt manuell/non-blocking.
|
||||||
- `QG-007` (composer-unused) bleibt periodisch/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`.
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ Provider:
|
|||||||
- `mapPreviewItem()`
|
- `mapPreviewItem()`
|
||||||
- `mapResultItem()`
|
- `mapResultItem()`
|
||||||
5. Bei Modul-Resources: Provider-Klasse in `module.php` unter `search_resources` registrieren.
|
5. Bei Modul-Resources: Provider-Klasse in `module.php` unter `search_resources` registrieren.
|
||||||
6. i18n-Labels pruefen.
|
6. i18n-Labels prüfen.
|
||||||
|
|
||||||
## Wichtige Regeln
|
## Wichtige Regeln
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Kompakter Tagesworkflow für Entwicklung, Tests und schema-nahe Änderungen.
|
|||||||
bin/dev init
|
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)
|
1. `.env` aus `.env.example` erstellen (falls fehlend)
|
||||||
2. `docker compose up --build -d`
|
2. `docker compose up --build -d`
|
||||||
@@ -36,17 +36,17 @@ docker compose restart php nginx
|
|||||||
|
|
||||||
## Module-Sync
|
## Module-Sync
|
||||||
|
|
||||||
Nach Aenderungen an Modulen, Manifesten oder `APP_ENABLED_MODULES`:
|
Nach Änderungen an Modulen, Manifesten oder `APP_ENABLED_MODULES`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose exec php php bin/console module:sync
|
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`.
|
Alle Dev-Orchestrator-Kommandos: `bin/dev --help`.
|
||||||
|
|
||||||
## Schema-Stand
|
## 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
|
docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress
|
||||||
```
|
```
|
||||||
|
|
||||||
Bei Modul-/Manifest-Aenderungen zusaetzlich:
|
Bei Modul-/Manifest-Änderungen zusaetzlich:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose exec php php bin/console module:sync
|
docker compose exec php php bin/console module:sync
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-26
|
|||||||
|
|
||||||
## Ziel
|
## 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
|
## 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
|
## 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
|
## 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
|
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
|
1. `module:migrate` — SQL-Migrationen anwenden
|
||||||
2. `module:permissions-sync` — Permissions registrieren
|
2. `module:permissions-sync` — Permissions registrieren
|
||||||
3. `module:build` — Seiten-Symlinks erstellen
|
3. `module:build` — Seiten-Symlinks erstellen
|
||||||
4. `module:assets-sync` — CSS/JS-Assets veroeffentlichen
|
4. `module:assets-sync` — CSS/JS-Assets veroeffentlichen
|
||||||
|
|
||||||
Nach jedem Manifest-Aenderung erneut ausfuehren.
|
Nach jedem Manifest-Änderung erneut ausführen.
|
||||||
|
|
||||||
## Schritt 7: Validieren
|
## Schritt 7: Validieren
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ Nach jedem Manifest-Aenderung erneut ausfuehren.
|
|||||||
docker compose exec php php bin/console module:validate mein-modul
|
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
|
## 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/
|
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
|
```bash
|
||||||
docker compose exec php vendor/bin/phpunit tests/Architecture/
|
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
|
### 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()`).
|
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
|
### Layout-Kontext
|
||||||
|
|
||||||
`LayoutContextProvider` implementieren — liefert Daten fuer Templates bei jedem Page-Render:
|
`LayoutContextProvider` implementieren — liefert Daten für Templates bei jedem Page-Render:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
'layout_context_providers' => [
|
'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()`).
|
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
|
### Event-Listener
|
||||||
|
|
||||||
@@ -308,7 +308,7 @@ Interface: `core/App/Module/Contracts/EventListener.php` (Methode: `handle(strin
|
|||||||
|
|
||||||
### Scheduler-Job
|
### 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
|
### 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).
|
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
|
```php
|
||||||
'i18n_path' => 'i18n',
|
'i18n_path' => 'i18n',
|
||||||
```
|
```
|
||||||
|
|
||||||
Dateien: `modules/mein-modul/i18n/default_de.json`, `modules/mein-modul/i18n/default_en.json`.
|
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
|
### Abhaengigkeit von anderem Modul
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ Schluessel werden per `t('key')` aufgeloest — identisch zu Core-Translations.
|
|||||||
'requires' => ['notifications'],
|
'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.<id>.*` Prefix
|
- [ ] Session-Keys verwenden `module.<id>.*` Prefix
|
||||||
- [ ] Keine Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`) im Modul-Code
|
- [ ] 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 |
|
| 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` |
|
| 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` |
|
| 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\<Name>\*` |
|
| Namespace-Fehler in Tests | Modul-Klasse in Core-Namespace | Alle Klassen unter `MintyPHP\Module\<Name>\*` |
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
Letzte Aktualisierung: 2026-03-06
|
Letzte Aktualisierung: 2026-03-06
|
||||||
|
|
||||||
Kurzstandard fuer neue Actions/Endpoints.
|
Kurzstandard für neue Actions/Endpoints.
|
||||||
|
|
||||||
## Regeln
|
## Regeln
|
||||||
|
|
||||||
- Input immer ueber `requestInput()`.
|
- Input immer über `requestInput()`.
|
||||||
- Validierungsfehler intern immer als `FormErrors`.
|
- Validierungsfehler intern immer als `FormErrors`.
|
||||||
- API-Validation immer mit `ApiResponse::validationFromFormErrors(...)`.
|
- API-Validation immer mit `ApiResponse::validationFromFormErrors(...)`.
|
||||||
- Web-Templates bekommen kompakte Fehlerlisten (`$errors`) aus `toFlatList()`.
|
- 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(...)`).
|
- Bei Redirect-POST-Formen: `FormErrors` intern sammeln und erst am Redirect-Rand transportieren (z. B. `flashFormErrors(...)`).
|
||||||
|
|
||||||
## Web-Beispiel (Action)
|
## Web-Beispiel (Action)
|
||||||
|
|||||||
@@ -15,20 +15,20 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
|
|||||||
4. `/docs/tutorial-04-architektur-request-flow.md`
|
4. `/docs/tutorial-04-architektur-request-flow.md`
|
||||||
- Request-Flow, Schichtmodell, Do/Don't.
|
- Request-Flow, Schichtmodell, Do/Don't.
|
||||||
5. `/docs/tutorial-05-erste-aenderung-ui.md`
|
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`
|
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`
|
7. `/docs/tutorial-07-security-tenant-scope.md`
|
||||||
- Sicherheitsgrundlagen, Tenant-Scope, Pflichtchecks.
|
- Sicherheitsgrundlagen, Tenant-Scope, Pflichtchecks.
|
||||||
8. `/docs/tutorial-08-api-erweitern.md`
|
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`
|
9. `/docs/tutorial-09-advanced-scheduler-sso.md`
|
||||||
- Fortgeschrittene Themen: Scheduler, Lifecycle, SSO.
|
- Fortgeschrittene Themen: Scheduler, Lifecycle, SSO.
|
||||||
|
|
||||||
## How-to Guides
|
## How-to Guides
|
||||||
|
|
||||||
- `/docs/howto-erste-aenderung.md`
|
- `/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`
|
- `/docs/howto-globale-suche.md`
|
||||||
- Neue Resource in der globalen Suche integrieren.
|
- Neue Resource in der globalen Suche integrieren.
|
||||||
- `/docs/howto-importe.md`
|
- `/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`
|
- `/docs/howto-rbac-permissions-playbook.md`
|
||||||
- RBAC-Rechte sauber erweitern (neue Permission, neue Ability, UI/API-Faelle).
|
- RBAC-Rechte sauber erweitern (neue Permission, neue Ability, UI/API-Faelle).
|
||||||
- `/docs/howto-request-input-validation.md`
|
- `/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`
|
- `/docs/howto-docker-lokal.md`
|
||||||
- Lokaler Docker-Betrieb.
|
- Lokaler Docker-Betrieb.
|
||||||
- `/docs/howto-docker-produktiv.md`
|
- `/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`
|
- `/docs/howto-betriebscheck-doctor.md`
|
||||||
- Schneller Systemcheck mit `php bin/console doctor`.
|
- Schneller Systemcheck mit `php bin/console doctor`.
|
||||||
- `/docs/howto-fehlerbehebung.md`
|
- `/docs/howto-fehlerbehebung.md`
|
||||||
- Haeufige Fehler und schnelle Loesungen.
|
- Häufige Fehler und schnelle Lösungen.
|
||||||
- `/docs/howto-lokale-entwicklung.md`
|
- `/docs/howto-lokale-entwicklung.md`
|
||||||
- Tages-Workflow fuer Entwicklung und Checks.
|
- Tages-Workflow für Entwicklung und Checks.
|
||||||
- `/docs/howto-modul-erstellen.md`
|
- `/docs/howto-modul-erstellen.md`
|
||||||
- Neues Modul erstellen: Scaffold, Manifest, Route, Permission, UI-Slot, Test.
|
- Neues Modul erstellen: Scaffold, Manifest, Route, Permission, UI-Slot, Test.
|
||||||
- `/docs/howto-gitea-required-checks.md`
|
- `/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`
|
- `/docs/howto-dokumentation-erweitern.md`
|
||||||
- Regeln fuer konsistente, wachsende Doku.
|
- Regeln für konsistente, wachsende Doku.
|
||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
|
|||||||
- `/docs/explanation-einstellungen-speicherung.md`
|
- `/docs/explanation-einstellungen-speicherung.md`
|
||||||
- Warum Settings in DB + Datei-Cache koexistieren.
|
- Warum Settings in DB + Datei-Cache koexistieren.
|
||||||
- `/docs/explanation-docker-betrieb.md`
|
- `/docs/explanation-docker-betrieb.md`
|
||||||
- Uebersicht und Entscheidungshilfe fuer Dev/Prod.
|
- Übersicht und Entscheidungshilfe für Dev/Prod.
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
@@ -88,9 +88,9 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
|
|||||||
- `/docs/reference-konventionen.md`
|
- `/docs/reference-konventionen.md`
|
||||||
- Projektweite Konventionen (kurz und verbindlich).
|
- Projektweite Konventionen (kurz und verbindlich).
|
||||||
- `/docs/reference-core-standards.md`
|
- `/docs/reference-core-standards.md`
|
||||||
- Regeln speziell fuer `core/**`.
|
- Regeln speziell für `core/**`.
|
||||||
- `/docs/reference-benutzer-lifecycle-policy.md`
|
- `/docs/reference-benutzer-lifecycle-policy.md`
|
||||||
- Policy- und Laufzeitreferenz fuer User Lifecycle.
|
- Policy- und Laufzeitreferenz für User Lifecycle.
|
||||||
- `/docs/reference-frontend-css.md`
|
- `/docs/reference-frontend-css.md`
|
||||||
- CSS-Schichtsystem und Namenskonventionen.
|
- CSS-Schichtsystem und Namenskonventionen.
|
||||||
- `/docs/reference-frontend-javascript.md`
|
- `/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`
|
- `/docs/reference-entwickler-checkliste.md`
|
||||||
- Definition of Done vor Merge.
|
- Definition of Done vor Merge.
|
||||||
- `/docs/reference-codex-prompts.md`
|
- `/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`
|
- `/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`
|
- `/docs/reference-cli-commands.md`
|
||||||
- Alle CLI-Kommandos (`php bin/console`), Bootstrap-Helfer, Anleitung neue Kommandos.
|
- Alle CLI-Kommandos (`php bin/console`), Bootstrap-Helfer, Anleitung neue Kommandos.
|
||||||
- `/docs/reference-module-manifest-contract.md`
|
- `/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`
|
- `/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`
|
- Agent-Workflow (Rollen, State-Machine, Contracts): siehe `/.agents/workflow.md`
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ Letzte Aktualisierung: 2026-04-01
|
|||||||
|
|
||||||
## Einstiegspunkt
|
## Einstiegspunkt
|
||||||
|
|
||||||
Alle CLI-Kommandos laufen ueber einen einzigen Einstiegspunkt:
|
Alle CLI-Kommandos laufen über einen einzigen Einstiegspunkt:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
php bin/console <command> [argumente] [optionen]
|
php bin/console <command> [argumente] [optionen]
|
||||||
```
|
```
|
||||||
|
|
||||||
Uebersicht aller verfuegbaren Kommandos:
|
Übersicht aller verfügbaren Kommandos:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
php bin/console list
|
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
|
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:
|
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
|
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):
|
Status-Anzeige (kein Schreibzugriff):
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ Status-Anzeige (kein Schreibzugriff):
|
|||||||
docker compose exec php php bin/console db:migrate --status
|
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
|
### module:migrate
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ docker compose exec php php bin/console module:deactivate <module-id> --confirm
|
|||||||
docker compose exec php php bin/console module:deactivate <module-id> --dry-run
|
docker compose exec php php bin/console module:deactivate <module-id> --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
|
### scheduler:run
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ Der Docker-Scheduler-Service ruft dieses Kommando automatisch alle 60 Sekunden a
|
|||||||
|
|
||||||
### module:validate
|
### 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
|
```bash
|
||||||
docker compose exec php php bin/console module:validate <module-id>
|
docker compose exec php php bin/console module:validate <module-id>
|
||||||
@@ -128,7 +128,7 @@ docker compose exec php php bin/console module:validate --all
|
|||||||
|
|
||||||
### make:module
|
### 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
|
```bash
|
||||||
docker compose exec php php bin/console make:module <module-id>
|
docker compose exec php php bin/console make:module <module-id>
|
||||||
@@ -144,7 +144,7 @@ Fuehrt System-Gesundheitschecks aus (ENV, DB, RBAC, Scheduler-Heartbeat).
|
|||||||
docker compose exec php php bin/console doctor
|
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:
|
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 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
|
## Neue Kommandos anlegen
|
||||||
|
|
||||||
1. Klasse in `core/Console/Commands/` erstellen, die `MintyPHP\Console\Command` erweitert.
|
1. Klasse in `core/Console/Commands/` erstellen, die `MintyPHP\Console\Command` erweitert.
|
||||||
2. `name()`, `description()` und `execute()` implementieren.
|
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:
|
Beispiel:
|
||||||
|
|
||||||
@@ -204,5 +204,5 @@ Die `Command`-Basisklasse stellt Helfer bereit:
|
|||||||
|
|
||||||
| Methode | Zweck |
|
| 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 |
|
| `$this->projectRoot()` | Gibt den absoluten Projekt-Root-Pfad zurueck |
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-09
|
|||||||
|
|
||||||
## Ziel
|
## 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)
|
## Prompt: Implementierung (strict)
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ Kurze Definition of Done vor Merge.
|
|||||||
- [ ] Runtime-Komponenten folgen Contract `init(root, config) -> { destroy() }`
|
- [ ] Runtime-Komponenten folgen Contract `init(root, config) -> { destroy() }`
|
||||||
- [ ] Runtime-Komponenten enthalten keinen eigenen `DOMContentLoaded`-/Sideeffect-Auto-Init
|
- [ ] Runtime-Komponenten enthalten keinen eigenen `DOMContentLoaded`-/Sideeffect-Auto-Init
|
||||||
- [ ] Listener/Timer/Observer aus Runtime-Komponenten werden in `destroy()` sauber abgebaut
|
- [ ] 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
|
- [ ] 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)`
|
- [ ] Service-Auflösung in `pages/**`/`templates/**`/`core/Support/**` nur via `app(Foo::class)`
|
||||||
- [ ] Keine `new ...Factory()` in `core/Service/**` außerhalb `*Factory.php`
|
- [ ] 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`
|
- [ ] 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/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/phpstan analyse -c phpstan.neon --no-progress`
|
||||||
- [ ] `docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php`
|
- [ ] `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-Änderungen: `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='addressbook,bookmarks' php bin/console module:sync`
|
||||||
- [ ] Runtime-Sync erzeugt Step-Summary (`migrate`, `permissions-sync`, `build`, `assets-sync`) und `vendor_warnings_ignored=<n>`
|
- [ ] Runtime-Sync erzeugt Step-Summary (`migrate`, `permissions-sync`, `build`, `assets-sync`) und `vendor_warnings_ignored=<n>`
|
||||||
- [ ] Keine First-party CLI-Warnings/Notices/Deprecations im Runtime-Sync (Vendor-Warnings sind nur temporaer toleriert und muessen gezaehlt sichtbar sein)
|
- [ ] 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-Aenderungen: `docker compose exec php vendor/bin/phpunit tests/Architecture/CodexSkillReferenceContractTest.php`
|
- [ ] bei Docs-/Skills-Änderungen: `docker compose exec php vendor/bin/phpunit tests/Architecture/CodexSkillReferenceContractTest.php`
|
||||||
- [ ] `bin/docs-link-check.sh` (QG-008, scannt standardmaessig ohne `.agents/runs/**`)
|
- [ ] `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/docs-drift-check.sh` (QG-008-Zusatz, blockt Legacy-Referenzen + fehlenden Setup-Vertrag)
|
||||||
- [ ] `bin/codex-skills-sync.sh --check` (QG-009)
|
- [ ] `bin/codex-skills-sync.sh --check` (QG-009)
|
||||||
- [ ] bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors)
|
- [ ] bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors)
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ Letzte Aktualisierung: 2026-03-18
|
|||||||
|
|
||||||
## Ziel
|
## 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
|
## Kanonische Quelle
|
||||||
|
|
||||||
Normativer Manifest- und Runtime-Contract: `/docs/reference-module-manifest-contract.md`.
|
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+
|
## 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`).
|
- `module.php` validiert gegen den kanonischen Contract (`permissions`, `scheduler_jobs`, `ui_slots`, `routes`).
|
||||||
- Route-/Slot-/Layout-Guards laufen fail-fast.
|
- Route-/Slot-/Layout-Guards laufen fail-fast.
|
||||||
3. **Security + Scope absichern**
|
3. **Security + Scope absichern**
|
||||||
- AuthZ/RBAC serverseitig pruefen.
|
- AuthZ/RBAC serverseitig prüfen.
|
||||||
- Tenant-Scope serverseitig pruefen.
|
- Tenant-Scope serverseitig prüfen.
|
||||||
- POST-Mutationen mit CSRF absichern.
|
- POST-Mutationen mit CSRF absichern.
|
||||||
4. **Runtime-Hygiene absichern**
|
4. **Runtime-Hygiene absichern**
|
||||||
- `php bin/console module:sync` laeuft reproduzierbar mit standardisierter Step-Summary.
|
- `php bin/console module:sync` laeuft reproduzierbar mit standardisierter Step-Summary.
|
||||||
- Keine First-party CLI-Warnings/Notices/Deprecations; Vendor-Rauschen wird nur gezaehlt/reportet.
|
- Keine First-party CLI-Warnings/Notices/Deprecations; Vendor-Rauschen wird nur gezaehlt/reportet.
|
||||||
5. **Testbarkeit und Gates**
|
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.
|
- `phpunit` und `phpstan` als Pflicht-Gates gruen.
|
||||||
6. **Daten- und Betriebsfaehigkeit**
|
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.
|
- Logs/Audit ohne unredacted PII/Secrets.
|
||||||
|
|
||||||
## Derzeit Out of Scope
|
## 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.
|
- Eigener DB-Server oder Netzwerk-Microservice je Modul.
|
||||||
- Externe Drittanbieter-Module mit Legacy-Kompatibilitaet.
|
- Externe Drittanbieter-Module mit Legacy-Kompatibilitaet.
|
||||||
|
|
||||||
## Verfuegbare Core-Services fuer Module
|
## Verfügbare Core-Services für Module
|
||||||
|
|
||||||
JS-seitig:
|
JS-seitig:
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,6 @@ Regel: Vendor-Overrides nur für Bibliotheks-Selektoren; projektspezifische UI-S
|
|||||||
## Module-CSS Token-Regel
|
## Module-CSS Token-Regel
|
||||||
|
|
||||||
1. Modul-CSS nutzt primär Core-Tokens (`--app-*`) statt eigener Farbwerte.
|
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.
|
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.
|
4. Harte Hex-Fallbacks nur als Ausnahmefall, nicht als Standard.
|
||||||
|
|||||||
@@ -48,14 +48,14 @@ Empfohlenes Muster:
|
|||||||
- `destroy()` muss alle Listener/Timer/Observer abbauen.
|
- `destroy()` muss alle Listener/Timer/Observer abbauen.
|
||||||
- Hybrid Host-Policy:
|
- Hybrid Host-Policy:
|
||||||
- Host-gebundene UI-Komponenten nutzen explizite `data-app-component`-Hosts im Markup.
|
- Host-gebundene UI-Komponenten nutzen explizite `data-app-component`-Hosts im Markup.
|
||||||
- Tabs sind host-gebunden und laufen ausschliesslich ueber `data-app-component="tabs"`.
|
- Tabs sind host-gebunden und laufen ausschliesslich über `data-app-component="tabs"`.
|
||||||
- Globale Utilities ohne natuerliches Host-Element werden runtime-global (`scope: 'global'`) registriert, aber mit demselben Lifecycle-Contract.
|
- Globale Utilities ohne natürliches 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.
|
- Root-Strict gilt für host-gebundene Komponenten: keine `document.querySelector`-Fallback-Pfade.
|
||||||
- Projektseitige Custom-Globals auf `window.*` sind verboten; Komponenten kommunizieren ueber Core-Channels.
|
- Projektseitige Custom-Globals auf `window.*` sind verboten; Komponenten kommunizieren über Core-Channels.
|
||||||
|
|
||||||
## UI Storage Contract
|
## 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.
|
- 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.
|
- Hard-Cut-Policy: keine Legacy-Key-Fallbacks und kein Legacy-Key-Sync in migrierten Runtime-Komponenten/Core-Modulen.
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Letzte Aktualisierung: 2026-04-01
|
|||||||
Alle Konfiguration erfolgt über Umgebungsvariablen in der `.env`-Datei.
|
Alle Konfiguration erfolgt über Umgebungsvariablen in der `.env`-Datei.
|
||||||
Vorlage: `.env.example` — niemals echte Credentials committen.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Letzte Aktualisierung: 2026-03-24
|
|||||||
- Namespace: `MintyPHP\Module\<Name>\*` — nie Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`).
|
- Namespace: `MintyPHP\Module\<Name>\*` — nie Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`).
|
||||||
- Verzeichnis: `modules/<id>/lib/Module/<Name>/` (Service, Repository, Providers, Support).
|
- Verzeichnis: `modules/<id>/lib/Module/<Name>/` (Service, Repository, Providers, Support).
|
||||||
- Session-Keys: Prefix `module.<id>.*`.
|
- Session-Keys: Prefix `module.<id>.*`.
|
||||||
- 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.
|
- Kein Modul-spezifisches Markup in Core-Templates.
|
||||||
- Tests: `modules/<id>/tests/` (werden von `phpunit.xml` automatisch entdeckt via `modules/*/tests`).
|
- Tests: `modules/<id>/tests/` (werden von `phpunit.xml` automatisch entdeckt via `modules/*/tests`).
|
||||||
- Modul-Actions importieren nie `OperationsAuthorizationPolicy::ABILITY_*` — eigene Policy nutzen.
|
- 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/phpunit`
|
||||||
- `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress`
|
- `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)
|
- bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors)
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ Letzte Aktualisierung: 2026-03-25
|
|||||||
|
|
||||||
## Ziel
|
## 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
|
## 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.
|
`/docs/reference-extension-readiness.md` referenziert diesen Contract und dupliziert keine Felddefinitionen.
|
||||||
|
|
||||||
## JSON-Schema-Enforcement
|
## JSON-Schema-Enforcement
|
||||||
@@ -25,8 +25,8 @@ Ein Manifest muss sowohl:
|
|||||||
|
|
||||||
## Namespace-Konvention
|
## Namespace-Konvention
|
||||||
|
|
||||||
Alle PHP-Klassen eines Moduls muessen den Namespace `MintyPHP\Module\<Name>\*` verwenden.
|
Alle PHP-Klassen eines Moduls müssen den Namespace `MintyPHP\Module\<Name>\*` verwenden.
|
||||||
Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`, `MintyPHP\Support\*`) sind fuer Modul-Code verboten.
|
Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`, `MintyPHP\Support\*`) sind für Modul-Code verboten.
|
||||||
|
|
||||||
Verzeichnis-Layout:
|
Verzeichnis-Layout:
|
||||||
|
|
||||||
@@ -75,8 +75,8 @@ Der `ModuleAutoloader` registriert daraus den absoluten Pfad `modules/<id>/i18n/
|
|||||||
```
|
```
|
||||||
|
|
||||||
- `key` und `description` sind Pflichtfelder.
|
- `key` und `description` sind Pflichtfelder.
|
||||||
- Runtime-Sync erfolgt ueber `php bin/console module:sync`.
|
- Runtime-Sync erfolgt über `php bin/console module:sync`.
|
||||||
- `module:sync` fuehrt diesen Sync automatisch aus.
|
- `module:sync` führt diesen Sync automatisch aus.
|
||||||
|
|
||||||
## `scheduler_jobs` Contract
|
## `scheduler_jobs` Contract
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ Der `ModuleAutoloader` registriert daraus den absoluten Pfad `modules/<id>/i18n/
|
|||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
- Manifest ist Source of Truth fuer Job-Metadaten und Defaults.
|
- Manifest ist Source of Truth für Job-Metadaten und Defaults.
|
||||||
- Handler werden zur Laufzeit container-resolvable fuer `execute(...)` geladen.
|
- Handler werden zur Laufzeit container-resolvable für `execute(...)` geladen.
|
||||||
|
|
||||||
## `ui_slots` Contract (V1.2)
|
## `ui_slots` Contract (V1.2)
|
||||||
|
|
||||||
@@ -118,15 +118,15 @@ Neue generische Slot-Typen:
|
|||||||
Abgrenzung CSS:
|
Abgrenzung CSS:
|
||||||
|
|
||||||
- `layout.head_style` = global auf allen Seiten.
|
- `layout.head_style` = global auf allen Seiten.
|
||||||
- `asset_groups` = seiten-/kontextbezogen ueber `style_groups`.
|
- `asset_groups` = seiten-/kontextbezogen über `style_groups`.
|
||||||
|
|
||||||
## Guard-Regeln
|
## Guard-Regeln
|
||||||
|
|
||||||
- Route-Kollisionen sind fail-fast:
|
- Route-Kollisionen sind fail-fast:
|
||||||
- Modul vs Modul auf `target` und `path`.
|
- Modul vs Modul auf `target` und `path`.
|
||||||
- Modul vs Core auf `path` beim Router-Boot.
|
- Modul vs Core auf `path` beim Router-Boot.
|
||||||
- Layout-Provider duerfen reservierte Core-Keys nicht ueberschreiben (`moduleSlots`, `csrfKey`, `currentTenant`, ...).
|
- Layout-Provider duerfen reservierte Core-Keys nicht überschreiben (`moduleSlots`, `csrfKey`, `currentTenant`, ...).
|
||||||
- Layout-Provider-Top-Level-Keys muessen namespaced sein (`<module_id>.<key>`).
|
- Layout-Provider-Top-Level-Keys müssen namespaced sein (`<module_id>.<key>`).
|
||||||
|
|
||||||
## Runtime-Fingerprint
|
## Runtime-Fingerprint
|
||||||
|
|
||||||
@@ -141,16 +141,16 @@ Methoden: `ModuleRuntimePageBuilder::expectedFingerprint()`, `readFingerprint()`
|
|||||||
|
|
||||||
## API-Channel-Isolation
|
## 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 `Session::start()`, kein Cookie-Setting, kein CSRF-Token
|
||||||
- Kein Remember-Me, kein Session-Timeout, kein Tenant-UI-Refresh
|
- 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
|
- `AccessControl` listet `api/` als always-public
|
||||||
|
|
||||||
## Standard-Runbook
|
## 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`
|
1. `module:migrate`
|
||||||
2. `module:permissions-sync`
|
2. `module:permissions-sync`
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-25
|
|||||||
|
|
||||||
## Ziel
|
## 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
|
## Scope v1
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ Referenz fuer das Modul `notifications`: Event-Registrierung, Erzeugungsregeln,
|
|||||||
- `user.activated`
|
- `user.activated`
|
||||||
- `user.deactivated`
|
- `user.deactivated`
|
||||||
- `user.assignment_changed`
|
- `user.assignment_changed`
|
||||||
- Dedupe fuer diese Typen mit 30 Minuten Fenster.
|
- Dedupe für diese Typen mit 30 Minuten Fenster.
|
||||||
|
|
||||||
## Modul-Verkabelung
|
## Modul-Verkabelung
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ Kanonische Quelle: `modules/notifications/module.php`
|
|||||||
- mappt Eventtyp -> Listenerklasse + Methode `handle`.
|
- mappt Eventtyp -> Listenerklasse + Methode `handle`.
|
||||||
- `ui_slots`
|
- `ui_slots`
|
||||||
- `topbar.right_item`: Bell-Template
|
- `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`)
|
- `runtime.component`: Bell-JS (`initNotificationBell`)
|
||||||
- `permissions`
|
- `permissions`
|
||||||
- `notifications.view`
|
- `notifications.view`
|
||||||
@@ -45,9 +45,9 @@ Kanonische Quelle: `modules/notifications/module.php`
|
|||||||
5. `NotificationRepository` persistiert in `user_notifications`.
|
5. `NotificationRepository` persistiert in `user_notifications`.
|
||||||
6. Bell-Endpunkte lesen tenant-scoped Daten und aktualisieren den Session-`unread_count`.
|
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\NotificationMessage`
|
||||||
- `MintyPHP\Module\Notifications\Service\NotificationService::createFromMessage(...)`
|
- `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
|
## Datenvertrag Notification
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ Persistierter Kernvertrag:
|
|||||||
- `link` (nullable string)
|
- `link` (nullable string)
|
||||||
- `data` (nullable JSON)
|
- `data` (nullable JSON)
|
||||||
|
|
||||||
Erweiterung fuer locale-neutrale Texte:
|
Erweiterung für locale-neutrale Texte:
|
||||||
|
|
||||||
- `data.__message.title_key` (string)
|
- `data.__message.title_key` (string)
|
||||||
- `data.__message.title_params` (array)
|
- `data.__message.title_params` (array)
|
||||||
@@ -111,20 +111,20 @@ Dedupe-Metadaten (intern):
|
|||||||
- Alle Bell-Endpunkte erzwingen:
|
- Alle Bell-Endpunkte erzwingen:
|
||||||
- Login
|
- Login
|
||||||
- Ability `notifications.view`
|
- 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.
|
- Tenant-Scope wird serverseitig aus `current_tenant` erzwungen.
|
||||||
- SQL ausschliesslich im Repository (`NotificationRepository`), Service nur Orchestrierung.
|
- SQL ausschliesslich im Repository (`NotificationRepository`), Service nur Orchestrierung.
|
||||||
|
|
||||||
## Guardrails (Frontend)
|
## Guardrails (Frontend)
|
||||||
|
|
||||||
- Endpunkte werden mit App-Base-URL gebaut (kein harter Root-Pfad).
|
- 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.
|
- 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
|
## 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.
|
- Keine fragilen relativen Tiefenpfade auf Core-Templates verwenden.
|
||||||
- Modulinterne Templates bleiben lokal relativ zum Modul.
|
- Modulinterne Templates bleiben lokal relativ zum Modul.
|
||||||
|
|
||||||
@@ -138,22 +138,22 @@ Dedupe-Metadaten (intern):
|
|||||||
|
|
||||||
### Unit
|
### Unit
|
||||||
|
|
||||||
- Listener-Tests fuer alle Core-5 Typen:
|
- Listener-Tests für alle Core-5 Typen:
|
||||||
- Empfaengerregeln
|
- Empfaengerregeln
|
||||||
- Actor-Exclusion
|
- Actor-Exclusion
|
||||||
- ungultige/leere Payloads
|
- ungultige/leere Payloads
|
||||||
- Service-Tests fuer Dedupe (created vs suppressed)
|
- Service-Tests für Dedupe (created vs suppressed)
|
||||||
- Policy-Tests fuer `notifications.view`
|
- Policy-Tests für `notifications.view`
|
||||||
|
|
||||||
### Integration/Flow
|
### Integration/Flow
|
||||||
|
|
||||||
- End-to-End fuer create/delete/activate/deactivate/assignment-change.
|
- End-to-End für create/delete/activate/deactivate/assignment-change.
|
||||||
- Bell-Endpunkte mit Tenant-Scope und Permission-Pruefung.
|
- Bell-Endpunkte mit Tenant-Scope und Permission-Prüfung.
|
||||||
- Bulk-Flows dispatchen konsistent.
|
- Bulk-Flows dispatchen konsistent.
|
||||||
|
|
||||||
### Manueller Smoke
|
### Manueller Smoke
|
||||||
|
|
||||||
1. Zwei Admins im selben Tenant, einer als Actor.
|
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.
|
3. Zweiter Admin sieht Bell-Badge + Listeneintrag.
|
||||||
4. Wiederholung innerhalb 30 Minuten erzeugt kein Duplikat.
|
4. Wiederholung innerhalb 30 Minuten erzeugt kein Duplikat.
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
Die Tests sind nach Schutzwirkung organisiert, nicht nur nach technischer Ebene.
|
Die Tests sind nach Schutzwirkung organisiert, nicht nur nach technischer Ebene.
|
||||||
Wichtige Architektur- und Security-Invarianten sollen schnell gezielt laufen koennen,
|
Wichtige Architektur- und Security-Invarianten sollen schnell gezielt laufen können,
|
||||||
ohne dass jede Aenderung immer die komplette Suite im Kopf behalten muss.
|
ohne dass jede Änderung immer die komplette Suite im Kopf behalten muss.
|
||||||
|
|
||||||
## PHPUnit-Suiten
|
## 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/`.
|
- `Architecture`: alle Architektur-Contracts unter `tests/Architecture/`.
|
||||||
- `ArchitectureCore`: Core-Boundaries, Module-/Repository-Contracts, Taxonomie- und Sync-Contracts.
|
- `ArchitectureCore`: Core-Boundaries, Module-/Repository-Contracts, Taxonomie- und Sync-Contracts.
|
||||||
- `ArchitectureSecurity`: CSRF, PRG, File-Storage, Crypto, Logging sowie AuthZ-nahe 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.
|
- `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.
|
- Nur stabile Invarianten testen, keine einmaligen Migrationsdetails.
|
||||||
- Guards oder Risiken explizit abdecken, zum Beispiel `GR-CORE-*`, `GR-SEC-*`, `GR-TEST-*`.
|
- Guards oder Risiken explizit abdecken, zum Beispiel `GR-CORE-*`, `GR-SEC-*`, `GR-TEST-*`.
|
||||||
- Keine Duplikate neben bereits breiten Contracts anlegen.
|
- 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.
|
- Monolithische Sammeltests vermeiden; lieber kleine thematische Contracts.
|
||||||
|
|
||||||
## Delete vs. Refactor vs. Keep
|
## Delete vs. Refactor vs. Keep
|
||||||
|
|
||||||
- `keep`: testet einen echten plattformweiten Contract oder Security-Guard.
|
- `keep`: testet einen echten plattformweiten Contract oder Security-Guard.
|
||||||
- `refactor`: Schutz ist wichtig, aber der Test ist zu datei-, markup- oder implementation-detailnah.
|
- `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.
|
- 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.
|
- Thin Wrapper auf gemeinsame Primitive zentral testen, nicht pro Gateway erneut.
|
||||||
- Mockability-, Reflection- und Interface-Existenz-Tests ohne Risiko-Schutz vermeiden.
|
- Mockability-, Reflection- und Interface-Existenz-Tests ohne Risiko-Schutz vermeiden.
|
||||||
- Kleine Normalisierungs-Matrizen mit DataProvidern oder zusammengezogenen Contract-Dateien verdichten.
|
- Kleine Normalisierungs-Matrizen mit DataProvidern oder zusammengezogenen Contract-Dateien verdichten.
|
||||||
|
|
||||||
## Typische Low-Value-Muster
|
## Typische Low-Value-Muster
|
||||||
|
|
||||||
- Gateway-Test prueft nur `encrypt/decrypt` erneut, obwohl das Basisverhalten schon zentral abgesichert ist.
|
- Gateway-Test prüft 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 bestätigt nur, dass ein Service eins zu eins an Repository oder Gateway weiterreicht.
|
||||||
- Test prueft nur Methodensignatur, Reflection oder dass eine Klasse mockbar ist.
|
- Test prüft nur Methodensignatur, Reflection oder dass eine Klasse mockbar ist.
|
||||||
- Mehrere Minidateien decken denselben Settings-/Fallback-Mechanismus mit identischem Mock-Muster ab.
|
- 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/User/UserAccountServiceTest.php`
|
||||||
- methodenweiser Low-value-Pass in `tests/Service/Org/DepartmentServiceTest.php`
|
- methodenweiser Low-value-Pass in `tests/Service/Org/DepartmentServiceTest.php`
|
||||||
- methodenweiser Low-value-Pass in `tests/Service/Access/RoleServiceTest.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
|
||||||
|
|||||||
Reference in New Issue
Block a user