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:
2026-04-29 09:57:22 +02:00
parent 2e73cb98b4
commit 545bcc789b
39 changed files with 499 additions and 237 deletions

View File

@@ -115,7 +115,7 @@ flowchart TD
- In `pages/**` und `templates/**` sind inline `<script type="module">...</script>` ohne `src` verboten.
- 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.
- 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

View File

@@ -103,6 +103,6 @@ $meinService = app(\MintyPHP\Service\MeinNeuerService::class);
den konkreten Service direkt registrieren und per `app()` holen.
- Der Container lebt **pro HTTP-Anfrage** — er wird in `web/index.php` initialisiert
und über `setAppContainer()` im globalen State abgelegt.
- In CLI-Commands wird der Container separat initialisiert (ueber die Runtime-Bootstrap-Klassen unter `core/Console/Support/`).
- In CLI-Commands wird der Container separat initialisiert (über die Runtime-Bootstrap-Klassen unter `core/Console/Support/`).
- In `core/Service/**` außerhalb von `*Factory.php` niemals `new ...Factory()`,
`new ...Service()` oder `new ...Repository()` direkt instanziieren.

View File

@@ -53,7 +53,7 @@ Das ist oft erwartbar, solange es um nicht-gecachte Keys geht.
Prüfregel:
- Geht es um `appSetting(...)`-Keys? Dann Datei-Cache relevant.
- Geht es um SMTP/SSO/API-Details? Dann DB ist massgeblich.
- Geht es um SMTP/SSO/API-Details? Dann DB ist maßgeblich.
## Betriebs-Hinweis

View File

@@ -6,7 +6,7 @@ Letzte Aktualisierung: 2026-03-14
Vollstaendige Erklaerung des Session-Lifecycle: Wann wird ein User abgemeldet, wann greift der Remember-Token, wie bleiben Frontend und Server synchron.
## Session-Lifecycle (Uebersicht)
## Session-Lifecycle (Übersicht)
```
Login (Passwort / SSO)
@@ -35,7 +35,7 @@ Jeder Request (web/index.php)
| Idle | 30 Min | 5 Min 24 Std | Ja, bei jeder Aktivitaet | `session_idle_timeout_minutes` |
| Absolute | 8 Std | 1 Std 72 Std | Nein, nie | `session_absolute_timeout_hours` |
Pruefung in `web/index.php` (bei jedem Request):
Prüfung in `web/index.php` (bei jedem Request):
```
Idle: (now - last_activity) > idle_timeout → Timeout
@@ -67,7 +67,7 @@ Quelle: `web/js/components/app-session-warning.js`
Problem ohne Keepalive: User scrollt 29 Min auf einer Seite → JS zeigt "aktiv", Server sagt "idle".
Loesung: Alle 5 Minuten prueft ein Intervall ob seit dem letzten Sync Interaktion stattfand. Falls ja → `POST /admin/session-ping/data` → Server-Timer zurueckgesetzt.
Lösung: Alle 5 Minuten prüft ein Intervall ob seit dem letzten Sync Interaktion stattfand. Falls ja → `POST /admin/session-ping/data` → Server-Timer zurueckgesetzt.
| Szenario | Keepalive-Ping? |
|----------|-----------------|
@@ -100,12 +100,12 @@ DB: user_remember_tokens
└─ last_used
```
Selector und Token sind getrennt: Selector fuer schnellen DB-Lookup, Token-Hash fuer timing-sichere Validierung. Kein Klartext-Token in der DB.
Selector und Token sind getrennt: Selector für schnellen DB-Lookup, Token-Hash für timing-sichere Validierung. Kein Klartext-Token in der DB.
### Auto-Login-Ablauf
1. Kein aktiver Session-User → Remember-Cookie lesen
2. Rate-Limit pruefen (IP nicht blockiert?)
2. Rate-Limit prüfen (IP nicht blockiert?)
3. Selector → DB-Lookup
4. Token → `hash_equals(SHA256)` Verify
5. User aktiv? Token nicht abgelaufen?
@@ -125,7 +125,7 @@ Quelle: `core/Service/Auth/RememberMeRateLimiter.php`
- Fail-open: Bei Memcached-Ausfall wird nicht blockiert
- Erfolgreicher Auto-Login setzt Counter zurueck
Siehe `/docs/howto-anfragelimits.md` fuer alle Rate-Limits.
Siehe `/docs/howto-anfragelimits.md` für alle Rate-Limits.
## Zusammenspiel Absolute Timeout + Remember-Token
@@ -137,7 +137,7 @@ Login → 8h Absolute Timeout → Session endet
└─ NEIN → Login-Seite
```
Solange der Remember-Token lebt (Default 30 Tage), bekommt der User nach Ablauf des Absolute-Timeout automatisch eine neue Session. Der Uebergang ist nahtlos (kein Flash, kein Login-Screen).
Solange der Remember-Token lebt (Default 30 Tage), bekommt der User nach Ablauf des Absolute-Timeout automatisch eine neue Session. Der Übergang ist nahtlos (kein Flash, kein Login-Screen).
Das bedeutet: Mit aktivem Remember-Token ist die effektive Session-Dauer nicht 8 Stunden, sondern bis zu 30 Tage. Das ist by-design, sollte aber bei Compliance-Anforderungen (z. B. echte Re-Authentifizierung nach X Stunden) beruecksichtigt werden.
@@ -148,9 +148,9 @@ Das bedeutet: Mit aktivem Remember-Token ist die effektive Session-Dauer nicht 8
| `httponly` | `true` | Kein JS-Zugriff (XSS-Schutz) |
| `samesite` | `Lax` | CSRF-Schutz bei Cross-Site-Navigation |
| `secure` | dynamisch | `true` bei HTTPS, `false` bei HTTP (Dev) |
| `path` | `/` | Gueltig fuer gesamte Domain |
| `path` | `/` | Gueltig für gesamte Domain |
Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime::isSecure()`). In Produktion muss HTTPS ueber Nginx erzwungen werden (Redirect 80→443 + HSTS).
Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime::isSecure()`). In Produktion muss HTTPS über Nginx erzwungen werden (Redirect 80→443 + HSTS).
## Audit-Events
@@ -165,7 +165,7 @@ Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime:
| Komponente | Pfad |
|------------|------|
| Timeout-Pruefung | `web/index.php` |
| Timeout-Prüfung | `web/index.php` |
| AuthService | `core/Service/Auth/AuthService.php` |
| RememberMeService | `core/Service/Auth/RememberMeService.php` |
| RememberMeRateLimiter | `core/Service/Auth/RememberMeRateLimiter.php` |

View File

@@ -78,4 +78,4 @@ Unterschied zu den DB-basierten Limits oben: Memcached statt `request_rate_limit
1. API ohne Token >120 Requests/min gegen `/api/v1/*` -> `429` erwartet.
2. Web-Login mit falschem Passwort >5 pro E-Mail+IP -> `429` erwartet.
3. API-Login mit falschen Credentials wiederholt -> `429` erwartet.
4. Remember-Cookie mit falschem Token >5 pro IP -> Auto-Login blockiert, Cookie geloescht.
4. Remember-Cookie mit falschem Token >5 pro IP -> Auto-Login blockiert, Cookie gelöscht.

View File

@@ -4,9 +4,9 @@ Letzte Aktualisierung: 2026-03-19
## Ziel
`php bin/console doctor` ist der schnelle Gesundheitscheck fuer eine Instanz.
`php bin/console doctor` ist der schnelle Gesundheitscheck für eine Instanz.
Er prueft unter anderem:
Er prüft unter anderem:
- ENV-Validierung (Pflichtkeys + Formate)
- AppContainer-Bootstrap
@@ -35,13 +35,13 @@ docker compose exec php php bin/console doctor
- `0`: keine harten Fehler
- `1`: mindestens ein `FAIL`-Check
`WARN` fuehrt nicht zu Exit `1`, sollte aber geprueft werden.
`WARN` führt nicht zu Exit `1`, sollte aber geprüft werden.
## Typischer Einsatz im Betrieb
1. Direkt nach Neuinstallation / Deployment.
2. Bei 4xx/5xx-Symptomen als erster Schritt.
3. Nach Konfigurations- oder RBAC-Aenderungen.
3. Nach Konfigurations- oder RBAC-Änderungen.
## Beispielausgabe

View File

@@ -16,8 +16,8 @@ Neue Seiten schnell, konsistent und langfristig wartbar ergänzen.
Die Dokumentation folgt dem Diataxis-Modell mit genau vier Quadranten in dieser Reihenfolge:
1. **Tutorials** — Lernorientierte Schritt-fuer-Schritt-Anleitungen
2. **How-to Guides** — Aufgabenorientierte Anleitungen fuer konkrete Ziele
1. **Tutorials** — Lernorientierte Schritt-für-Schritt-Anleitungen
2. **How-to Guides** — Aufgabenorientierte Anleitungen für konkrete Ziele
3. **Explanation** — Verstaendnisorientierte Hintergrunderklaerungen
4. **Reference** — Informationsorientierte Fakten und Nachschlagewerke

View File

@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-04-01
## Ziel
QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-Blocker zu aktivieren.
QA-Pflichtchecks für CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-Blocker zu aktivieren.
## Enthaltene Basis
@@ -14,7 +14,7 @@ QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-B
## Was `qa-required` abdeckt
`bin/qa-required.sh` fuehrt die aktuell blockenden Gates aus:
`bin/qa-required.sh` führt die aktuell blockenden Gates aus:
- `QG-001` PHPUnit
- `QG-002` PHPStan
@@ -25,14 +25,14 @@ QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-B
## Phase-1 Setup (noch nicht blockend)
1. Sicherstellen, dass der Gitea-Runner Docker + Docker Compose ausfuehren darf.
2. Workflow-Datei nach `.gitea/workflows/qa-required.yaml` uebernehmen.
3. PR gegen `main` oeffnen und pruefen, dass Job `qa-required` gruen laeuft.
1. Sicherstellen, dass der Gitea-Runner Docker + Docker Compose ausführen darf.
2. Workflow-Datei nach `.gitea/workflows/qa-required.yaml` übernehmen.
3. PR gegen `main` öffnen und prüfen, dass Job `qa-required` gruen laeuft.
4. Branch Protection noch **nicht** auf "required" setzen.
## Phase-2 Aktivierung (blockend)
1. Branch-Protection fuer `main` aktivieren.
1. Branch-Protection für `main` aktivieren.
2. Statuscheck `qa-required` als required markieren.
3. Optional: weitere Jobs ergaenzen (z. B. nightly/extended Checks), aber nur `qa-required` blockend setzen.
@@ -40,4 +40,4 @@ QA-Pflichtchecks fuer CoreCore in Gitea vorbereiten, ohne sie sofort als Merge-B
- `QG-005` (Browser-Smoke) bleibt manuell/non-blocking.
- `QG-007` (composer-unused) bleibt periodisch/non-blocking.
- Fuer lokale Ausfuehrung: `bin/dev qa-required` bzw. `bin/dev qa-extended`.
- Fuer lokale Ausführung: `bin/dev qa-required` bzw. `bin/dev qa-extended`.

View File

@@ -47,7 +47,7 @@ Provider:
- `mapPreviewItem()`
- `mapResultItem()`
5. Bei Modul-Resources: Provider-Klasse in `module.php` unter `search_resources` registrieren.
6. i18n-Labels pruefen.
6. i18n-Labels prüfen.
## Wichtige Regeln

View File

@@ -12,7 +12,7 @@ Kompakter Tagesworkflow für Entwicklung, Tests und schema-nahe Änderungen.
bin/dev init
```
`bin/dev init` ist nicht-destruktiv und fuehrt aus:
`bin/dev init` ist nicht-destruktiv und führt aus:
1. `.env` aus `.env.example` erstellen (falls fehlend)
2. `docker compose up --build -d`
@@ -36,17 +36,17 @@ docker compose restart php nginx
## Module-Sync
Nach Aenderungen an Modulen, Manifesten oder `APP_ENABLED_MODULES`:
Nach Änderungen an Modulen, Manifesten oder `APP_ENABLED_MODULES`:
```bash
docker compose exec php php bin/console module:sync
```
Dieser Befehl fuehrt automatisch aus: `migrate``permissions-sync``build``assets-sync`.
Dieser Befehl führt automatisch aus: `migrate``permissions-sync``build``assets-sync`.
Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist der Sync noetig.
Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist der Sync nötig.
Alle verfuegbaren CLI-Kommandos: `php bin/console list` (siehe `/docs/reference-cli-commands.md`).
Alle verfügbaren CLI-Kommandos: `php bin/console list` (siehe `/docs/reference-cli-commands.md`).
Alle Dev-Orchestrator-Kommandos: `bin/dev --help`.
## Schema-Stand
@@ -70,7 +70,7 @@ docker compose exec php vendor/bin/phpunit
docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress
```
Bei Modul-/Manifest-Aenderungen zusaetzlich:
Bei Modul-/Manifest-Änderungen zusaetzlich:
```bash
docker compose exec php php bin/console module:sync

View File

@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-26
## Ziel
Schritt-fuer-Schritt Anleitung: vom leeren Verzeichnis zum lauffaehigen Modul mit Route, Permission, UI-Slot und Test.
Schritt-für-Schritt Anleitung: vom leeren Verzeichnis zum lauffaehigen Modul mit Route, Permission, UI-Slot und Test.
## Voraussetzungen
@@ -54,7 +54,7 @@ return [
];
```
Alternative: `APP_ENABLED_MODULES` Umgebungsvariable (ueberschreibt die Datei).
Alternative: `APP_ENABLED_MODULES` Umgebungsvariable (überschreibt die Datei).
## Schritt 3: Manifest konfigurieren
@@ -138,7 +138,7 @@ final class MeinModulContainerRegistrar implements ContainerRegistrar
}
```
Ohne diese Registrierung wird die Policy von `ModuleClassResolver` ignoriert und die Permission-Pruefung fuer UI-Slots schlaegt fehl (Slot wird nicht angezeigt).
Ohne diese Registrierung wird die Policy von `ModuleClassResolver` ignoriert und die Permission-Prüfung für UI-Slots schlaegt fehl (Slot wird nicht angezeigt).
## Schritt 5: Erste Seite anlegen
@@ -171,14 +171,14 @@ Datei `modules/mein-modul/pages/mein-modul/index(default).phtml`:
docker compose exec php php bin/console module:sync
```
Dieser Befehl fuehrt automatisch aus:
Dieser Befehl führt automatisch aus:
1. `module:migrate` — SQL-Migrationen anwenden
2. `module:permissions-sync` — Permissions registrieren
3. `module:build` — Seiten-Symlinks erstellen
4. `module:assets-sync` — CSS/JS-Assets veroeffentlichen
Nach jedem Manifest-Aenderung erneut ausfuehren.
Nach jedem Manifest-Änderung erneut ausführen.
## Schritt 7: Validieren
@@ -186,7 +186,7 @@ Nach jedem Manifest-Aenderung erneut ausfuehren.
docker compose exec php php bin/console module:validate mein-modul
```
Prueft: Manifest-Syntax, Klassen-Existenz, Namespace-Konventionen, Verzeichnisstruktur.
Prüft: Manifest-Syntax, Klassen-Existenz, Namespace-Konventionen, Verzeichnisstruktur.
## Schritt 8: Testen
@@ -195,7 +195,7 @@ docker compose exec php vendor/bin/phpunit --filter=MeinModul
docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon modules/mein-modul/
```
Architektur-Tests (pruefen automatisch Namespace-Isolation, Session-Key-Prefix, Manifest-Contract):
Architektur-Tests (prüfen automatisch Namespace-Isolation, Session-Key-Prefix, Manifest-Contract):
```bash
docker compose exec php vendor/bin/phpunit tests/Architecture/
@@ -203,7 +203,7 @@ docker compose exec php vendor/bin/phpunit tests/Architecture/
---
## Erweitern: Haeufige Erweiterungspunkte
## Erweitern: Häufige Erweiterungspunkte
### UI-Slot: Sidebar-Tab
@@ -278,11 +278,11 @@ Fuer globale Assets (auf jeder Seite) stattdessen `layout.head_style` oder `runt
Interface: `core/App/Module/Contracts/SessionProvider.php` (Methoden: `populate()`, `clear()`).
**Session-Key-Konvention:** `module.mein-modul.*` (wird per Architektur-Test geprueft).
**Session-Key-Konvention:** `module.mein-modul.*` (wird per Architektur-Test geprüft).
### Layout-Kontext
`LayoutContextProvider` implementieren — liefert Daten fuer Templates bei jedem Page-Render:
`LayoutContextProvider` implementieren — liefert Daten für Templates bei jedem Page-Render:
```php
'layout_context_providers' => [
@@ -292,7 +292,7 @@ Interface: `core/App/Module/Contracts/SessionProvider.php` (Methoden: `populate(
Interface: `core/App/Module/Contracts/LayoutContextProvider.php` (Methode: `provide()`).
**Key-Konvention:** Top-Level-Keys muessen namespaced sein: `mein-modul.nav`, nicht `nav`.
**Key-Konvention:** Top-Level-Keys müssen namespaced sein: `mein-modul.nav`, nicht `nav`.
### Event-Listener
@@ -308,7 +308,7 @@ Interface: `core/App/Module/Contracts/EventListener.php` (Methode: `handle(strin
### Scheduler-Job
Siehe `/docs/howto-geplante-aufgaben.md` und `modules/audit/module.php` fuer Beispiele.
Siehe `/docs/howto-geplante-aufgaben.md` und `modules/audit/module.php` für Beispiele.
### Modul-eigene Datenbank
@@ -317,16 +317,16 @@ Siehe `/docs/howto-geplante-aufgaben.md` und `modules/audit/module.php` fuer Bei
```
SQL-Dateien unter `modules/mein-modul/db/updates/` — idempotent (IF NOT EXISTS, ON DUPLICATE KEY).
Ausgefuehrt ueber `php bin/console module:migrate`.
Ausgeführt über `php bin/console module:migrate`.
### Uebersetzungen
### Übersetzungen
```php
'i18n_path' => 'i18n',
```
Dateien: `modules/mein-modul/i18n/default_de.json`, `modules/mein-modul/i18n/default_en.json`.
Schluessel werden per `t('key')` aufgeloest — identisch zu Core-Translations.
Schlüssel werden per `t('key')` aufgeloest — identisch zu Core-Translations.
### Abhaengigkeit von anderem Modul
@@ -334,7 +334,7 @@ Schluessel werden per `t('key')` aufgeloest — identisch zu Core-Translations.
'requires' => ['notifications'],
```
Nicht-deklarierte Cross-Module-Imports sind verboten und werden per Architektur-Test geprueft.
Nicht-deklarierte Cross-Module-Imports sind verboten und werden per Architektur-Test geprüft.
---
@@ -351,13 +351,13 @@ Nicht-deklarierte Cross-Module-Imports sind verboten und werden per Architektur-
- [ ] Session-Keys verwenden `module.<id>.*` Prefix
- [ ] Keine Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`) im Modul-Code
## Haeufige Fehler
## Häufige Fehler
| Problem | Ursache | Loesung |
| Problem | Ursache | Lösung |
|---|---|---|
| Sidebar-Tab/UI-Slot wird nicht angezeigt | AuthorizationPolicy nicht im Container registriert | Policy in ContainerRegistrar mit `PermissionService` registrieren |
| 404 auf Modul-Route | `module:sync` nicht ausgefuehrt | `php bin/console module:sync` |
| 404 auf Modul-Route | `module:sync` nicht ausgeführt | `php bin/console module:sync` |
| Permission existiert nicht | Permission nicht in Manifest deklariert | `permissions`-Array in `module.php` ergaenzen, dann `module:sync` |
| CSS/JS werden nicht geladen | Assets nicht veroeffentlicht | `php bin/console module:assets-sync` oder `module:sync` |
| RuntimeException: fingerprint mismatch | Build veraltet nach Manifest-Aenderung | `php bin/console module:sync` |
| RuntimeException: fingerprint mismatch | Build veraltet nach Manifest-Änderung | `php bin/console module:sync` |
| Namespace-Fehler in Tests | Modul-Klasse in Core-Namespace | Alle Klassen unter `MintyPHP\Module\<Name>\*` |

View File

@@ -2,15 +2,15 @@
Letzte Aktualisierung: 2026-03-06
Kurzstandard fuer neue Actions/Endpoints.
Kurzstandard für neue Actions/Endpoints.
## Regeln
- Input immer ueber `requestInput()`.
- Input immer über `requestInput()`.
- Validierungsfehler intern immer als `FormErrors`.
- API-Validation immer mit `ApiResponse::validationFromFormErrors(...)`.
- Web-Templates bekommen kompakte Fehlerlisten (`$errors`) aus `toFlatList()`.
- `Flash` ist fuer Redirect-/Outcome-Meldungen (z. B. Success) gedacht, nicht als primaerer Validation-Container.
- `Flash` ist für Redirect-/Outcome-Meldungen (z. B. Success) gedacht, nicht als primaerer Validation-Container.
- Bei Redirect-POST-Formen: `FormErrors` intern sammeln und erst am Redirect-Rand transportieren (z. B. `flashFormErrors(...)`).
## Web-Beispiel (Action)

View File

@@ -15,20 +15,20 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
4. `/docs/tutorial-04-architektur-request-flow.md`
- Request-Flow, Schichtmodell, Do/Don't.
5. `/docs/tutorial-05-erste-aenderung-ui.md`
- Erste sichere UI-Aenderung im Admin-Bereich.
- Erste sichere UI-Änderung im Admin-Bereich.
6. `/docs/tutorial-06-erste-aenderung-backend.md`
- Erste Backend-/Service-/Repository-Aenderung.
- Erste Backend-/Service-/Repository-Änderung.
7. `/docs/tutorial-07-security-tenant-scope.md`
- Sicherheitsgrundlagen, Tenant-Scope, Pflichtchecks.
8. `/docs/tutorial-08-api-erweitern.md`
- API-Aenderung sauber mit OpenAPI und Tests umsetzen.
- API-Änderung sauber mit OpenAPI und Tests umsetzen.
9. `/docs/tutorial-09-advanced-scheduler-sso.md`
- Fortgeschrittene Themen: Scheduler, Lifecycle, SSO.
## How-to Guides
- `/docs/howto-erste-aenderung.md`
- Schritt-fuer-Schritt durch die erste Codeaenderung.
- Schritt-für-Schritt durch die erste Codeänderung.
- `/docs/howto-globale-suche.md`
- Neue Resource in der globalen Suche integrieren.
- `/docs/howto-importe.md`
@@ -44,7 +44,7 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
- `/docs/howto-rbac-permissions-playbook.md`
- RBAC-Rechte sauber erweitern (neue Permission, neue Ability, UI/API-Faelle).
- `/docs/howto-request-input-validation.md`
- Einheitliches Request/Input- und Validation-Muster fuer Web + API.
- Einheitliches Request/Input- und Validation-Muster für Web + API.
- `/docs/howto-docker-lokal.md`
- Lokaler Docker-Betrieb.
- `/docs/howto-docker-produktiv.md`
@@ -52,15 +52,15 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
- `/docs/howto-betriebscheck-doctor.md`
- Schneller Systemcheck mit `php bin/console doctor`.
- `/docs/howto-fehlerbehebung.md`
- Haeufige Fehler und schnelle Loesungen.
- Häufige Fehler und schnelle Lösungen.
- `/docs/howto-lokale-entwicklung.md`
- Tages-Workflow fuer Entwicklung und Checks.
- Tages-Workflow für Entwicklung und Checks.
- `/docs/howto-modul-erstellen.md`
- Neues Modul erstellen: Scaffold, Manifest, Route, Permission, UI-Slot, Test.
- `/docs/howto-gitea-required-checks.md`
- Gitea-Workflow fuer `qa-required` vorbereiten (Phase 1 enforcement-ready).
- Gitea-Workflow für `qa-required` vorbereiten (Phase 1 enforcement-ready).
- `/docs/howto-dokumentation-erweitern.md`
- Regeln fuer konsistente, wachsende Doku.
- Regeln für konsistente, wachsende Doku.
## Explanation
@@ -75,7 +75,7 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
- `/docs/explanation-einstellungen-speicherung.md`
- Warum Settings in DB + Datei-Cache koexistieren.
- `/docs/explanation-docker-betrieb.md`
- Uebersicht und Entscheidungshilfe fuer Dev/Prod.
- Übersicht und Entscheidungshilfe für Dev/Prod.
## Reference
@@ -88,9 +88,9 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
- `/docs/reference-konventionen.md`
- Projektweite Konventionen (kurz und verbindlich).
- `/docs/reference-core-standards.md`
- Regeln speziell fuer `core/**`.
- Regeln speziell für `core/**`.
- `/docs/reference-benutzer-lifecycle-policy.md`
- Policy- und Laufzeitreferenz fuer User Lifecycle.
- Policy- und Laufzeitreferenz für User Lifecycle.
- `/docs/reference-frontend-css.md`
- CSS-Schichtsystem und Namenskonventionen.
- `/docs/reference-frontend-javascript.md`
@@ -98,13 +98,13 @@ Diese Dokumentation ist nach dem Diataxis-Modell in vier Quadranten gegliedert:
- `/docs/reference-entwickler-checkliste.md`
- Definition of Done vor Merge.
- `/docs/reference-codex-prompts.md`
- Standard-Prompts fuer Skill-basierte Planung und Implementierung.
- Standard-Prompts für Skill-basierte Planung und Implementierung.
- `/docs/reference-extension-readiness.md`
- Freigabe-Checkliste fuer weitere Module auf Basis des bestehenden Modul-Contracts.
- Freigabe-Checkliste für weitere Module auf Basis des bestehenden Modul-Contracts.
- `/docs/reference-cli-commands.md`
- Alle CLI-Kommandos (`php bin/console`), Bootstrap-Helfer, Anleitung neue Kommandos.
- `/docs/reference-module-manifest-contract.md`
- Verbindlicher Runtime- und Manifest-Contract fuer Module (V1.1).
- Verbindlicher Runtime- und Manifest-Contract für Module (V1.1).
- `/docs/reference-notifications-module.md`
- Verbindliche Referenz fuer Notifications (Events, Guardrails, Dedupe, Bell-Vertrag, Tests).
- Verbindliche Referenz für Notifications (Events, Guardrails, Dedupe, Bell-Vertrag, Tests).
- Agent-Workflow (Rollen, State-Machine, Contracts): siehe `/.agents/workflow.md`

View File

@@ -4,13 +4,13 @@ Letzte Aktualisierung: 2026-04-01
## Einstiegspunkt
Alle CLI-Kommandos laufen ueber einen einzigen Einstiegspunkt:
Alle CLI-Kommandos laufen über einen einzigen Einstiegspunkt:
```bash
php bin/console <command> [argumente] [optionen]
```
Uebersicht aller verfuegbaren Kommandos:
Übersicht aller verfügbaren Kommandos:
```bash
php bin/console list
@@ -32,9 +32,9 @@ Fuehrt den vollstaendigen Runtime-Sync aus: `db-migrate` → `migrate` → `perm
docker compose exec php php bin/console module:sync
```
Noetig nach jeder Aenderung an Modulen, Manifesten, Routen oder `APP_ENABLED_MODULES` — und nach jedem `git pull`, der Schema-Updates unter `db/updates/*.sql` mitbringt.
Nötig nach jeder Änderung an Modulen, Manifesten, Routen oder `APP_ENABLED_MODULES` — und nach jedem `git pull`, der Schema-Updates unter `db/updates/*.sql` mitbringt.
Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist dieser Befehl die Loesung.
Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist dieser Befehl die Lösung.
Maschinenlesbar:
@@ -52,7 +52,7 @@ Jede `db/updates/*.sql` MUSS idempotent sein (`CREATE TABLE IF NOT EXISTS`, `INS
docker compose exec php php bin/console db:migrate
```
`module:sync` ruft den Befehl als ersten Schritt automatisch auf. Direktaufruf nuetzlich, wenn nur DB-Updates gewuenscht sind ohne Module-Build.
`module:sync` ruft den Befehl als ersten Schritt automatisch auf. Direktaufruf nützlich, wenn nur DB-Updates gewuenscht sind ohne Module-Build.
Status-Anzeige (kein Schreibzugriff):
@@ -60,7 +60,7 @@ Status-Anzeige (kein Schreibzugriff):
docker compose exec php php bin/console db:migrate --status
```
Listet `applied:` und `pending:` separat — nuetzlich beim Debugging veralteter Schemata.
Listet `applied:` und `pending:` separat — nützlich beim Debugging veralteter Schemata.
### module:migrate
@@ -103,7 +103,7 @@ docker compose exec php php bin/console module:deactivate <module-id> --confirm
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
@@ -117,7 +117,7 @@ Der Docker-Scheduler-Service ruft dieses Kommando automatisch alle 60 Sekunden a
### module:validate
Validiert Manifest, Klassen und Struktur eines Moduls. Prueft JSON-Schema-Compliance des `module.php`, Namespace-Konventionen, Interface-Implementierungen, Permission-Key-Formate und Verzeichnisstruktur.
Validiert Manifest, Klassen und Struktur eines Moduls. Prüft JSON-Schema-Compliance des `module.php`, Namespace-Konventionen, Interface-Implementierungen, Permission-Key-Formate und Verzeichnisstruktur.
```bash
docker compose exec php php bin/console module:validate <module-id>
@@ -128,7 +128,7 @@ docker compose exec php php bin/console module:validate --all
### make:module
Erzeugt die vollstaendige Verzeichnisstruktur fuer ein neues Modul inkl. Manifest, ContainerRegistrar-Stub, AuthorizationPolicy-Stub und leeren Verzeichnissen.
Erzeugt die vollstaendige Verzeichnisstruktur für ein neues Modul inkl. Manifest, ContainerRegistrar-Stub, AuthorizationPolicy-Stub und leeren Verzeichnissen.
```bash
docker compose exec php php bin/console make:module <module-id>
@@ -144,7 +144,7 @@ Fuehrt System-Gesundheitschecks aus (ENV, DB, RBAC, Scheduler-Heartbeat).
docker compose exec php php bin/console doctor
```
Siehe `/docs/howto-betriebscheck-doctor.md` fuer Details.
Siehe `/docs/howto-betriebscheck-doctor.md` für Details.
Maschinenlesbar:
@@ -168,15 +168,15 @@ bin/dev qa-extended
```
`bin/dev console ...` delegiert intern auf `docker compose exec -T php php bin/console ...`.
`bin/dev qa` ist ein Alias fuer `bin/dev qa-required`.
`bin/dev qa` ist ein Alias für `bin/dev qa-required`.
## Neue Kommandos anlegen
1. Klasse in `core/Console/Commands/` erstellen, die `MintyPHP\Console\Command` erweitert.
2. `name()`, `description()` und `execute()` implementieren.
3. Optional: `usage()` fuer `--help`-Ausgabe ueberschreiben.
3. Optional: `usage()` für `--help`-Ausgabe überschreiben.
Das Kommando wird automatisch erkannt — kein manuelles Registrieren noetig.
Das Kommando wird automatisch erkannt — kein manuelles Registrieren nötig.
Beispiel:
@@ -204,5 +204,5 @@ Die `Command`-Basisklasse stellt Helfer bereit:
| Methode | Zweck |
|---|---|
| `$this->bootstrapApp($channel)` | App-Bootstrap fuer Nicht-Modul-Kommandos |
| `$this->bootstrapApp($channel)` | App-Bootstrap für Nicht-Modul-Kommandos |
| `$this->projectRoot()` | Gibt den absoluten Projekt-Root-Pfad zurueck |

View File

@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-09
## Ziel
Wiederverwendbare Prompt-Muster fuer konsistente Planung und Implementierung mit den Skills `core-guardrails` und `starterkit-planner`.
Wiederverwendbare Prompt-Muster für konsistente Planung und Implementierung mit den Skills `core-guardrails` und `starterkit-planner`.
## Prompt: Implementierung (strict)

View File

@@ -45,9 +45,9 @@ Kurze Definition of Done vor Merge.
- [ ] Runtime-Komponenten folgen Contract `init(root, config) -> { destroy() }`
- [ ] Runtime-Komponenten enthalten keinen eigenen `DOMContentLoaded`-/Sideeffect-Auto-Init
- [ ] Listener/Timer/Observer aus Runtime-Komponenten werden in `destroy()` sauber abgebaut
- [ ] Runtime-Konfiguration liegt in `page-config-app-components` (default) bzw. `page-config-login-components` (login) und wird ueber `readPageConfig(...)` gelesen
- [ ] Runtime-Konfiguration liegt in `page-config-app-components` (default) bzw. `page-config-login-components` (login) und wird über `readPageConfig(...)` gelesen
- [ ] Host-gebundene Runtime-Komponenten haben explizite `data-app-component`-Hosts im Markup
- [ ] Global-Utilities ohne natuerliches Host-Element sind explizit runtime-global registriert (`scope: 'global'`)
- [ ] Global-Utilities ohne natürliches Host-Element sind explizit runtime-global registriert (`scope: 'global'`)
- [ ] Service-Auflösung in `pages/**`/`templates/**`/`core/Support/**` nur via `app(Foo::class)`
- [ ] Keine `new ...Factory()` in `core/Service/**` außerhalb `*Factory.php`
- [ ] Keine direkten `new ...Service()`, `new ...Gateway()`, `new ...Repository()` in `core/Service/**` außerhalb `*Factory.php`
@@ -74,12 +74,12 @@ Kurze Definition of Done vor Merge.
- [ ] `docker compose exec php vendor/bin/phpunit` zweimal hintereinander in identischer Umgebung (beide Runs gruen)
- [ ] `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress`
- [ ] `docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php`
- [ ] bei Modul-/Manifest-/Routen-Aenderungen: `APP_ENABLED_MODULES='' php bin/console module:sync`
- [ ] bei Modul-/Manifest-/Routen-Aenderungen: `APP_ENABLED_MODULES='addressbook,bookmarks' php bin/console module:sync`
- [ ] bei Modul-/Manifest-/Routen-Änderungen: `APP_ENABLED_MODULES='' php bin/console module:sync`
- [ ] bei Modul-/Manifest-/Routen-Änderungen: `APP_ENABLED_MODULES='addressbook,bookmarks' php bin/console module:sync`
- [ ] Runtime-Sync erzeugt Step-Summary (`migrate`, `permissions-sync`, `build`, `assets-sync`) und `vendor_warnings_ignored=<n>`
- [ ] Keine First-party CLI-Warnings/Notices/Deprecations im Runtime-Sync (Vendor-Warnings sind nur temporaer toleriert und muessen gezaehlt sichtbar sein)
- [ ] bei Docs-/Skills-Aenderungen: `docker compose exec php vendor/bin/phpunit tests/Architecture/CodexSkillReferenceContractTest.php`
- [ ] `bin/docs-link-check.sh` (QG-008, scannt standardmaessig ohne `.agents/runs/**`)
- [ ] Keine First-party CLI-Warnings/Notices/Deprecations im Runtime-Sync (Vendor-Warnings sind nur temporaer toleriert und müssen gezaehlt sichtbar sein)
- [ ] bei Docs-/Skills-Änderungen: `docker compose exec php vendor/bin/phpunit tests/Architecture/CodexSkillReferenceContractTest.php`
- [ ] `bin/docs-link-check.sh` (QG-008, scannt standardmäßig ohne `.agents/runs/**`)
- [ ] `bin/docs-drift-check.sh` (QG-008-Zusatz, blockt Legacy-Referenzen + fehlenden Setup-Vertrag)
- [ ] `bin/codex-skills-sync.sh --check` (QG-009)
- [ ] bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors)

View File

@@ -4,13 +4,13 @@ Letzte Aktualisierung: 2026-03-18
## Ziel
Verbindliche Vorbedingungen fuer weitere eigenstaendige Module auf dem bestehenden Modul-System festhalten.
Verbindliche Vorbedingungen für weitere eigenstaendige Module auf dem bestehenden Modul-System festhalten.
## Kanonische Quelle
Normativer Manifest- und Runtime-Contract: `/docs/reference-module-manifest-contract.md`.
Diese Readiness-Doku ist bewusst kurz und verweist fuer Felddefinitionen/Guards immer auf den Manifest-Contract.
Diese Readiness-Doku ist bewusst kurz und verweist für Felddefinitionen/Guards immer auf den Manifest-Contract.
## Readiness-Checkliste vor Modul 2+
@@ -21,17 +21,17 @@ Diese Readiness-Doku ist bewusst kurz und verweist fuer Felddefinitionen/Guards
- `module.php` validiert gegen den kanonischen Contract (`permissions`, `scheduler_jobs`, `ui_slots`, `routes`).
- Route-/Slot-/Layout-Guards laufen fail-fast.
3. **Security + Scope absichern**
- AuthZ/RBAC serverseitig pruefen.
- Tenant-Scope serverseitig pruefen.
- AuthZ/RBAC serverseitig prüfen.
- Tenant-Scope serverseitig prüfen.
- POST-Mutationen mit CSRF absichern.
4. **Runtime-Hygiene absichern**
- `php bin/console module:sync` laeuft reproduzierbar mit standardisierter Step-Summary.
- Keine First-party CLI-Warnings/Notices/Deprecations; Vendor-Rauschen wird nur gezaehlt/reportet.
5. **Testbarkeit und Gates**
- Architektur- und Domain-Tests fuer neue Logik ergaenzen.
- Architektur- und Domain-Tests für neue Logik ergaenzen.
- `phpunit` und `phpstan` als Pflicht-Gates gruen.
6. **Daten- und Betriebsfaehigkeit**
- Schema-/Datenaenderungen fuer Bestandsinstallationen idempotent in `db/updates/*.sql`.
- Schema-/Datenänderungen für Bestandsinstallationen idempotent in `db/updates/*.sql`.
- Logs/Audit ohne unredacted PII/Secrets.
## Derzeit Out of Scope
@@ -39,7 +39,7 @@ Diese Readiness-Doku ist bewusst kurz und verweist fuer Felddefinitionen/Guards
- Eigener DB-Server oder Netzwerk-Microservice je Modul.
- Externe Drittanbieter-Module mit Legacy-Kompatibilitaet.
## Verfuegbare Core-Services fuer Module
## Verfügbare Core-Services für Module
JS-seitig:

View File

@@ -88,6 +88,6 @@ Regel: Vendor-Overrides nur für Bibliotheks-Selektoren; projektspezifische UI-S
## Module-CSS Token-Regel
1. Modul-CSS nutzt primär Core-Tokens (`--app-*`) statt eigener Farbwerte.
2. Modul-spezifische Variablen sind als Alias erlaubt, muessen aber auf Core-Tokens mappen.
2. Modul-spezifische Variablen sind als Alias erlaubt, müssen aber auf Core-Tokens mappen.
3. Keine Legacy-/Phantom-Tokens (`--app-text`, `--app-hover`, `--app-border-light`) neu einführen.
4. Harte Hex-Fallbacks nur als Ausnahmefall, nicht als Standard.

View File

@@ -48,14 +48,14 @@ Empfohlenes Muster:
- `destroy()` muss alle Listener/Timer/Observer abbauen.
- Hybrid Host-Policy:
- Host-gebundene UI-Komponenten nutzen explizite `data-app-component`-Hosts im Markup.
- Tabs sind host-gebunden und laufen ausschliesslich ueber `data-app-component="tabs"`.
- Globale Utilities ohne natuerliches Host-Element werden runtime-global (`scope: 'global'`) registriert, aber mit demselben Lifecycle-Contract.
- Root-Strict gilt fuer host-gebundene Komponenten: keine `document.querySelector`-Fallback-Pfade.
- Projektseitige Custom-Globals auf `window.*` sind verboten; Komponenten kommunizieren ueber Core-Channels.
- Tabs sind host-gebunden und laufen ausschliesslich über `data-app-component="tabs"`.
- Globale Utilities ohne natürliches Host-Element werden runtime-global (`scope: 'global'`) registriert, aber mit demselben Lifecycle-Contract.
- Root-Strict gilt für host-gebundene Komponenten: keine `document.querySelector`-Fallback-Pfade.
- Projektseitige Custom-Globals auf `window.*` sind verboten; Komponenten kommunizieren über Core-Channels.
## UI Storage Contract
- Persistente UI-States laufen fuer Runtime-Komponenten ueber `web/js/core/app-ui-storage.js`.
- Persistente UI-States laufen für Runtime-Komponenten über `web/js/core/app-ui-storage.js`.
- Storage-Keys sind namespaced (`namespace:version:scope:*`) statt ungeordnet verteilt.
- Hard-Cut-Policy: keine Legacy-Key-Fallbacks und kein Legacy-Key-Sync in migrierten Runtime-Komponenten/Core-Modulen.

View File

@@ -5,7 +5,7 @@ Letzte Aktualisierung: 2026-04-01
Alle Konfiguration erfolgt über Umgebungsvariablen in der `.env`-Datei.
Vorlage: `.env.example` — niemals echte Credentials committen.
Setup-Vertrag (Source of Truth): `config/config.php` ist im Repository getrackt und liest alle Werte über `$envString()`/`$envInt()`/`$envBool()` aus den ENV-Variablen. Diese Seite und `web/index.php` sind die massgeblichen Referenzen dafuer.
Setup-Vertrag (Source of Truth): `config/config.php` ist im Repository getrackt und liest alle Werte über `$envString()`/`$envInt()`/`$envBool()` aus den ENV-Variablen. Diese Seite und `web/index.php` sind die maßgeblichen Referenzen dafür.
---

View File

@@ -53,7 +53,7 @@ Letzte Aktualisierung: 2026-03-24
- Namespace: `MintyPHP\Module\<Name>\*` — nie Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`).
- Verzeichnis: `modules/<id>/lib/Module/<Name>/` (Service, Repository, Providers, Support).
- 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.
- Tests: `modules/<id>/tests/` (werden von `phpunit.xml` automatisch entdeckt via `modules/*/tests`).
- Modul-Actions importieren nie `OperationsAuthorizationPolicy::ABILITY_*` — eigene Policy nutzen.
@@ -63,5 +63,5 @@ Letzte Aktualisierung: 2026-03-24
- `docker compose exec php vendor/bin/phpunit`
- `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress`
- bei Modul-/Manifest-Aenderungen: `docker compose exec php php bin/console module:sync`
- bei Modul-/Manifest-Änderungen: `docker compose exec php php bin/console module:sync`
- bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors)

View File

@@ -4,11 +4,11 @@ Letzte Aktualisierung: 2026-03-25
## Ziel
Verbindlicher Contract fuer `modules/*/module.php`, damit Module zur Runtime deterministisch geladen und validiert werden.
Verbindlicher Contract für `modules/*/module.php`, damit Module zur Runtime deterministisch geladen und validiert werden.
## Status
Dieses Dokument ist die kanonische (normative) Quelle fuer Manifest-, Runtime- und Guard-Regeln des Modul-Systems.
Dieses Dokument ist die kanonische (normative) Quelle für Manifest-, Runtime- und Guard-Regeln des Modul-Systems.
`/docs/reference-extension-readiness.md` referenziert diesen Contract und dupliziert keine Felddefinitionen.
## JSON-Schema-Enforcement
@@ -25,8 +25,8 @@ Ein Manifest muss sowohl:
## Namespace-Konvention
Alle PHP-Klassen eines Moduls muessen den Namespace `MintyPHP\Module\<Name>\*` verwenden.
Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`, `MintyPHP\Support\*`) sind fuer Modul-Code verboten.
Alle PHP-Klassen eines Moduls müssen den Namespace `MintyPHP\Module\<Name>\*` verwenden.
Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`, `MintyPHP\Support\*`) sind für Modul-Code verboten.
Verzeichnis-Layout:
@@ -75,8 +75,8 @@ Der `ModuleAutoloader` registriert daraus den absoluten Pfad `modules/<id>/i18n/
```
- `key` und `description` sind Pflichtfelder.
- Runtime-Sync erfolgt ueber `php bin/console module:sync`.
- `module:sync` fuehrt diesen Sync automatisch aus.
- Runtime-Sync erfolgt über `php bin/console module:sync`.
- `module:sync` führt diesen Sync automatisch aus.
## `scheduler_jobs` Contract
@@ -101,8 +101,8 @@ Der `ModuleAutoloader` registriert daraus den absoluten Pfad `modules/<id>/i18n/
],
```
- Manifest ist Source of Truth fuer Job-Metadaten und Defaults.
- Handler werden zur Laufzeit container-resolvable fuer `execute(...)` geladen.
- Manifest ist Source of Truth für Job-Metadaten und Defaults.
- Handler werden zur Laufzeit container-resolvable für `execute(...)` geladen.
## `ui_slots` Contract (V1.2)
@@ -118,15 +118,15 @@ Neue generische Slot-Typen:
Abgrenzung CSS:
- `layout.head_style` = global auf allen Seiten.
- `asset_groups` = seiten-/kontextbezogen ueber `style_groups`.
- `asset_groups` = seiten-/kontextbezogen über `style_groups`.
## Guard-Regeln
- Route-Kollisionen sind fail-fast:
- Modul vs Modul auf `target` und `path`.
- Modul vs Core auf `path` beim Router-Boot.
- Layout-Provider duerfen reservierte Core-Keys nicht ueberschreiben (`moduleSlots`, `csrfKey`, `currentTenant`, ...).
- Layout-Provider-Top-Level-Keys muessen namespaced sein (`<module_id>.<key>`).
- Layout-Provider duerfen reservierte Core-Keys nicht überschreiben (`moduleSlots`, `csrfKey`, `currentTenant`, ...).
- Layout-Provider-Top-Level-Keys müssen namespaced sein (`<module_id>.<key>`).
## Runtime-Fingerprint
@@ -141,16 +141,16 @@ Methoden: `ModuleRuntimePageBuilder::expectedFingerprint()`, `readFingerprint()`
## API-Channel-Isolation
API-Requests (`api/`-Prefix) ueberspringen den gesamten Web-Session-Flow:
API-Requests (`api/`-Prefix) überspringen den gesamten Web-Session-Flow:
- Kein `Session::start()`, kein Cookie-Setting, kein CSRF-Token
- Kein Remember-Me, kein Session-Timeout, kein Tenant-UI-Refresh
- API-Auth erfolgt ueber `ApiBootstrap.php` (Bearer-Token)
- API-Auth erfolgt über `ApiBootstrap.php` (Bearer-Token)
- `AccessControl` listet `api/` als always-public
## Standard-Runbook
`php bin/console module:sync` fuehrt in fester Reihenfolge aus:
`php bin/console module:sync` führt in fester Reihenfolge aus:
1. `module:migrate`
2. `module:permissions-sync`

View File

@@ -4,7 +4,7 @@ Letzte Aktualisierung: 2026-03-25
## Ziel
Referenz fuer das Modul `notifications`: Event-Registrierung, Erzeugungsregeln, Guardrails, Frontend-Vertrag und Testbarkeit.
Referenz für das Modul `notifications`: Event-Registrierung, Erzeugungsregeln, Guardrails, Frontend-Vertrag und Testbarkeit.
## Scope v1
@@ -15,7 +15,7 @@ Referenz fuer das Modul `notifications`: Event-Registrierung, Erzeugungsregeln,
- `user.activated`
- `user.deactivated`
- `user.assignment_changed`
- Dedupe fuer diese Typen mit 30 Minuten Fenster.
- Dedupe für diese Typen mit 30 Minuten Fenster.
## Modul-Verkabelung
@@ -25,7 +25,7 @@ Kanonische Quelle: `modules/notifications/module.php`
- mappt Eventtyp -> Listenerklasse + Methode `handle`.
- `ui_slots`
- `topbar.right_item`: Bell-Template
- `layout.head_style`: Modul-CSS fuer Topbar + Dropdown
- `layout.head_style`: Modul-CSS für Topbar + Dropdown
- `runtime.component`: Bell-JS (`initNotificationBell`)
- `permissions`
- `notifications.view`
@@ -45,9 +45,9 @@ Kanonische Quelle: `modules/notifications/module.php`
5. `NotificationRepository` persistiert in `user_notifications`.
6. Bell-Endpunkte lesen tenant-scoped Daten und aktualisieren den Session-`unread_count`.
## Producer-Contract (fuer Core + andere Module)
## Producer-Contract (für Core + andere Module)
Stabile Erzeugung erfolgt ueber:
Stabile Erzeugung erfolgt über:
- `MintyPHP\Module\Notifications\Service\NotificationMessage`
- `MintyPHP\Module\Notifications\Service\NotificationService::createFromMessage(...)`
@@ -78,7 +78,7 @@ $notificationService->createForTenantAdminUsersFromMessage(
);
```
Plain/Fallback-Erzeugung bleibt moeglich mit `NotificationMessage::plain(...)`.
Plain/Fallback-Erzeugung bleibt möglich mit `NotificationMessage::plain(...)`.
## Datenvertrag Notification
@@ -90,7 +90,7 @@ Persistierter Kernvertrag:
- `link` (nullable string)
- `data` (nullable JSON)
Erweiterung fuer locale-neutrale Texte:
Erweiterung für locale-neutrale Texte:
- `data.__message.title_key` (string)
- `data.__message.title_params` (array)
@@ -111,20 +111,20 @@ Dedupe-Metadaten (intern):
- Alle Bell-Endpunkte erzwingen:
- Login
- Ability `notifications.view`
- POST-Endpunkte (`mark-read`, `delete`) pruefen CSRF.
- POST-Endpunkte (`mark-read`, `delete`) prüfen CSRF.
- Tenant-Scope wird serverseitig aus `current_tenant` erzwungen.
- SQL ausschliesslich im Repository (`NotificationRepository`), Service nur Orchestrierung.
## Guardrails (Frontend)
- Endpunkte werden mit App-Base-URL gebaut (kein harter Root-Pfad).
- Fehlerpfade laufen ueber zentrale Telemetrie (`warn_once`).
- Fehlerpfade laufen über zentrale Telemetrie (`warn_once`).
- A11y-Klickzeilen im Dropdown sind lokal gestylt, damit globale `[role="button"]` Regeln nicht durchschlagen.
- Default-`details/summary`-Chevron wird pro Komponente ueber `data-summary-chevron="none"` deaktiviert.
- Default-`details/summary`-Chevron wird pro Komponente über `data-summary-chevron="none"` deaktiviert.
## Template/Partial Best Practice
- Core-Partials immer ueber `templatePath('partials/...')` einbinden.
- Core-Partials immer über `templatePath('partials/...')` einbinden.
- Keine fragilen relativen Tiefenpfade auf Core-Templates verwenden.
- Modulinterne Templates bleiben lokal relativ zum Modul.
@@ -138,22 +138,22 @@ Dedupe-Metadaten (intern):
### Unit
- Listener-Tests fuer alle Core-5 Typen:
- Listener-Tests für alle Core-5 Typen:
- Empfaengerregeln
- Actor-Exclusion
- ungultige/leere Payloads
- Service-Tests fuer Dedupe (created vs suppressed)
- Policy-Tests fuer `notifications.view`
- Service-Tests für Dedupe (created vs suppressed)
- Policy-Tests für `notifications.view`
### Integration/Flow
- End-to-End fuer create/delete/activate/deactivate/assignment-change.
- Bell-Endpunkte mit Tenant-Scope und Permission-Pruefung.
- End-to-End für create/delete/activate/deactivate/assignment-change.
- Bell-Endpunkte mit Tenant-Scope und Permission-Prüfung.
- Bulk-Flows dispatchen konsistent.
### Manueller Smoke
1. Zwei Admins im selben Tenant, einer als Actor.
2. Actor fuehrt User-Aktion aus.
2. Actor führt User-Aktion aus.
3. Zweiter Admin sieht Bell-Badge + Listeneintrag.
4. Wiederholung innerhalb 30 Minuten erzeugt kein Duplikat.