Skip to content

Audit: Grundeinstellungen V2 (/v2/admin/settings)

Stand: 2026-08-03. Geprüft wurde, welche Einstellung auf der Seite eine Wirkung im V2-Backend hat, welche V1-Konfiguration in V2 noch keine Stelle hat, und welcher Block auf der Seite fachlich falsch einsortiert ist.

Korrektur zur Erstfassung

Zwei Punkte der ersten Fassung waren falsch und sind unten berichtigt:

  • global_cert ist kein SSL-/PEM-Zertifikat. Der Katalog beschrieb es als „PEM-Zertifikat für ausgehende Verbindungen", tatsächlich ist es die Zertifikatsangabe unter der Unterschrift auf Berichten (V1: add_signature == 'GLOBAL'). Die Empfehlung „raus, Betriebssache" war damit hinfällig; Label und Hilfetext sind korrigiert, das Feld gehört zu den Unterschriften.
  • Ersatzlos entfernen war der falsche Schluss. Alle Kandidaten (enable_local_user_accounts, enable_fixed_grid_header, download_folder, show_empty_doc, Barcode, pic_doc_code, certificate_field_fieldname) werden von calServer V1 aktiv gelesen. Auf einer Installation, die noch V1 fährt, ist diese Seite die einzige gepflegte Admin-Oberfläche dafür. Statt zu löschen tragen sie jetzt das Kennzeichen Nur V1 aus dem Schema (scope).

Prüfmethode: für jeden Property-Key wurde der Consumer in laravel/app/ und frontend-v2/ gesucht. „Ohne Wirkung" heißt: der einzige Fundort ist der Katalog app/Support/SettingsCatalog.php bzw. die Seite selbst. Der Wert wird also gespeichert und wieder angezeigt, aber niemand liest ihn.

Befund und Umsetzung

Die Abschnitte 1 bis 4 beschreiben den Befund zum Prüfzeitpunkt, nicht den heutigen Aufbau der Oberfläche. Was daraus umgesetzt wurde, steht in Abschnitt 5; die Umzüge selbst begründet ADR-031.


Kurzfassung

  • Die V1-Parität der Felder ist erreicht. Alle 39 Keys aus basicSettingFields, alle 20 aus inventorySettingFields und alle 6 aus securitySettingFields (httpdocs/protected/config/constants.php) haben in V2 ein Eingabefeld. Es fehlt kein V1-Feld.
  • Die Wirkung fehlt an 26 von rund 70 Feldern. Captcha, Cookie-Banner, Report-Briefkopf, Barcode und einige Einzelwerte sind reine Formulare.
  • Was wirklich fehlt, ist der V1-Tab „Administration". Cron Jobs, Cache, Backup und Dateispeicher haben in V2 teils fertige Endpunkte, aber keine Oberfläche.
  • Das Sammelbecken hat zwei Ursachen: die Seite bündelt vier fachlich unabhängige Themen, und sie hat zwei Bauweisen nebeneinander (schema-getrieben aus dem Katalog gegen handgeschriebenes Formular).

1. Ausgangslage: was die Seite heute ist

frontend-v2/pages/admin/settings.vue (754 Zeilen) hält vier Tabs, drei Persistenzwege und sechs Speichern-Buttons:

Tab Quelle Bauweise Speichern
Anmeldung settings/user, Sektionen branding + registration schema-getrieben (useSettingsSchema + SettingsSchemaForm) PUT /admin/properties
Passwort & Sicherheit settings/user, Sektionen password + security + ssl + report_pdf schema-getrieben derselbe PUT
Regeln settings/calibration + settings/customer handgeschriebenes Formular, Labels im Frontend zwei getrennte PUTs, Aufteilung per Frontend-Whitelist
Portal QR_Code_Role-Flags (ADR-010) eigener Endpunkt PUT /admin/portal-settings

Der Bruch ist strukturell: Der Katalog (SettingsCatalog::all()) kennt genau eine Gruppe, settings.user. Die Regeln-Tab-Keys stehen nicht darin, also lebt ihre Beschreibung (Label, Typ, Hilfetext, Validierung) im Vue-Template. Das ist die Stelle, an der die Seite wieder wächst: eine neue Regel bedeutet Frontend-Code, keinen Katalog-Eintrag.

Nebenwirkung im Frontend: saveRules() teilt die Werte über eine hartcodierte Menge (customerFields = new Set(['search_customer_fields'])) wieder auf die Subkategorien auf. Jede weitere settings/customer-Regel muss an dieser Stelle nachgetragen werden, sonst landet sie still in settings/calibration.


2. Was umgesetzt ist (mit Wirkung im Backend)

Tab „Anmeldung" (18 Felder, 16 wirksam)

Setting Wirkung
company_name, company_login_text, logo_company, background_image_company, background_color_company AuthController::branding(), Login-Seite
default_language Branding + Registrierung + Rollen-/Modul-Labels
system_email MailerActionRunner, SystemMailService
registration_from_name, registration_mail_list, registration_form_company AuthController::register(), Passwort-Reset
enable_registration_dialog, enable_registration_mail, enable_double_opt_registration, enable_welcome_mail Registrierungsablauf komplett verdrahtet
registration_pending_email, registration_welcome_email Double-Opt-in- und Willkommensmail

Ohne Wirkung: information_email_for_admin, registration_terms_conditions (die AGB werden auf pages/register.vue nirgends angezeigt oder bestätigt).

Tab „Passwort & Sicherheit" (23 Felder, 9 wirksam)

Setting Wirkung
minimal_number_characters, ..._lowercase_..., ..._uppercase_..., ..._special_..., ..._digit_... PasswordPolicyService, wird über branding() auch ans Frontend geliefert
password_expiry_days, warning_password_expiry_days AuthController (Ablauf + Vorwarnung beim Login), Ersteintrag durch AppSetup
activate_number_of_failed_login, number_of_failed_login LoginSecurity, Kontosperre nach Fehlversuchen

Ohne Wirkung: die kompletten Blöcke reCAPTCHA (3), Friendly Captcha (3), Cookie-Banner (3), SSL-Zertifikat (1) und Report-PDF (4).

Tab „Regeln" (24 Felder plus Zähler-Block, 14 wirksam)

Setting Wirkung
due_date_period, critical_date_period_1..3 CalibrationStatusService (Fälligkeits- und Kritisch-Schwellen)
status_field_fieldname MailerActionRunner
additional_status_field_fieldname StatusController
type_field_fieldname DeviceType, DeviceTypeBlueprintService, InventorySpecificationController
customer_email_field CustomerEmailFieldResolver
inventory_description_fields, search_customer_fields LookupService (Anzeige in Auswahlcombos)
disable_double_asset_number InventoryController, StoreInventoryRequest
disable_double_booking_number BookingController, StoreBookingRequest
enable_user_opens_order OpenOrderWarningService
enable_badge_dms_view FileSettingController (Freigabe-Badge)
counter_count, counter_N FieldCounterService ([GLOBAL_COUNTER_N] in Vorgabewerten)
counter_N_reset_{day,week,month,year} ResetGlobalCounters (nächtlicher Lauf)

Ohne Wirkung: certificate_field_fieldname, pic_doc_code, die vier Barcode-Felder, show_empty_doc, download_folder sowie die beiden bereits als V1-only beschrifteten Schalter enable_local_user_accounts und enable_fixed_grid_header.

Tab „Portal" (4 Felder, vollständig)

portal_enable, portal_start_address, qrlink_enable, qrlink_address laufen über PortalSettingsController nach ADR-010, inklusive Public-User-Status und Kundenzähler. Der einzige Tab ohne Lücke.


3. Was fehlt

3a. Wirkung zu vorhandenen Feldern

Nach Aufwand und Nutzen sortiert:

  1. Captcha auf der Anmeldung (6 Felder). Der Schalter suggeriert Schutz, den es nicht gibt. Entweder in login.vue + AuthController::login() umsetzen oder aus der UI nehmen, bis es soweit ist. Ein aktivierter Schalter ohne Prüfung ist schlechter als ein fehlender.
  2. Report-Briefkopf und PDF-Kopf/Fuß (4 Felder). V1 druckt damit Lieferscheine und Berichte. In V2 liest die Report-Pipeline die Werte nicht.
  3. Cookie-Banner (3 Felder). Datenschutz-Thema mit Außenwirkung, in V2 nirgends gerendert.
  4. AGB-Bestätigung bei der Registrierung (registration_terms_conditions).
  5. Barcode/Etikett (4 Felder). Hier fehlt nicht die Konfiguration, sondern die Funktion: V2 hat keinen Etikettendruck, der einen Barcode-Typ auswerten könnte.

3b. Konfigurationsstellen, die V2 komplett fehlen

Der V1-Tab Administration (basicSettings/administration) hat in V2 keine Entsprechung. Bei vier Punkten existiert der Endpunkt bereits und nur die Oberfläche fehlt:

Thema V2-Backend V2-Frontend
Cron Jobs GET/POST/PUT/DELETE /admin/cron-jobs, POST /admin/cron-jobs/restart fehlt
Cache leeren POST /admin/cache/flush fehlt
Backup-Aktionen /admin/backup-actions inkl. clone und test-run fehlt (docs-v2/admin/backup.md behauptet bereits eine UI)
Dateispeicher-Pfade settings/file_store (vom InitialDataSeeder gesetzt) fehlt
SymmetricDS-Pfade settings/symmetric fehlt
Session-Timeout nur .env fehlt (in V1 auf der Seite editierbar)

Nicht nachzubauen sind aus dem V1-Tab-Set:

  • Grid Feature Flags (use_legacy_*) schalten V1-Legacy-Grids. In V2 bedeutungslos, der Endpunkt existiert nur für V1-Installationen.
  • Report-Engine-Flags sind bereits umgesetzt, allerdings in /admin/reports statt in den Grundeinstellungen. Das ist die richtige Stelle.
  • Plugins-Tab: der Inhalt war im Wesentlichen MET/TEAM, das V2 unter /admin/metteam hat.

4. Was woanders besser aufgehoben ist

Die Seite heißt „Grundeinstellungen", trägt aber vier verschiedene Fragen: Wie sieht das System von außen aus?, Wer darf rein und wie sicher?, Welches Feld bedeutet was? und Wie druckt der Bericht?. Nur die ersten beiden gehören hierher.

Report-PDF raus, nach /admin/reports

left_header_order, right_header_order, pdf_report_header, pdf_report_footer stehen heute im Tab „Passwort & Sicherheit". Ein Briefkopf hat mit Passwortrichtlinien nichts zu tun, und /admin/reports hat mit „Berichtseinstellungen" bereits den passenden Tab. Der Katalog kann die Sektion report_pdf behalten, nur die Seite muss sie anders anzeigen: ein zweites SettingsSchemaForm mit :section-keys="['report_pdf']" in /admin/reports genügt, die Speicherlogik ist dieselbe.

Feldzuweisungen raus, nach /admin/field-definitions

Acht Felder (status_field_fieldname, additional_status_field_fieldname, type_field_fieldname, certificate_field_fieldname, customer_email_field, inventory_description_fields, search_customer_fields, pic_doc_code) beantworten die Frage „welches Feld übernimmt welche Rolle". Das ist Feldverwaltung, keine Grundeinstellung.

Der Aufenthaltsort ist nicht nur kosmetisch falsch, er produziert Fehler: Alle acht sind freie Textfelder. Der Admin muss den api_name treffen, der je nach Installation status oder C2305 heißt (siehe frontend-v2/CLAUDE.md, „Die V1-Codes sind die Feld-Identität"). Ein Tippfehler fällt erst auf, wenn Wochen später eine Mail-Aktion den Status nicht findet. Auf /admin/field-definitions steht die Registry ohnehin schon zur Verfügung, also kann daraus eine Auswahl statt eines Textfelds werden.

Zähler-Block raus, zu den Vorgabewerten

counter_count, counter_N und die 4·N Reset-Flags sind ausschließlich für [GLOBAL_COUNTER_N] in Vorgabewerten da (FieldCounterService, DefaultValuePicker, ADR-018 „Vorgabewerte als Formeln"). Sie gehören neben den Vorgabewert-Editor, nicht in einen Abschnitt „Sonstiges". Der Block ist außerdem der optisch größte auf der Seite (bei 4 Zählern 20 Bedienelemente).

Kennzeichnen statt entfernen

Die erste Fassung wollte vier Felder löschen. Die Prüfung gegen httpdocs/ hat das widerlegt: jedes davon wird von V1 gelesen.

Setting V1-Consumer
enable_local_user_accounts LoginForm.php
enable_fixed_grid_header KGridViewTrait.php
download_folder FrontendProperty.php
show_empty_doc small_view.php, document/files.php
certificate_field_fieldname drei Kalibrier-Views
pic_doc_code small_view.php, view.php
Barcode (4) Etikettendruck
global_cert Model.php, FrontendDms.php, AdminSignatureSetting.php

Kundensysteme laufen V1 (siehe Root-CLAUDE.md). Ein Feld aus der V2-Maske zu werfen, das V1 auswertet, nimmt dem Admin die Bedienstelle, ohne die Einstellung loszuwerden. Deshalb bleiben sie, tragen aber scope: 'v1' im Katalog und in der Oberfläche das Kennzeichen Nur V1 mit Tooltip. Das ist die Information, die der Benutzer braucht, an der Stelle, an der er sie braucht — und sie steht in den Daten, nicht in Prosa in zwei von sechs Hilfetexten.

global_cert ist ein Sonderfall: Der Katalog beschrieb es als PEM für ausgehende Verbindungen. Es ist die Zertifikatsangabe im Unterschriftsblock von Berichten. Label, Hilfetext und Sektion sind korrigiert; fachlich gehört es zu den Unterschriften unter /admin/reports, nicht in eine SSL-Sektion.

Verschieben, wenn die Funktion kommt

  • show_empty_doc gehört zur Dateiverwaltung (/admin/files).
  • Die Barcode-Sektion gehört zum Etikettendruck, sobald es ihn gibt.
  • Der Portal-Tab ist an sich richtig platziert, wäre aber zusammen mit dem Public User (heute /admin/users) als eigener Bereich „Öffentlicher Zugang" schlüssiger. Kein dringender Umbau, ADR-010 hat das bewusst so gelegt.

Bleiben soll

  • Branding und Anmeldeseite.
  • Registrierung.
  • Passwortrichtlinie und Login-Sicherheit (inklusive Captcha, sobald wirksam).
  • Fristen und Ablaufzeiträume: die vier Schwellen gelten systemweit für Statusampeln, Dashboard und Grids. /admin/statuses wäre denkbar, ist aber enger geschnitten als die Wirkung der Werte.

5. Zielbild und Reihenfolge

Zielbild /admin/settings: drei Tabs statt vier, alle aus dem Katalog gespeist.

  1. Anmeldung & Branding
  2. Passwort & Sicherheit
  3. Regeln (Fristen, Doppel-Nummern-Sperren, Warnungen)

Portal bleibt als vierter Tab, bis es einen Bereich „Öffentlicher Zugang" gibt.

Reihenfolge, kleinste sinnvolle Schritte zuerst:

  1. ~~Tote Felder entfernen~~ → Wirkungsbereich kennzeichnen. ✅ umgesetzt: scope: 'v1' im Katalog, Kennzeichen Nur V1 in der Oberfläche. Siehe die Korrektur oben, warum aus „entfernen" „kennzeichnen" wurde.
  2. settings/calibration und settings/customer in den SettingsCatalog aufnehmen. ✅ umgesetzt. Der Regeln-Tab ist jetzt genauso schema-getrieben wie die anderen, die Frontend-Whitelist in saveRules() ist weg, und Labels/Hilfen sind serverseitig übersetzbar. Das ist der Schritt, der verhindert, dass die Seite wieder zum Sammelbecken wird.
  3. Report-PDF nach /admin/reports, zusammen mit global_cert in den Tab „Unterschriften". ✅ umgesetzt (ADR-031).
  4. Feldzuweisungen nach /admin/field-definitions, Freitext ersetzt durch Feldauswahl aus der Registry. ✅ umgesetzt (ADR-031).
  5. Zähler-Block zu den Vorgabewerten. ✅ umgesetzt (ADR-031).
  6. Neue Seite /admin/operations („Betrieb") für Cron Jobs, Cache-Flush, Backup-Aktionen und Dateispeicher-Pfade. ✅ umgesetzt. Nicht eine Berechtigung, sondern drei: die Endpunkte tragen administration_management, database_management_admin und basic_setting_admin, also prüft jeder Tab seine eigene und entfällt ohne sie.
  7. Captcha und Cookie-Banner entweder umsetzen oder ausblenden. ✅ umgesetzt als ausblenden: die neun Felder sind aus dem Katalog genommen. Anders als bei den V1-Regeln genügte hier kein scope: 'v1' — ein Schalter „Anmeldung mit reCAPTCHA schützen", der in V2 nichts prüft, verspricht Schutz, den es nicht gibt. Die Werte bleiben in der property-Tabelle, V1 wertet sie weiter aus.

Schritte 3 bis 5 verschieben Bedienelemente zwischen Admin-Seiten und ändern damit die Menü-Topologie. Nach der Linie von ADR-014, ADR-016 und ADR-018 gehört dafür ein ADR ins laravel/docs/adr/-Verzeichnis — geschrieben als ADR-031, „Eine Einstellung steht da, wo sie wirkt".

Damit sind alle sieben Schritte abgearbeitet.

Was dabei nicht angefasst wird: die Speicherform. Alle Werte bleiben in der property-Tabelle unter ihrem V1-Namen und ihrer V1-Subkategorie. Verschoben wird nur, wo sie bedient werden. Damit bleibt jede V1-Installation kompatibel und v1:sync trifft weiterhin dieselben Zeilen.