enhancement
major
minor
major
minor
minor
#29563
Standardgruppe: das persistierte Gruppen-Flag "defaultGroup" wird aus der Konfiguration abgeleitet statt in der Datenbank gespeichert; Semantik der Standardgruppe dokumentiert
Betrifft 8.0.0-SNAPSHOT, tl-core (InitialGroupManager, Group, PersonGroupsInitializer), tl-element (Modell tl.accounts), tl-layout-view (Administrations-Ansichten der Gruppen).
Ausgangslage
Der InitialGroupManager legt beim Start die konfigurierten Gruppen an und merkt sich die unter default-group benannte Gruppe. Die Mitgliedschaft in dieser Gruppe wird vom PersonGroupsInitializer beim Anlegen eines Accounts hergestellt – und nur dann. Ein Account, der bereits existiert, wenn eine Anwendung eine default-group einführt oder auf eine andere Gruppe umstellt, wird nicht automatisch Mitglied. Beobachtet: employees als Standardgruppe auf einer Datenbank mit den Accounts root, anonymous, erika → Gruppe leer; der danach angelegte Account max wurde automatisch aufgenommen.
Die Dokumentation des Konfigurations-Properties (InitialGroupManager.Config#getDefaultGroup(): "Name of the group all persons have"), des Getters (getDefaultGroup(): "the Group which each person has") und von Group#isDefaultGroup() ("a group in which each user is a member") beschreibt dagegen eine dauerhaft geltende Invariante über alle Accounts, die der Code nie hergestellt hat. Nur der Tooltip des Modell-Attributs tl.accounts:Group#defaultGroup beschreibt das tatsächliche Verhalten ("automatically assigned to all new users").
Zusätzlich wird das Flag tl.accounts:Group#defaultGroup als Flex-Attribut an der Gruppe persistiert: InitialGroupManager setzt es genau einmal, wenn es die konfigurierte Gruppe neu anlegt. Existiert die Gruppe bereits, wird das Flag weder gesetzt noch gelöscht; wird die Konfiguration von Gruppe A auf Gruppe B umgestellt, bleibt das Flag an A stehen und fehlt an B. Zur Laufzeit liest kein Code das persistierte Flag (einziger Leser ist der Migrations-Prozessor zu #29447); der Wert dient allein der Anzeige. In der Gruppen-Administration (Formular und Anlege-Dialog) ist es trotzdem als editierbare Checkbox sichtbar – eine Änderung dort hat keinerlei Wirkung, da der PersonGroupsInitializer die Standardgruppe über den konfigurierten Namen auflöst.
Entscheidung zur Mitgliedschaft
Die Semantik "Standardgruppe = die Gruppe, in die jeder neu angelegte Account aufgenommen wird" bleibt bestehen; es handelt sich nicht um eine lebende Bindung über alle Accounts. Bereits vorhandene Accounts nimmt ein Administrator über das Feld Mitglieder der Gruppe auf, bzw. eine Anwendung, die eine Standardgruppe in eine bestehende Datenbank einführt, liefert dafür eine eigene Migration (Muster: RemoveAnonymousFromDefaultGroupProcessor, #29447). Der anonyme Account ist grundsätzlich ausgenommen (#29447).
Lösung
- Das persistierte Flag entfällt. Group#isDefaultGroup() liefert, ob die Gruppe die vom InitialGroupManager aus der Konfiguration aufgelöste Standardgruppe ist (false, solange der Service nicht läuft, etwa in Tests und Werkzeugen, die nur das Modell laden); Group#setDefaultGroup(boolean) und die Konstante Group.GROUP_DEFAULT sind entfernt. InitialGroupManager schreibt beim Anlegen einer Gruppe nichts mehr an die Gruppe.
- Das Modell-Attribut tl.accounts:Group#defaultGroup behält Name und Typ (tl.core:Boolean), ist aber ein abgeleitetes Attribut (derived-storage mit method-call auf Group#isDefaultGroup(), wie Person#locale). Bestehende Formular-Definitionen und Views funktionieren unverändert; das Feld ist damit automatisch schreibgeschützt.
- Der Migrations-Nachprozessor zu #29447 (RemoveAnonymousFromDefaultGroupProcessor, bisher nur in 8.0.0-alpha8 ausgeliefert) ermittelt die Standardgruppe über den konfigurierten Namen default-group (aus der ApplicationConfig, wie schon den Namen des anonymen Accounts) und sucht die Gruppe per Name in der Tabelle Group, statt das gespeicherte Flag zu lesen. Grund: der MigrationService führt alle Prozessoren aller anstehenden Migrationen vor allen Nachprozessoren aus; die Migration dieses Tickets löscht die Flag-Werte in der Prozessor-Phase, so dass der Nachprozessor auf einer Datenbank, die beide Migrationen in einem Lauf durchführt, per Flag keine Gruppe mehr fände. Nebeneffekt: der Nachprozessor arbeitet auch dort korrekt, wo das Flag bereits veraltet war.
- Dokumentation (JavaDoc des Konfigurations-Properties, des Getters, von isDefaultGroup() sowie Tooltip des Modell-Attributs in Deutsch und Englisch): die Standardgruppe ist die Gruppe, in die jeder neu angelegte Account aufgenommen wird; bestehende Accounts werden bei einer Änderung der Einstellung nicht angepasst; der anonyme Account ist ausgenommen.
- Administrations-Ansichten (React, tl-layout-view): der Anlege-Dialog für Gruppen zeigt das Feld nicht mehr; das Gruppen-Formular zeigt es als berechneten, schreibgeschützten Wert (auch im Bearbeitungsmodus).
- Die React-Demo-Anwendung (tl-demo-react) konfiguriert die Gruppe users als Standardgruppe, damit das Flag in der Administration beobachtbar ist.
- Test TestDefaultGroup (tl-core) prüft mit eigener Konfiguration: die konfigurierte Gruppe ist Standardgruppe, eine andere konfigurierte sowie eine zur Laufzeit angelegte Gruppe nicht.
Nicht Bestandteil: eine Aktion "alle Accounts aufnehmen" oder eine automatische Aufnahme bestehender Accounts.
Migration
Die Modell-Migration Ticket_29563_default_group_derived (tl-element) löscht das Attribut tl.accounts:Group#defaultGroup einschließlich der Flex-Daten der Tabelle Group und legt es als abgeleitetes Attribut neu an; sie läuft automatisch, manuell ist nichts zu tun. Anwendungen, die Group#setDefaultGroup(boolean) oder Group.GROUP_DEFAULT verwenden, müssen diese Aufrufe entfernen: die Standardgruppe wird ausschließlich über default-group im InitialGroupManager festgelegt. Die Migration zu #29447 (Entfernen des anonymen Accounts aus der Standardgruppe) setzt jetzt eine konfigurierte default-group voraus, die zum Zeitpunkt der Migration diese Gruppe benennt; ohne konfigurierte Standardgruppe entfernt sie nichts.