fs 22966fdacf feat(helpdesk): ticket detail drawer — third drawer consumer
Migrates the ticket detail view (communication feed + ticket metadata aside)
into the core detail drawer pattern. Click a ticket number in the customer's
support tab → drawer slides in with the full ticket thread; arrow icons step
through the current filter page; ↗ opens the full page.

- `modules/helpdesk/templates/helpdesk-ticket-detail.phtml` extracts the
  body (communication feed container + metadata aside + i18n JSON) so the
  full page and the fragment render from the same source.
- `ticket-fragment($id).php` / `(none).phtml` reuse BcODataGateway::getTicket
  and enforce the same ABILITY_ACCESS guard as the full page. Connection
  errors render inline without aborting the fragment.
- Route `helpdesk/ticket-fragment/{id}` declared in module.php.
- `helpdesk-detail.js` wires the tickets grid: ticket-no formatter emits
  `data-drawer-trigger`, `linkColumn` disabled, `initDetailDrawer` called
  with `onContentLoaded → initHelpdeskTicket(contentEl)` so the async
  communication feed loads inside the drawer just like on the full page.
- `fetchUrl`/`fullUrl` written as single-expression arrows so the
  DetailDrawerFragmentContractTest can discover the consumer and validate
  the fragment endpoint files exist — the test now covers all three drawer
  consumers (address book, admin users, helpdesk tickets).

The full-page ticket view is unchanged for users who deep-link directly;
only the router-to-body wiring moved through the partial.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:03:25 +02:00
2026-02-04 23:31:53 +01:00
2026-02-04 23:31:53 +01:00
2026-02-04 23:31:53 +01:00

CoreCore (MintyPHP)

CoreCore ist eine mandantenfaehige Admin-Anwendung auf Basis von MintyPHP. Der Fokus liegt auf klarer Rollen-/Rechtestruktur, Tenant-Scope und einer konsistenten Admin-UI.

Funktionsumfang

  • Mandantenverwaltung (inkl. Branding/Farbe/Favicon)
  • Abteilungen pro Mandant
  • Benutzerverwaltung mit Rollen, Sichtbarkeit und Stammdaten
  • Rollen- und Berechtigungsverwaltung
  • Adressbuch (tenant-scoped, read-only Profilansicht)
  • Globale Suche (Admin + Address Book)
  • Mail-Versand (SMTP/PHPMailer) inkl. Mail-Log
  • Onboarding-PDF fuer Zugangsdaten (Single inline, Bulk als ZIP)
  • Passwort-Reset und Remember-Login-Tokens
  • Geplante Aufgaben (Scheduler mit Ausfuehrungshistorie)

Tech Stack

  • PHP 8.5 (Runtime im Docker-Container)
  • MintyPHP Core
  • MariaDB 11
  • Memcached
  • Nginx
  • Grid.js (Tabellen)
  • PHPMailer
  • Dompdf (PDF Rendering)
  • endroid/qr-code (QR-Code Rendering)

Schnellstart (Docker)

  1. Umgebungsdatei anlegen
cp .env.example .env
  1. Config-Template fuer den App-Bootstrap anlegen
cp config/config.php.example config/config.php
  1. Container starten
docker compose up --build -d
  1. App oeffnen
  1. Container stoppen
docker compose down

Alternativ ueber den Dev-Orchestrator:

cp config/config.php.example config/config.php
bin/dev init
bin/dev up
bin/dev down
bin/dev console list
bin/dev qa

Produktion (Docker)

Es gibt eine getrennte Produktions-Compose:

  • Dev: /docker-compose.yml
  • Prod: /docker-compose.prod.yml

Grundschritte:

  1. .env auf Produktionswerte setzen (siehe /.env.prod.example)
  2. Domain und TLS in /docker/nginx/prod.conf anpassen
  3. Zertifikate unter /docker/nginx/certs/ bereitstellen
  4. Starten:
docker compose -f docker-compose.prod.yml up --build -d

Details stehen in:

  • /docs/howto-docker-lokal.md
  • /docs/howto-docker-produktiv.md
  • /docs/explanation-docker-betrieb.md (Übersicht)

Seed-Daten

Die Initialisierung liegt in /db/init/init.sql.

Standard-Demo-User:

  • E-Mail: demo@user.com
  • Passwort: Demo123
  • Tenant: MusterMandant
  • Abteilung: Musterabteilung
  • Rollen: Admin, User

Initiale DB-Settings (Seed):

  • app_title -> CoreCore
  • app_locale -> de
  • app_theme -> light
  • app_theme_user -> 1
  • app_registration -> 1 (aktiv)
  • app_primary_color -> #105433
  • api_token_default_ttl_days -> 90
  • api_token_max_ttl_days -> 365
  • api_cors_allowed_origins -> http://localhost:8080, http://127.0.0.1:8080
  • session_idle_timeout_minutes -> 30
  • session_absolute_timeout_hours -> 8
  • user_inactivity_deactivate_days -> 180
  • user_inactivity_delete_days -> 365
  • default_tenant_id -> MusterMandant
  • default_department_id -> Abteilungscode MUSTER (Musterabteilung)
  • default_role_id -> Rolle USER (User)
  • frontend_telemetry_enabled -> 1
  • frontend_telemetry_sample_rate -> 0.2
  • frontend_telemetry_allowed_events -> ajax_error,warn_once

Projektstruktur

  • /config Konfiguration (Routen, Assets, Themes, Module + ENV-Bootstrap)
  • /db/init Datenbankschema + Seeds
  • /lib Backend-Code (Repository, Service, Http, Support)
  • /pages Action-Layer + Views pro Route
  • /templates Layouts + wiederverwendbare Partials
  • /web oeffentliche Assets (CSS/JS/Vendor)
  • /i18n Uebersetzungen
  • /tests PHPUnit-Tests
  • /docs Projekt-Dokumentation

Architektur-Kurzregeln

  • Keine DB-Zugriffe in .phtml-Views.
  • SQL bleibt in Repositories.
  • Geschaeftslogik bleibt in Services.
  • pages/.../*.php fungiert als Action-/Controller-Schicht.
  • Service-Aufloesung in Actions/Helpern ueber app(Foo::class).
  • new ...Factory() nur im Composition Root (web/index.php + core/App/registerContainer.php) oder in *Factory.php.
  • pages/**/data().php sind GET-only (gridRequireGetRequest()) und normalisieren limit/offset/order/dir ueber Grid-Helper.
  • Permissions + Tenant-Scope werden in Actions/Services erzwungen.
  • Wiederkehrende UI-Bloecke als Partials zentralisieren.

UI-Konventionen

Edit-Seiten verwenden einheitliche Tab-Struktur:

  • erster Tab: Master data
  • letzter Tab: Visibility
  • optional letzter Tab: Danger zone

User-Organisation:

  • Departments werden tenantweise angezeigt (ein Multi-Select je ausgewaehltem Tenant).
  • Nach Tenant-Aenderungen im selben Formular werden Department-Optionen nach Speichern/Reload aktualisiert (kein Live-Update).

Zentrale Partials:

  • /templates/partials/app-details-titlebar.phtml
  • /templates/partials/app-visibility-status-field.phtml
  • /templates/partials/app-danger-zone-delete-field.phtml
  • /templates/partials/app-details-aside-audit.phtml
  • /templates/partials/app-details-aside-ids.phtml

Onboarding-PDF (User)

  • Permission: users.access_pdf
  • Single: admin/users/access-pdf/{uuid} (inline im neuen Tab)
  • Bulk: admin/users/access-pdf-bulk (POST, ZIP mit einer PDF pro User)
  • Hard limit: maximal 100 User pro Bulk-Request
  • Benoetigte Extensions: ext-zip, ext-dom, ext-mbstring
  • Bestehende Installationen: Schema-/Permission-Updates als idempotentes SQL-Update ausfuehren

Microsoft SSO (Tenant, Entra ID)

  • Zentraler Einstieg: login (optional mit Tenant-Hint login?tenant={tenant-slug})
  • OIDC-Endpunkte: auth/microsoft/start und auth/microsoft/callback
  • Tenant-Config liegt in tenant_auth_microsoft
  • Externe User-Linkung liegt in user_external_identities
  • Optionaler Profil-Sync pro Tenant:
    • sync_profile_on_login aktiviert Sync bei jedem Microsoft-Login
    • sync_profile_fields: first_name, last_name, phone, mobile, avatar
    • Default-Felder bei aktivem Sync ohne Auswahl: first_name,last_name
    • phone/mobile/avatar nutzen Microsoft Graph (User.Read)
  • Shared App Credentials werden in Settings gepflegt (optional Tenant-Overrides)
  • Permission fuer Tenant-SSO-Konfiguration: tenants.sso_manage
  • Bestandsinstallationen: Schema-/Permission-Updates als idempotentes SQL-Update ausfuehren
  • Wichtig: APP_CRYPTO_KEY in .env setzen, sonst koennen SSO-Secrets nicht gespeichert/verwendet werden

Asset- und Frontend-System

  • Core-CSS-Entrypoint: /web/css/core.css
  • CSS-Layer/Vendor-Basis: /web/css/app-layers.css
  • Vendor-Overrides: /web/css/vendor-overrides
  • Asset-Gruppen: /config/assets.php
  • Template-Styles: renderTemplateStyles('default'|'login')
  • Seiten-Styles per Action: Buffer::set('style_groups', ...)
  • CSS-Contract-Check: bin/css-contract-check.sh
  • JS-Bootstrap:
    • /web/js/app-boot.js (frueh, ohne Module)
    • /web/js/app-init.js (Standardseiten)
    • /web/js/app-login-init.js (Loginseiten)

Qualitaetschecks

Alle Befehle aus dem Projekt-Root ausfuehren.

PHPUnit

docker compose exec php vendor/bin/phpunit --bootstrap vendor/autoload.php

Gezielt:

docker compose exec php vendor/bin/phpunit --bootstrap vendor/autoload.php tests/I18n/TranslationKeysTest.php
docker compose exec php vendor/bin/phpunit --bootstrap vendor/autoload.php tests/Repository/RepoQueryTest.php

PHPStan

docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress

Coding Style (PHP CS Fixer)

CI-Check (ohne Dateien zu aendern):

docker compose exec php vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose

Lokal automatisch formatieren:

docker compose exec php composer cs:fix

Frontend-JS Smoke-Check (ohne Node)

  • Browser-DevTools öffnen (Console + Preserve log)
  • Kernflows klicken: Users, Address-Book, Audit-Listen, Filter setzen/zurücksetzen
  • Keine JavaScript-Errors/Unhandled-Rejections in der Console

Dokumentation

  • /docs/index.md Dokumentationsstart mit chronologischem Lernpfad und Referenzbereichen
  • /docs/tutorial-02-systemueberblick.md Einstieg in Produktbild und Kernprinzipien
  • /docs/tutorial-03-setup-und-erster-login.md lokales Setup und erster Smoke-Test
  • /docs/reference-domain-glossar.md zentrale Begriffe fuer Tenant/Role/Scope
  • /docs/tutorial-04-architektur-request-flow.md Request-Flow und Schichtmodell
  • /docs/tutorial-07-security-tenant-scope.md Security-Grundlagen vor Feature-Arbeit
  • /docs/tutorial-08-api-erweitern.md verbindlicher API-Aenderungsablauf inkl. OpenAPI

Troubleshooting

  • Verhalten wirkt stale nach groesseren Refactors:
docker compose restart php nginx
  • Uebersetzungs-Keys fehlen:
docker compose exec php vendor/bin/phpunit --bootstrap vendor/autoload.php tests/I18n/TranslationKeysTest.php
  • Favicon/Logo aus Storage fehlt:
    • Symlink und Tenant-Kontext pruefen (web/favicon/tenants -> storage/tenants).

Lizenz

MIT (siehe /LICENSE.md)

Description
No description provided
Readme 6.8 MiB
Languages
PHP 70.8%
HTML 11.8%
JavaScript 10.4%
CSS 6.6%
Shell 0.3%
Other 0.1%