Files
breadcrumb-the-shire/docs/reference-module-manifest-contract.md
fs 545bcc789b 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>
2026-04-29 09:57:22 +02:00

5.6 KiB

Module Manifest Contract (V1.2)

Letzte Aktualisierung: 2026-03-25

Ziel

Verbindlicher Contract für modules/*/module.php, damit Module zur Runtime deterministisch geladen und validiert werden.

Status

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

Zusatz zur Laufzeitvalidierung:

  • JSON-Schema-Datei: /.agents/contracts/module-manifest.schema.json
  • Laufzeit-Check bei Modul-Laden: ModuleManifestSchemaValidator
  • CLI-Check: php bin/console module:validate <module-id|--all>

Ein Manifest muss sowohl:

  1. das JSON-Schema erfuellen als auch
  2. die Laufzeit-Contracts (Klassen/Interfaces/Namespace) bestehen.

Namespace-Konvention

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:

modules/<id>/lib/Module/<Name>/
  Service/              # BookmarkService, Factory, etc.
  Repository/           # Repository + Interfaces
  Providers/            # SessionProvider, LayoutProvider, SearchProvider
  Support/              # Modul-spezifische Utilities
  <Name>ContainerRegistrar.php
  <Name>AuthorizationPolicy.php

Der ModuleAutoloader mappt MintyPHP\*modules/<id>/lib/ per PSR-4. Enforcement: ModuleStructureContractTest::testModuleClassesUseModuleNamespace.

Aktivierung (APP_ENABLED_MODULES)

  • nicht gesetzt: config/modules.php gilt.
  • gesetzt und leer (APP_ENABLED_MODULES=''): keine Module.
  • gesetzt mit Liste (APP_ENABLED_MODULES='a,b'): exakt diese Module.

i18n_path Contract

Module mit eigenen Übersetzungsdateien deklarieren den relativen Pfad zum i18n-Verzeichnis:

'i18n_path' => 'i18n',

Der ModuleAutoloader registriert daraus den absoluten Pfad modules/<id>/i18n/ als zusätzliche Übersetzungsquelle.

permissions Contract

permissions ist eine Objektliste:

'permissions' => [
    [
        'key' => 'module.permission',
        'description' => 'Human readable text',
        'active' => true,      // optional, default true
        'is_system' => true,   // optional, default true
    ],
],
  • key und description sind Pflichtfelder.
  • Runtime-Sync erfolgt über php bin/console module:sync.
  • module:sync führt diesen Sync automatisch aus.

scheduler_jobs Contract

scheduler_jobs ist eine Objektliste mit vollem Default-Contract:

'scheduler_jobs' => [
    [
        'job_key' => 'module.job',
        'handler' => App\\Scheduler\\MyJobHandler::class,
        'label' => 'Job label',
        'description' => 'Job description',
        'default_enabled' => true,
        'default_timezone' => 'Europe/Berlin',
        'default_schedule_type' => 'daily', // hourly|daily|weekly
        'default_schedule_interval' => 1,
        'default_schedule_time' => '02:00', // required for daily/weekly
        'default_schedule_weekdays_csv' => null, // weekly: e.g. '1,3,5'
        'default_catchup_once' => true,
        'allowed_schedule_types' => ['daily', 'weekly'],
    ],
],
  • 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)

Neue generische Slot-Typen:

  • topbar.right_item: { key, template, permission?, order }
  • layout.body_end_template: { key, template, permission?, order }
  • layout.head_style: { key, path, permission?, order }
  • runtime.component: { key, script, export?, selector?, scope?, config_path?, default_config?, phase?, permission?, order }

runtime.component.phase ist early|default|late (Default: late).

Abgrenzung CSS:

  • layout.head_style = global auf allen Seiten.
  • 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 überschreiben (moduleSlots, csrfKey, currentTenant, ...).
  • Layout-Provider-Top-Level-Keys müssen namespaced sein (<module_id>.<key>).

Runtime-Fingerprint

web/index.php validiert bei jedem Request, dass der Runtime-Stand zur aktuellen Modul-Konfiguration passt.

  • php bin/console module:build 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/console module:sync.
  • Kein Auto-Build im Request-Pfad — Build ist ausschliesslich CLI-Aufgabe.

Methoden: ModuleRuntimePageBuilder::expectedFingerprint(), readFingerprint(), writeFingerprint().

API-Channel-Isolation

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 über ApiBootstrap.php (Bearer-Token)
  • AccessControl listet api/ als always-public

Standard-Runbook

php bin/console module:sync führt in fester Reihenfolge aus:

  1. module:migrate
  2. module:permissions-sync
  3. module:build
  4. module:assets-sync

Der Output enthaelt eine deterministische Step-Summary (migrate, permissions-sync, build, assets-sync) inklusive vendor_warnings_ignored=<n>. First-party Warnings/Notices/Deprecations gelten als Fehler (fail-fast).