Files
breadcrumb-the-shire/docs/architektur.md
fs 25370a1a55 add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00

6.3 KiB

Architektur

Letzte Aktualisierung: 2026-02-21

1) Zielbild

Die Anwendung ist eine servergerenderte Multi-Tenant-Admin-Anwendung mit klarer Trennung von:

  • HTTP/Request-Flow (/web/index.php, lib/Http/*)
  • Action-Layer (/pages/**)
  • Business-Logik (/lib/Service/**)
  • Datenzugriff (/lib/Repository/**)
  • Rendering (/templates/**, *.phtml)
  • Frontend-Verhalten (/web/js/**)

2) Request-Lebenszyklus

Zentraler Entry Point ist /web/index.php.

Ablauf pro Request:

  1. Bootstrap (vendor/autoload.php, config/config.php, config/router.php, Helper)
  2. Firewall + Session Start
  3. Locale-Ermittlung (URL/Session/Cookie/default)
  4. Remember-Me Auto-Login
  5. Optionales Tenant-Snapshot-Refresh in Session
  6. Redirect auf locale-prefixed URL (falls nötig)
  7. Access Guard (AccessControl) für Public/Protected Paths
  8. Action-Layer aus pages/** laden
  9. View + Template rendern
  10. Session beenden, DB schließen

3) Routing-Modell

  • Route-Definitionen liegen in /config/routes.php.
  • Registrierung erfolgt in /config/router.php.
  • public=true in routes.php steuert, welche Pfade ohne Login erlaubt sind.

MintyPHP-Konvention (Dateinamensrouting):

  • pages/admin/users/edit($id).php erwartet URL-Parameter id
  • pages/admin/users/data().php für Datenendpunkte
  • ...(none).phtml für responses ohne Template-Layout
  • Binarausgaben (z. B. Onboarding-PDF/ZIP) setzen MINTY_ALLOW_OUTPUT im Action-Endpoint.

4) Schichten und Verantwortungen

Action-Layer (/pages)

  • Eingaben lesen/validieren
  • Permissions und Tenant-Scope prüfen
  • Services aufrufen
  • View-Daten vorbereiten

Service-Layer (/lib/Service)

  • Geschäftsregeln
  • Cross-Cutting-Logik (z. B. Auth, Settings, Branding)
  • Orchestrierung mehrerer Repositories

Repository-Layer (/lib/Repository)

  • SQL und Mapping
  • Filter-/Paging-Mechaniken
  • Keine UI-/HTTP-Logik

Template/View-Layer (/templates, *.phtml)

  • Nur Rendering
  • Keine DB-Zugriffe
  • Wiederkehrende UI-Teile als Partials

5) Datenmodell (fachlich)

Kernobjekte:

  • users
  • tenants
  • departments
  • roles
  • permissions

Verknüpfungen:

  • user_tenants, user_departments, user_roles
  • role_permissions
  • tenant_auth_microsoft, user_external_identities
  • tenant_custom_field_definitions, tenant_custom_field_options
  • user_custom_field_values, user_custom_field_value_options

Hinweis:

  • departments ist 1:1 an tenants gebunden über departments.tenant_id (kein M:N-Mapping).
  • In der User-Organisation wird die Department-Auswahl tenantweise gerendert (ein Multi-Select je zugewiesenem Tenant), gespeichert wird weiterhin flach über user_departments.
  • Tenant-spezifische User-Zusatzfelder werden separat modelliert:
    • Definitionen/Optionen pro Tenant in tenant_custom_field_*
    • Werte pro User in user_custom_field_*
    • Filterung im Address Book über dynamische Query-Keys cf_*, cfm_*, cfd_*.
  • field_key bleibt intern (tenant-weit eindeutig), wird im Tenant-UI automatisch aus dem Label erzeugt und nicht manuell gepflegt.
  • is_filterable ist fachlich nur für select, multiselect, boolean, date aktiv.
  • User-Zusatzfeldwerte sind in V1 optional (keine Pflichtvalidierung).
  • Tenant-Theme-Overrides werden direkt auf tenants gespeichert:
    • tenants.default_theme (NULL = globales app_theme)
    • tenants.allow_user_theme (NULL = globales app_theme_user).
    • Auflösung immer über $_SESSION['current_tenant'] und damit tenant-spezifisch für Multi-Tenant-User.
  • Tenant-SSO für Microsoft Entra ID:
    • Konfiguration pro Tenant in tenant_auth_microsoft.
    • Externe Identitäts-Verknüpfung stabil über user_external_identities (provider + tid + oid).
    • Login-Endpunkte: login (optional ?tenant={slug}), auth/microsoft/start, auth/microsoft/callback.
    • Shared-App-Credentials liegen global in settings; optionale Tenant-Overrides sind möglich.
    • Profil-Sync wird tenant-spezifisch über tenant_auth_microsoft.sync_profile_on_login und tenant_auth_microsoft.sync_profile_fields gesteuert.
    • Erlaubte Sync-Felder in V1: first_name, last_name, phone, mobile, avatar.
    • phone/mobile/avatar kommen über Microsoft Graph (/me, /me/photo/$value) und sind fail-open (Graph-Fehler blockieren den Login nicht).

Sicherheits-/Audit-nahe Tabellen:

  • user_remember_tokens
  • password_resets
  • email_verifications
  • mail_log

6) Sicherheits- und Scope-Modell

  • Auth Guard: protected by default
  • Permission Checks: feature-spezifisch in Actions/Services
  • Tenant Scope: datenabhängig über Tenant-Matches
  • Strictness steuerbar über TENANT_SCOPE_STRICT

Details siehe: /docs/sicherheitsmodell.md

7) Frontend-Architektur

JS-Struktur:

  • /web/js/core Basismodule (DOM/Grid Factory)
  • /web/js/components UI-Komponenten
  • /web/js/pages seitenspezifische Helfer

Bootstrap:

  • app-boot.js früh (no-js/js state, localStorage UI state)
  • app-init.js für Default-Template
  • app-login-init.js für Login-Template

CSS-Struktur:

  • Layer-Entrypoint: /web/css/app-layers.css
  • Basen/Variablen in /web/css/base
  • Layout in /web/css/layout
  • Komponenten in /web/css/components
  • Seitenstile in /web/css/pages
  • Vendor-Overrides in /web/css/vendor-overrides

8) Asset-Steuerung

Konfiguration liegt in /config/assets.php.

  • Template-Gruppen: default, login
  • Seiten-Gruppen optional via Buffer::set('style_groups', ...)
  • Rendering über Helper: renderTemplateStyles() und renderPageStyles()

9) Erweiterungsstrategie

Pragmatischer Weg für neue Features:

  1. Repository erweitern (SQL)
  2. Service-Regel bauen
  3. Action anbinden
  4. View/Partial integrieren
  5. JS nur falls interaktiv nötig
  6. Tests + Lint/Analyse laufen lassen

So bleibt die Trennung stabil und Refactoring kontrollierbar.

10) Settings-Architektur (DB + Datei-Cache)

  • settings (DB) ist die alleinige fachliche Quelle für globale Settings.
  • config/settings.php ist ein technischer Teil-Cache für sehr häufig gelesene UI-Basiswerte.
  • Zugriffsmuster:
    • SettingService::get* / SettingService::set* -> DB
    • appSetting(...) -> Datei-Cache (SettingCacheService)
  • Konsequenz:
    • Es ist korrekt, dass nicht alle DB-Settings im Datei-Cache stehen (z. B. SMTP/SSO/API-Details).
    • Der Cache muss nur die Keys enthalten, die im Runtime-Helper appSetting(...) verwendet werden.

Details: /docs/einstellungen-speicherung.md