From 5da506a20f9265dc49c862b7b3dd3a6a9ac5eab2 Mon Sep 17 00:00:00 2001 From: fs Date: Wed, 18 Mar 2026 22:58:15 +0100 Subject: [PATCH] documentation update with module guidelines --- CLAUDE.md | 43 ++++++++++++++++++---- agent-system/checks/guard-catalog.json | 28 ++++++++++++++ docs/howto-lokale-entwicklung.md | 20 +++++++++- docs/reference-konventionen.md | 16 +++++++- docs/reference-module-manifest-contract.md | 42 ++++++++++++++++++++- 5 files changed, 137 insertions(+), 12 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d511170..0229b2f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,6 +25,9 @@ docker compose exec php vendor/bin/phpunit # Run PHPStan (level 5) docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress +# Sync module runtime (after module changes or APP_ENABLED_MODULES change) +docker compose exec php php bin/module-runtime-sync.php + # Check unused Composer packages docker compose exec php vendor/bin/composer-unused ``` @@ -34,30 +37,40 @@ docker compose exec php vendor/bin/composer-unused ``` lib/ # All backend PHP (namespace MintyPHP\) App/ # DI container + bootstrap (AppContainer, Container/Registrars/) + Module/ # Module platform (Registry, Manifest, Autoloader, Builder) Repository/ # SQL queries, prepared statements, filters/paging Service/ # Business logic, validation, orchestration Http/ # Auth guards, API auth, request helpers Input/ # Request input handling (RequestInput, FormErrors) Support/ # Crypto, flash, guard, search, helpers -pages/ # Actions (controllers) — file-based routing +modules/ # Self-contained feature modules (namespace MintyPHP\Module\\) + /module.php # Module manifest (routes, slots, providers, permissions) + /lib/ # Module PHP classes (Service, Repository, Providers) + /pages/ # Module actions + views (symlinked into runtime) + /templates/ # Module-specific templates + /web/ # Module CSS/JS (published to web/modules//) + /tests/ # Module PHPUnit tests +pages/ # Core actions (controllers) — file-based routing pages/**/*.php # Action files (read input, check permissions, call services) pages/**/*.phtml # View files (rendering only, no DB calls) -templates/ # Layouts and partials +templates/ # Core layouts and partials partials/ # Reusable UI components emails/ # Email HTML templates pdfs/ # PDF templates (Dompdf) -config/ # App config (routes, assets, settings cache, themes) +config/ # App config (routes, assets, settings cache, themes, modules) web/ # Document root (entry point, CSS, JS, static assets) - js/core/ # DOM utilities, Grid.js factory + js/core/ # DOM utilities, Grid.js factory, component runtime js/components/ # Reusable UI components css/ # Layered CSS (base → components → layout → pages) -storage/ # Uploaded files (branding/, imports/, tenants/, users/) + modules/ # Published module assets (symlinks to modules//web/) +storage/ # Uploaded files + runtime state + runtime/pages/ # Symlinked page tree (core + modules, built by module-build) db/init/init.sql # Full schema + seed data (no migration framework) db/updates/ # Idempotent SQL update scripts for existing installs tests/ # PHPUnit tests (namespace MintyPHP\Tests\) docs/ # German-language documentation (Markdown) i18n/ # Translation files (de, en) -bin/ # CLI scripts (scheduler, doctor.php health check) +bin/ # CLI scripts (scheduler, module-runtime-sync, doctor.php) tools/ # Dev tooling scripts docker/ # Dockerfiles, Nginx configs, PHP configs ``` @@ -77,16 +90,30 @@ docker/ # Dockerfiles, Nginx configs, PHP configs 5. **View** (`pages/**/*.phtml`): Pure rendering. **No DB calls.** HTML escaping via `e(...)`. 6. **Template** (`templates/`): Layouts and partials. +### Modules + +- Modules are self-contained feature packages under `modules//` +- **Namespace:** `MintyPHP\Module\\*` — never use core namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`) +- **Manifest:** `module.php` declares routes, UI slots, providers, permissions, scheduler jobs +- **UI integration:** Only via platform slots (`aside.tab_panel`, `topbar.right_item`, `layout.head_style`, `runtime.component`, etc.) — no core template hardcoding +- **Session keys:** Prefixed with `module..*` +- **Activation:** `config/modules.php` or `APP_ENABLED_MODULES` env override +- **Runtime sync:** `php bin/module-runtime-sync.php` after any module/manifest change (builds page symlinks, syncs permissions, publishes assets) +- **Fingerprint guard:** `web/index.php` validates runtime state matches active modules; fails fast if stale +- **API isolation:** API requests (`api/` prefix) skip session/auth/cookie flows entirely; modules using API endpoints rely on `ApiBootstrap.php` + ### Routing - File-based: `pages/admin/users/edit($id).php` → URL parameter `id` +- Module pages: `modules//pages/` symlinked into `storage/runtime/pages/` at build time - `...(none).phtml` → no template layout - `data().php` suffix → data/AJAX endpoints - Named aliases in `config/routes.php` with `public` flag for auth guard +- Module routes declared in manifest, merged at boot (fail-fast on collision) ### PHP Conventions -- PSR-4 autoload: `MintyPHP\` → `lib/`, `MintyPHP\Tests\` → `tests/` +- PSR-4 autoload: `MintyPHP\` → `lib/`, `MintyPHP\Module\*` → `modules/*/lib/`, `MintyPHP\Tests\` → `tests/` - All user-facing text uses `t('key')` translation helper - Permissions + tenant scope enforced in actions/services, never just in UI - Security/integration settings stay in DB, not in `config/settings.php` file cache @@ -115,7 +142,7 @@ docker/ # Dockerfiles, Nginx configs, PHP configs ## Quality Gates -- **PHPStan level 5** — scans `config/`, `lib/`, `pages/`, `tests/` +- **PHPStan level 5** — scans `config/`, `lib/`, `modules/`, `pages/`, `tests/` - **PHPUnit 11** — bootstrap: `tests/bootstrap.php` - **Frontend Smoke-Check** — browser console bleibt fehlerfrei in Kernflows - **composer-unused** — periodic check for unused dependencies diff --git a/agent-system/checks/guard-catalog.json b/agent-system/checks/guard-catalog.json index af3a40a..cd8f0dc 100644 --- a/agent-system/checks/guard-catalog.json +++ b/agent-system/checks/guard-catalog.json @@ -268,6 +268,34 @@ "requirement": "MUST check existing CSS layers (base, components, layout, pages) for suitable classes before writing new rules. MUST use existing app-* component classes as the basis and only add additive overrides. MUST NOT duplicate declarations already defined in shared component or layout files.", "source": "tools/codex-skills/core-guardrails/references/boundaries-ui.md" }, + { + "id": "GR-MOD-001", + "area": "core", + "title": "Module classes must use MintyPHP\\Module\\ namespace", + "requirement": "All PHP classes under modules//lib/ MUST use the MintyPHP\\Module\\\\ namespace. MUST NOT use core namespaces (MintyPHP\\Service\\, MintyPHP\\Repository\\, MintyPHP\\Support\\, MintyPHP\\Http\\). Enforced by ModuleStructureContractTest::testModuleClassesUseModuleNamespace.", + "source": "docs/reference-module-manifest-contract.md" + }, + { + "id": "GR-MOD-002", + "area": "core", + "title": "Module runtime fingerprint must be current", + "requirement": "After any module/manifest/APP_ENABLED_MODULES change, MUST run php bin/module-runtime-sync.php before serving requests. web/index.php validates the runtime fingerprint and fails fast if stale. MUST NOT bypass or remove the fingerprint check.", + "source": "docs/reference-module-manifest-contract.md" + }, + { + "id": "GR-MOD-003", + "area": "ui", + "title": "Module UI only via platform slots", + "requirement": "Module UI contributions MUST use platform slots (aside.tab_panel, topbar.right_item, layout.head_style, layout.body_end_template, runtime.component, search.resource_item). MUST NOT add module-specific markup to core templates. Enforced by NoBookmarksHardcodingTest and NoAddressBookHardcodingTest.", + "source": "docs/reference-module-manifest-contract.md" + }, + { + "id": "GR-SEC-007", + "area": "security", + "title": "API requests must not start PHP sessions", + "requirement": "API requests (api/ prefix) MUST NOT trigger Session::start(), remember-me cookie handling, or session timeout redirects. API authentication is handled by ApiBootstrap.php with Bearer tokens. web/index.php enforces this via channel detection before session initialization.", + "source": "docs/reference-module-manifest-contract.md" + }, { "id": "GR-UI-017", "area": "ui", diff --git a/docs/howto-lokale-entwicklung.md b/docs/howto-lokale-entwicklung.md index 3587a0e..e833886 100644 --- a/docs/howto-lokale-entwicklung.md +++ b/docs/howto-lokale-entwicklung.md @@ -1,6 +1,6 @@ # Lokale Entwicklung -Letzte Aktualisierung: 2026-03-09 +Letzte Aktualisierung: 2026-03-18 ## Ziel @@ -21,6 +21,18 @@ Bei inkonsistentem Laufzeitverhalten: docker compose restart php nginx ``` +## Module-Sync + +Nach Aenderungen an Modulen, Manifesten oder `APP_ENABLED_MODULES`: + +```bash +docker compose exec php php bin/module-runtime-sync.php +``` + +Dieser Befehl fuehrt automatisch aus: `migrate` → `permissions-sync` → `build` → `assets-sync`. + +Falls `web/index.php` den Fehler "Module runtime is stale" wirft, ist der Sync noetig. + ## Schema-Stand - Basis-Schema + Seeds: `db/init/init.sql` @@ -42,6 +54,12 @@ 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: + +```bash +docker compose exec php php bin/module-runtime-sync.php +``` + Bei JS-Änderungen zusätzlich Browser-Smoke mit DevTools-Console (keine JS-Errors). ## Struktur-Gates (empfohlen) diff --git a/docs/reference-konventionen.md b/docs/reference-konventionen.md index f710e26..46af66f 100644 --- a/docs/reference-konventionen.md +++ b/docs/reference-konventionen.md @@ -1,6 +1,6 @@ # Konventionen (kurz und verbindlich) -Letzte Aktualisierung: 2026-03-17 +Letzte Aktualisierung: 2026-03-18 ## 1) Code @@ -48,8 +48,20 @@ Letzte Aktualisierung: 2026-03-17 - Runtime-Komponenten nur über Lifecycle-Contract (`init(root, config)` + `destroy()`), ohne komponenteneigenen Auto-Init. - Host-gebundene Runtime-Komponenten über `data-app-component` markieren; nur echte Global-Utilities ohne Host als runtime-global registrieren. -## 6) Mindestchecks vor Merge +## 7) Module + +- Namespace: `MintyPHP\Module\\*` — nie Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`). +- Verzeichnis: `modules//lib/Module//` (Service, Repository, Providers, Support). +- Session-Keys: Prefix `module..*`. +- UI-Integration nur ueber Plattform-Slots (`aside.tab_panel`, `topbar.right_item`, `layout.head_style`, `runtime.component`, etc.). +- Kein Modul-spezifisches Markup in Core-Templates. +- Tests: `modules//tests/` (werden von `phpunit.xml` automatisch entdeckt via `modules/*/tests`). +- Modul-Actions importieren nie `OperationsAuthorizationPolicy::ABILITY_*` — eigene Policy nutzen. +- Manifest-Contract: `/docs/reference-module-manifest-contract.md`. + +## 8) Mindestchecks vor Merge - `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/module-runtime-sync.php` - bei JS-Änderungen: Browser-Smoke mit DevTools-Console (keine JS-Errors) diff --git a/docs/reference-module-manifest-contract.md b/docs/reference-module-manifest-contract.md index 2fb3f70..8548139 100644 --- a/docs/reference-module-manifest-contract.md +++ b/docs/reference-module-manifest-contract.md @@ -1,4 +1,4 @@ -# Module Manifest Contract (V1.1) +# Module Manifest Contract (V1.2) Letzte Aktualisierung: 2026-03-18 @@ -11,6 +11,26 @@ Verbindlicher Contract fuer `modules/*/module.php`, damit Module zur Runtime det Dieses Dokument ist die kanonische (normative) Quelle fuer Manifest-, Runtime- und Guard-Regeln des Modul-Systems. `/docs/reference-extension-readiness.md` referenziert diesen Contract und dupliziert keine Felddefinitionen. +## Namespace-Konvention + +Alle PHP-Klassen eines Moduls muessen den Namespace `MintyPHP\Module\\*` verwenden. +Core-Namespaces (`MintyPHP\Service\*`, `MintyPHP\Repository\*`, `MintyPHP\Support\*`) sind fuer Modul-Code verboten. + +Verzeichnis-Layout: + +``` +modules//lib/Module// + Service/ # BookmarkService, Factory, etc. + Repository/ # Repository + Interfaces + Providers/ # SessionProvider, LayoutProvider, SearchProvider + Support/ # Modul-spezifische Utilities + ContainerRegistrar.php + AuthorizationPolicy.php +``` + +Der `ModuleAutoloader` mappt `MintyPHP\*` → `modules//lib/` per PSR-4. +Enforcement: `ModuleStructureContractTest::testModuleClassesUseModuleNamespace`. + ## Aktivierung (`APP_ENABLED_MODULES`) - nicht gesetzt: `config/modules.php` gilt. @@ -86,6 +106,26 @@ Abgrenzung CSS: - Layout-Provider duerfen reservierte Core-Keys nicht ueberschreiben (`moduleSlots`, `csrfKey`, `currentTenant`, ...). - Layout-Provider-Top-Level-Keys muessen namespaced sein (`.`). +## Runtime-Fingerprint + +`web/index.php` validiert bei jedem Request, dass der Runtime-Stand zur aktuellen Modul-Konfiguration passt. + +- `bin/module-build.php` schreibt nach jedem Build `storage/runtime/.module-fingerprint` (sortierte Modul-IDs, kommasepariert). +- `web/index.php` vergleicht den Fingerprint mit der erwarteten Modul-Liste. +- Bei Mismatch: `RuntimeException` mit Hinweis auf `php bin/module-runtime-sync.php`. +- Kein Auto-Build im Request-Pfad — Build ist ausschliesslich CLI-Aufgabe. + +Methoden: `ModuleRuntimePageBuilder::expectedFingerprint()`, `readFingerprint()`, `writeFingerprint()`. + +## API-Channel-Isolation + +API-Requests (`api/`-Prefix) ueberspringen 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) +- `AccessControl` listet `api/` als always-public + ## Standard-Runbook `php bin/module-runtime-sync.php` fuehrt in fester Reihenfolge aus: