Die Berechtigungs-Engine – Funktionsstamm, Ausführungs- und Anzeigeprüfung
Der Funktionskatalog, der Erkennungslauf, die Entscheidungsreihenfolge der Ausführungs- und Anzeigeprüfung, die Zuweisungstabelle und bekannte Einschränkungen.
Überblick
Die Engine läuft bei jeder Admin-Anfrage: Der Startschritt registriert die Bibliotheken, die Controller rufen die Methoden von dlbtpermission auf. Drei Ebenen: 1) Basis-Routenrecht (Zugriff, Ändern), 2) Funktionsberechtigung, 3) Inhaltsbereich. Die Tabellennamen tragen in der Datenbank das eigene Präfix der Installation.
Funktionsstamm (feature)
Der einzige Funktionsstamm: Eine Zeile ist ein Paar aus route und action_key. Hauptfelder: module, name, access_type (UNMAPPED, BASE, SUBSCRIPTION, SYSTEM; Standard UNMAPPED), visibility_rule (auto, never, always), parent_feature_id, list_price, currency, uom, usage_mode, limit_*, billing_period, permission_present, gate_covered, cron_related, cron_job_type, status.
Herkunft der Zeilen:
- Seed-Migrationen mit ausdrücklicher Einstufung.
- Projektion aus dem alten Katalog
permissionnach jeder Migration (projectPermissionCatalogue(),INSERT IGNORE,UNMAPPED); alte Gruppenzuweisungen werden Gruppen-Vorlagenzeilen mit Quellerole. Rückwärts wird nichts kopiert. - Erkennung: Die Schaltfläche „scan“ des Funktionsstamms (
masterdata/feature::scan) ruftDlbtfeature::scan()auf.
Die Seeds enthalten 523 Paare route::Schlüssel: BASE 45, SUBSCRIPTION 6, SYSTEM 44, UNMAPPED 78, weitere 350 nur im alten Katalog (nach der Projektion UNMAPPED); 122 im Code geprüfte Schlüssel stehen in keinem Seed. Dlbtfeature::classify() lädt den aktiven Stamm einmal je Anfrage; bei null geladenen Zeilen fällt die Prüfung auf den alten Weg zurück.
Erkennung (Dlbtfeature::scan())
- Liest nur die Admin-Controllerdateien; je Datei zählt die erste Routendefinition.
- Sammelt Aufrufe von
canAction(undcanActionForGroup(; bei einer Route in einer Variablen wird die eigene Route der Datei verwendet; der Schlüssel muss ein Literal sein. - Erkennt nicht:
canSave(),canBulkAction(),canBulk(),canSee(),uiMode(),lockReason(),canActionForUser(),canSeeDeleted(),canStorageContext(). - Ergänzt die aktiven Zeilen des alten Katalogs (Vereinigung) und baut aus
Dlbtcronhealth::JOBSeine Zuordnung Route → Hintergrundaufgabe. - Bestehende Zeilen erhalten nur die gemessenen Fakten (
access_type, Name, Notiz bleiben); neue Zeilen sindUNMAPPED, Status 1. - Liefert
added,updated,gap_permission,gap_gate; danachflush().
Ausführungsprüfung (canAction)
- Kein angemeldeter Benutzer → verweigert;
user_group_id = 1→ erlaubt. - Bei geladenem Stamm: Schlüssel nicht im Stamm → verweigert;
SYSTEM→ für jeden angemeldeten Benutzer erlaubt. - Sonst ist eine HEUTE gültige Zeile mit
access_mode = 'usable'inuser_featurenötig (beliebige Quelle; beide Datumsenden zählen, NULL ist offen). Fehlt sie, entscheidet die Abhängigkeitsregel. - Mit Zeile →
Dlbtentitlement::allows():UNMAPPEDundBASEerlaubt;SUBSCRIPTIONerlaubt außer bei überfälliger Schuld (nur bei eingeschalteter Schuldsperre, mit Karenztagen; gemessen an den überfälligen offenen Rechnungen des Mandanten des Benutzers). - Bei leerem oder unlesbarem Stamm entscheidet der alte gruppenbezogene Katalog, danach kann
allows()einschränken.
Abhängigkeitsöffnung (dependencyAllows): nur für Leseschlüssel (list, autocomplete, search, select, view, read), wenn der Benutzer eine nutzbare Zeile für eine andere Funktion hat, deren systemseitige Abhängigkeit in feature_dependency hierher zeigt. Eine kommerzielle Abhängigkeit öffnet nichts. Beispiel: Das Erfassen einer Rechnung öffnet die Listen der Partner, Unternehmensgruppen, Rechnungsblöcke und Bankkonten.
Anzeigeprüfung und Oberflächenmodus
canSee: Super-Admin, leerer Stamm, Schlüssel nicht im Stamm,visibility_rule = alwaysundSYSTEM→ sichtbar;never→ verborgen. Sonst ist eine heute gültige Zeile (sichtbar oder nutzbar) nötig;listist auch sichtbar, wenn eine Zeile für irgendeine Funktion der Route existiert. Bei anderen Schlüsseln müssen auch die Liste der Route und der Schlüsselmenuder Menügruppe sichtbar sein (Permission::MENU_GROUPS).uiMode:canAction→ok; sonstcanSee→upsell; sonstnone.lockReason: Funktion im Stamm, nichtSYSTEM, ohne nutzbare Zeile →subscription; Schuld →debt. DasupsellGuard()des Startschritts leitet vollständige Seitenaufrufe danach auf die Angebotsseite.canSave($route, $id): id > 0 →edit; id = 0 →add, sofern im Stamm, sonstedit.canBulk,canBulkAction: Der Schlüssel mit Präfixbulkentscheidet, falls vorhanden.canSeeDeleted: Super-Admin oderdelete.getAllowedScopeValues: Inhaltsregeln (die eigene Regel des Benutzers geht der Gruppenregel vor; nur Erlaubniswerte).
Zuweisung (user_feature)
Die einzige Zuweisungstabelle: user_id (bei Gruppenvorlage user_group_id), feature_id, date_from, date_to, source (role, subscription, order, manual), source_ref, origin, access_mode (visible, usable), offer_definition_id, is_override, Limit- und Preisfelder, definition_id, plan_id. Eine Gruppenzeile (user_id = 0, source = 'role') ist eine Vorlage, die die Prüfung nicht liest; syncGroupRoleRows() und fillUserRoleFromGroup() zerlegen sie in Benutzerzeilen. Schreibwege: Dlbtentitlement::grant() und grantStructure(), Dlbtprovision::materialise(), saveUserFeatureRows() und addMeteredOrder() des Funktionsberechtigungs-Modells, Dlbtpayment::syncGrants(), Dlbtsignup::creditOnly(), materialiseLimits() des Abonnement-Modells.
Bekannte Einschränkungen
- Die Spalte
sourcezählt in der Prüfung nicht:PAID_SOURCESundhasPaidFeature()werden nirgends aufgerufen. - Weder
canSeenochcanActionnutzt die Hierarchieparent_feature_id. MENU_GROUPSkennt zum Beispiel die Routen von Bestellkatalog, Bestellungen, Zusatzpaketen, Paketfamilien, Registrierung, Test-Bootstrap und Kasse nicht; dort entfällt die Menügruppen-Bedingung.isVisibleGrant(), das die alte Spaltevisibleliest, wird nie aufgerufen.