Änderungen
Was sich in diesem Portal geändert hat, neueste Fassung zuerst. Im Betrieb ist gerade Fassung 0.30.0.
Changelog — BTV Portal
SemVer, Einträge mit Bereichs-Präfix (core:, verwaltung:, <modul>:). Die Fußzeile liest die erste ## [x.y.z]-Überschrift als laufende Version — wer eine neue Fassung ausliefert, trägt sie hier oben ein.
Zählung vor dem Livegang: 0.x. Das Portal ist noch nicht produktiv; die Fassungen zählen deshalb ab dem 09.09.2026 unter 0 weiter (0.22.0 folgt auf 2.21.0 — die Nebenzahl läuft durch, damit nichts verwechselt wird). Die Einträge darunter behalten ihre alten Nummern 1.x und 2.x: Sie sind so ausgeliefert worden, und ein Verlauf, der sich nachträglich umbenennt, ist schlechter als einer mit einem Bruch. Die 1.0.0 vergibt der Auftraggeber ausdrücklich mit dem Livegang.
Die Einträge bis einschließlich 1.2.0 sind nachträglich aus der Git-Historie zusammengefasst: Der Neubau entstand vom 31.07. bis zum 02.08.2026 am Stück, ohne dass unterwegs ein Changelog geführt wurde. Sie sind deshalb gröber als das, was ab 1.3.0 hier steht — einen Verlauf zu erfinden, den es so nie gab, wäre schlechter als ein zusammengefasster.
[0.30.0] — 2026-09-13
- core: Die Startseite nutzt die volle Breite. Die Arbeitsfläche stand zentriert zwischen zwei breiten Leerstreifen, obwohl die Konvention seit 2.15.0 sagt, der Inhaltscontainer bekommt keinen Deckel: Der Override der Arbeitsfläche setzte
width: 100%, hob den Deckel--seitenbreiteder Grundregel damit aber nicht auf — nur Tabellen- undbreit-Seiten entkamen ihm. Jetzt stehtmax-width: noneausdrücklich dort, mit Prüffall. - core: Jede Modulkachel trägt ein Bild statt Buchstaben. Vier von fünf Kacheln zeigten Kürzel („AE", „AB", „NS", „M"), die sich um einen Buchstaben unterscheiden; nur die Benutzerverwaltung hatte ein Symbol. Die drei Fachmodule nennen jetzt eines je Kachel (Briefkasten, Board, Newsletter, Ausweis), und die Startseite fällt in drei Stufen zurück: Symbol · Modulbild aus
assets/module/· Kürzel. Ein neues Modul, das nur sein Modulbild mitbringt, steht damit nie mit Buchstaben da. Die Gruppe „System" hat ihr Zahnrad — der Name stand in der Seitenleiste, die Symboltabelle kannte ihn nicht. - core: Übersicht der Schnittstellen unter System · Zustand · Schnittstellen. Mit wem spricht dieses Portal, in welcher Betriebsart, in welchem Zustand, wann zuletzt, über welche Jobs, mit welchen Umgebungsschlüsseln (nur die Namen) — Kern und Module in einer Liste, aus einem Register. Vertrag
App\Contracts\Schnittstelle, Kern-Einträge inconfig/schnittstellen.php, Modul-Einträge über den neuen HookModul::schnittstellen(). Sieben Anbindungen stehen dort: Mitgliederverwaltung, Anmeldedienst, Verzeichnis (Profilbilder), Postversand, die beiden Altquellen und der Newsletter-Dienst (aus dem Modul). Die Fläche ruft nichts auf — jeder Zustand kommt aus Konfiguration, Protokoll und Zählern; der Weg in der letzten Spalte führt zum gedrosselten Prüfknopf. - core: Die Mitgliederverwaltung für alle Module über den Vertrag
App\Contracts\Mitgliederdaten: Personen (einzeln, über Kennung oder gebundenes Konto), Lizenzen, Vereine und Listen — aus dem Abgleich-Index und, wo es sein muss, von der Gegenstelle, mit denselben Schutzmechanismen wie der Kern. Der Anlass: Es gab keinen Kern-Dienst dafür, und das Newsletter-Modul hatte sich einen zweiten Client mit eigenen Umgebungsschlüsseln gebaut. - newsletter: Die Quelle geht über den Kern. Ohne eigene
NEWSLETTER_QUELLE_*-Schlüssel nutzt das Modul die Anbindung des Kerns (Adressen, Schlüssel, Tageszähler). Die eigenen Schlüssel bleiben als Ausnahme für ein abweichendes Adressschema. Läuft der Kern insimulate, während das Modullivesteht, ist das ein lauter Fehler — Beispieldaten in echten Verteilern wären kein Abgleich. - Konventionen ergänzt (Kacheln, Mitgliederdaten, Anbindungen); 25 neue Prüffälle.
[0.29.2] — 2026-09-10
- core: Nachrichten im Postfach sind lesbar und ihre Verweise klickbar. Eine Nachricht stand als Wand aus Zeilenumbrüchen, und Adressen darin waren Text zum Abtippen.
TextFormat::nachricht()zeichnet jetzt aus, was ein geschriebener Text ohnehin trägt: Leerzeilen als Absätze, Zeilen mit-als Aufzählung,fettals Hervorhebung,https://…als Verweis — eigene Adressen zeigen den Pfad statt des Servers, fremde bleiben vollständig und öffnen nichts still. Maskiert wird zuerst. Gilt im Postfach und in den Unterhaltungen der Verwaltung. Die Erinnerung an überfällige Akkreditierungsanträge ist damit eine Liste mit hervorgehobener Kennung und einem Verweis je Antrag.
[0.29.1] — 2026-09-10
- digi: Die Boards blenden erledigte Vorgänge aus, bis jemand sie ausdrücklich sehen will — ein Board ist eine Arbeitsfläche, und was erledigt ist, braucht dort keinen Platz. Dieselbe Regel wie im Listengerüst: Die Vorgabe gilt, solange niemand das Filterformular abgeschickt hat; das Kennzeichen wandert in Board-Wechsel, Vorgangslinks und Archivsicht mit. Die Vorgabe zählt nicht als gesetzter Filter.
- digi: Der Zustandsfilter wirkt auch in der Sprintplanung — auf die Sprintspalten. Abgeschlossene Sprints sind dort mit derselben Vorgabe ausgeblendet wie in der Sprintliste; eine ausgeblendete Spalte nimmt ihre Karten mit und steht nicht als Ziel in der Klappliste, der Backlog bleibt immer. Die Sperre beim Ziehen löst dieser Filter nicht aus: Er blendet Spalten aus, keine Karten innerhalb einer Spalte. Das Listengerüst lässt eine Fläche dafür einen Filter selbst auf ihre Sammlung anwenden (
filterAnwendenSammlung()), wenn er keine Spalte der Zeile ist.
[0.29.0] — 2026-09-10
- digi: Die Sprintliste filtert nach Zustand und blendet abgeschlossene Sprints aus, bis jemand sie ausdrücklich sehen will. Dafür kennt das Listengerüst jetzt eine Filter-Vorgabe (
standardfilter()): Sie gilt, solange niemand das Filterformular abgeschickt hat. Der Unterschied zwischen „nie gefiltert" und „bewusst alles abgewählt" ist einer Adresse nicht anzusehen — beide Male fehlt der Parameter —, deshalb trägt das Formular ein Kennzeichen, das in alle Verweise der Seite mitwandert. Wer den Filter leert, bekommt wirklich alles.
[0.28.1] — 2026-09-10
- core: Der Seitentitel nimmt die ganze Breite, eine breite Tabelle rollt in ihrer Hülle statt die Seite. Der Deckel auf dem Held-Inhalt brach lange Titel nach 68 Zeichen um, obwohl rechts Platz war — die Lesebreite gilt dem Fließtext. Und eine
1fr-Rasterspalte ist mindestens so breit wie ihr breitester Inhalt: Eine breite Tabelle weitete damit Rumpf und Seite, die Seite rollte waagrecht. Rumpf, Inhalt und Kartenzeile stehen jetzt aufminmax(0, 1fr), und die Tabellenhülle rollt wieder nur die Tabelle. Zwei Tests halten beides fest.
[0.28.0] — 2026-09-10
- digi: Vollabgleich mit dem Digitalisierungsportal.
portal:altquelle digi --aktualisierennimmt die Quelle für ihre Felder als führend — Status, zuständige Person, Kategorie, Titel, Texte, Zeitstempel und Planung werden nachgezogen, nicht nur Leerstellen gefüllt. Portal-eigene Angaben (Nachrichtenstrang, im Portal geschriebene Nachrichten, Stufe im Sprintboard) bleiben unberührt, ein leerer oder falscher Quellwert überschreibt nie, und wo im Portal nach dem letzten Lauf gearbeitet wurde, nennt der Bericht den Vorgang mit Kennung und überschriebenen Spalten. Neue Berichtsspalte „aktualisiert". Verlauf, Nachrichten, Verweise, Nutzen und Anhänge werden für jeden Vorgang abgeglichen, auch für den unveränderten — die Ursache der lückenhaften Historie lag in der Übernahme des v1-Portals, die bei „unverändert" nicht in die Unterzeilen sah. Eine Adresse im Feld der zuständigen Person wird zum Namen des Portalkontos aufgelöst; Quelltabellen, die niemand liest, stehen mit Grund im Bericht. Spaltenkarte inALTQUELLEN-IMPORT.md.tools/deploy/altquelle-digi.shreicht--aktualisierendurch.
[0.27.1] — 2026-09-10
- core: Die Dokumentenablage nimmt Arbeitsmappen (
.xlsx) an. Zwei Vorlagen aus dem Digitalisierungsportal waren bei der Übernahme abgewiesen worden. Geprüft wird weiterhin der Inhalt, nie der Name: Nur eine echte OOXML-Arbeitsmappe kommt durch, ein Zip-Archiv mit dieser Endung nicht, und angezeigt im Browser wird sie nie — nur heruntergeladen.
[0.27.0] — 2026-09-10
Angaben untereinander, Profilseite mit den Daten fremder Systeme, Sprintplanung aus dem Altportal sichtbar.
- core: Angaben stehen portalweit untereinander. Eine zweite, spätere CSS-Regel legte Beschriftung und Wert als Raster in vier, fünf Spalten nebeneinander und überschrieb still die erste; ein zweiter, verdeckter Fehler im Wrapper der Datenzeile hätte denselben Effekt zurückgebracht.
.angabenist jetzt einmal definiert: eine Angabe je Zeile, Beschriftung links, Wert rechts, auf schmalen Schirmen gestapelt. Das Raster gehört den Kästen, nicht ihrem Inhalt; ein Test wacht darüber. - verwaltung: Die Konto-Profilseite zeigt, was das Portal aus fremden Systemen weiß. Mitgliederverwaltung: Art der Zuordnung (Zustimmung, Handentscheidung, automatischer Treffer samt Bewertung), Quellen und Stand des Abgleich-Index, jede Lizenz mit Art, Nummer und Gültigkeit — abgelaufene als abgelaufen. Internes Konto: gekürzte Entra-Kennung, Adresse von dort, letzte Anmeldung, Datum des Profilbild-Abrufs; ein Anmeldename wird nicht gespeichert und nicht behauptet. Newsletter: zwei belegbare Auskünfte über die Adresse (in einer Quelle des Versands enthalten, Versandprotokoll), sonst „nicht ermittelbar" mit Grund. Herkunft aus einer Altquelle mit Datum und Altkennung, wenn belegt. Aus dem Index wird nur der Eintrag der zugeordneten Kennung gelesen, Angaben Dritter bleiben verschlüsselt.
- digi: Sprintplanung aus dem Digitalisierungsportal vollständig und sichtbar. Die Quelle hat genau zwei Planungstabellen, alle 18 Spalten kommen an. Drei Defekte behoben: eine unbekannte Prioritätsstufe wird in der Liste ergänzt statt beim nächsten Speichern verloren zu gehen; die Reihenfolge der Sprints ist als Spalte sichtbar und mit Pfeilen änderbar; der Spaltenkopf der Sprintplanung nennt Zeitraum und Zustand (er las
statusstattstate) und summiert den Aufwand des ganzen Sprints. Nutzen- und Anhangtabellen der Quelle haben ihre Gegenprobe.
[0.26.0] — 2026-09-10
Benutzerverwaltung aus einem Guss, Antrags-Datenblatt der Medienakkreditierung nach dem Presseportal. Konzept in docs/BENUTZERVERWALTUNG-KONZEPT-2026-09-10.md.
- verwaltung: Die Konto-Seite ist eine Profilseite. Sie beginnt mit der Person — Initialen, Name, Kennung, Rolle, Zustand — und zeigt acht Bereiche als Karten: Person & Kontakt, Zugang & Sicherheit, Rollen & Rechte, Mitgliederverwaltung, Newsletter, Fachmodule, Prüfung & Verlauf, Gefahrenzone. Die vierzehn gleich aussehenden Knöpfe von früher stehen jetzt bei den Angaben, die sie ändern: höchstens drei je Karte, genau einer gefüllt. Woher jede Angabe stammt und wohin sie weitergeht, sagt eine Fußnote am Feld mit Legende am Seitenende. Neu erreichbar: die Prüfspur dieses Kontos, die Anliegen und Akkreditierungen der Person, die Newsletter-Auskunft. Das alte Datenblatt bleibt als Reiter „Alle Angaben" mit Suche, Filter und Excel-Ausfuhr. Eine Bankverbindung erscheint nie im Klartext.
- verwaltung: Gruppe „Konten" mit drei Menüpunkten und Reitern statt fünf gleichrangiger Einträge: Konten [Übersicht | Freigaben], Bestätigungen [Rollen | Mitgliederzuordnung], Unterhaltungen. „Freigaben" bleibt mit Zähler in der Kopfzeile, der Reiter unten zählt nicht doppelt.
- core: Navigationspfad durchgängig. Jede Stufe mit Seite ist verlinkt und trägt ihre Parameter — die Stufe „Konto" führte bisher auf eine leere Seite. Über der Liste stehen Gruppe und Menüpunkt, darüber die Wurzel „Verwaltung". Entscheidung und Rückfrage hängen am Konto, von dem der Klick kam, nicht an der Warteschlange „Freigaben".
- core: Vier Knopfsorten statt einer. Gefüllt = Aktion, rot gefüllt = Gefahr, umrandet = Navigation auf eine andere Fläche, Textverweis mit Pfeil = derselbe Datensatz aus einem anderen Winkel. Höchstens eine gefüllte Aktion je Fläche, und der Zustand entscheidet, welche. Regel und Muster in
KONVENTIONEN.mdund auf/admin-muster. - core: Herkunft und Fußnoten als Baustein. Statt Klammertext hinter jedem Wert eine hochgestellte Ziffer und eine Legende mit Quelle und Richtung („aus dem Benutzerkonto der Organisation, nur lesend" · „aus der Mitgliederverwaltung, keine Weitergabe" · „wird an den Newsletter-Versand übermittelt"). Die Herkunftsregel stand doppelt im Code und steht jetzt einmal.
- core: Held für Verwaltungsflächen. Jede Fläche kann einen Kopf angeben; Flächen zu einem Datensatz zeigen Initialen, Namen, Kennung, Marken und rechts die eine Aktion. Genau eine Überschrift erster Ordnung je Seite, jetzt geprüft.
- verwaltung: Prüfspur filtert nach Konto (
?konto=<Kennung>, als Objekt und als handelnde Person); DienstKontobezuegeliefert Anliegen, Akkreditierungen (über die E-Mail), Prüfspur, Zuordnung, Lizenzen. - akkreditierung: Datenblatt eines Antrags nach dem Vorbild des Presseportals. Angaben und Nachweis als Kästen nebeneinander, darunter Statusverlauf und Mails zu diesem Antrag; Telefon und E-Mail als Verweise, Zustimmungen mit Zeitpunkt. Jeder Nachweis nennt Typ und Größe und lässt sich in der Seite ansehen — über dieselbe geschützte Route, mit Prüfspur. Der Ausweis lässt sich herunterladen und neu erzeugen; dabei wechselt der Prüfcode, der alte QR-Code verfällt. „Nachweise löschen", „Badge löschen" und „Antrag vollständig löschen" stehen im Kasten „Datenschutz / Löschen". Das Formulargerüst kennt dafür zweispaltige Abschnitte, Nachweise mit Vorschau und Aktionen im Feld.
- akkreditierung: presse@btv-turnen.de ist Standard für Absender und internen Empfänger der Modul-Mails, änderbar im Reiter „Kontakt". Solange die Adresse im Mailversand nicht als Absender freigegeben ist, geht die Mail unter dem Portal-Absender hinaus und presse@ steht als Antwortadresse — nichts geht still verloren; ein Selbstprüfungspunkt zeigt den Zustand.
[0.25.0] — 2026-09-10
Funktionsabgleich Anliegen und Medienakkreditierung gegen die Altportale, Benachrichtigungen im Postfach und per Mail. Zwei Bestandsaufnahmen (docs/DIGI-FUNKTIONSABGLEICH-2026-09-10.md, docs/AKKREDITIERUNG-FUNKTIONSABGLEICH-2026-09-10.md) gegen den Quellcode des Digitalisierungs- und des Presseportals; jede Lücke mit HTTP-Test durch die Route geschlossen.
- core: Neuer Dienst
Portalmitteilung. Eine Mitteilung geht auf beiden Wegen hinaus — als Nachricht im Portal-Postfach und als E-Mail über die Outbox. Er führt je Empfänger einen Nachrichtenstrang fort, statt je Ereignis eine neue Unterhaltung zu beginnen, und sagt, was geschehen ist: Zu einer Adresse ohne Portalkonto geht die Mail allein hinaus. MitanGruppe()erreicht er alle Konten, die ein Recht halten — die internen Meldungen der Module gingen bisher an eine Funktionsadresse ohne Konto. Die Statusbenachrichtigung der Registrierung ist der erste Aufrufer; Module schreiben keine Kern-Tabellen mehr selbst. - digi: Benachrichtigungen landen im Portal-Postfach und per Mail. Eingangsbestätigung, interne Meldung, Statuswechsel, Nachricht des Teams und Nachricht am Vorgang erzeugen beides; der Zähler in der Kopfleiste zeigt sie. Wer stellvertretend erfasst hat, bekommt die Post ebenso wie die einreichende Person. Ohne Portalkonto steht im Verlauf einmalig ein Systemvermerk. Die Meldung nach dem Statuswechsel sagt ehrlich, ob im Portal, per Mail oder gar nicht benachrichtigt wurde.
- digi: Bearbeitungsverlauf sichtbar, Blättern durch die gefilterte Liste. Zweiter Klappbereich neben dem Statusverlauf mit altem und neuem Wert; auf der Vorgangsseite eine Blätterleiste, die den Filter der Board-Liste mitnimmt.
- digi: Inhalt bearbeiten vollständig. Das Team kann Dateien nachreichen und entfernen sowie Ticket- und Planner-Verweise setzen, alles im Verlauf. Beim Verschieben wird auch das Zielboard geprüft — vorher konnte eine Person mit Freigabe für ein Board Vorgänge in jedes andere schieben. Der Menüpunkt „Anliegen erfassen" hängt am Bearbeitungsrecht. Im Steuerungsformular ist an jedem Status vermerkt, ob er benachrichtigt.
- digi: Einstellungen. „Verantwortlich" entsteht aus den Konten mit Bearbeitungsrecht, ergänzbar über die Einstellungen. Mail-Empfänger der Boards werden vor dem Speichern geprüft. Die Stufen des Ablaufs lassen sich verschieben, aber nicht umbenennen oder entfernen; eine Stufe mit Vorgängen kann nicht gestrichen werden.
- digi: Planung. Filter Dringlichkeit, Verantwortliche und Umfang in Priorisierung und Sprintplanung; mit aktivem Filter ist Verschieben auf dem Sprintplanungs-Board gesperrt, mit sichtbarer Begründung.
- digi: Ansprechperson, „aus dem eigenen Verantwortungsbereich" und „Leitung informiert" sind wieder Pflicht (wie im Digitalisierungsportal, Entscheidung des Auftraggebers 10.09.2026).
- akkreditierung: Die drei internen Meldungen — neuer Antrag, nachgereichte Unterlagen, Erinnerung an Überfällige — landen im Postfach jedes Kontos mit Bearbeitungsrecht und zusätzlich als E-Mail; die Funktionsadresse wird weiter bedient, wenn sie zu keinem Konto gehört. Post an die antragstellende Person bleibt reine E-Mail: Medienvertretende haben kein Portalkonto.
- akkreditierung: Nach dem Nachreichen springt der Status von „Rückfrage offen" auf „In Prüfung" zurück, mit Verlaufseintrag — vorher blieb die Antwort in der Liste unsichtbar. Die Ausgabe von Hand hält fest, wer sie vermerkt hat; die Nachreiche-Adresse hat dieselbe Bremse wie das Formular; eine geänderte interne Bemerkung steht im Verlauf; der Funktionsfilter zeigt auch Werte, die nur noch an Altanträgen hängen.
- akkreditierung: Die Infomail an die Wettkampfleitung geht über einen Editor hinaus (Empfänger, Betreff, Text änderbar), trägt QR-Code und Druckliste als Anhänge, verlangt das Bearbeitungsrecht wie im Altportal und schreibt je Antrag einen Verlaufseintrag.
- akkreditierung: Öffentliche Seite. Verweis auf die Medienrichtlinien am Zustimmungskästchen, Ablauf in vier Schritten über dem Formular. Die automatische Löschung hat einen Notaus in den Einstellungen. Eine Veranstaltung mit Anträgen wird beim Löschen deaktiviert statt verweigert.
- akkreditierung: Übernahme aus dem Presseportal prüft jetzt auch die Nachweise gegen unbekannte Spalten und bringt die Einstellungen des Fachbereichs mit: bis zu 16 freigegebene Mailtexte, Funktionsliste, interner Empfänger, Bearbeitungszusage, Löschfristen, Notaus, Schalter für abgelehnte Anträge in der Einlassliste. Übernommen wird nur, wo im Neubau noch der Auslieferungsstand steht (
--einstellungen-ueberschreibenhebt das auf). - akkreditierung: Der Wortlaut des SAFE-SPORT-Merkblatts kommt jetzt 1:1 aus dem freigegebenen PDF (Safe Sport DTB/BTV) statt aus einer eigenen Formulierung — Seite und PDF-Ausgabe teilen weiterhin dieselbe Quelle (
Merkblatttext). Die bisherigen v2-eigenen Zusätze (Aufwärmzonen, Vorrang der Wettkampfleitung, „Wenn Dir etwas auffällt") sind fachlich nicht freigegeben und deshalb entfallen — sie müssten beim Fachbereich eigens nachgereicht werden, falls sie weiterhin gelten sollen. - akkreditierung: Die Infomail an die Wettkampfleitung (
wl_info) kündigt ihre Anhänge jetzt an. QR-Code und Druckliste hängen seit heute an dieser Mail (AkkreditierungWlMail::anhaengeErzeugen); der ausgelieferte Text erwähnte sie bisher nicht. - deploy:
tools/deploy/altquelle-presse.shrichtet den Lesezugang zum Presseportal ein, spiegelt die Nachweise und startet die Übernahme. - doku: Entscheidungen Ü9 (kein SQL-Download aus der Oberfläche) und Ü10 (Löschprotokoll des Presseportals) in
ENTSCHEIDUNGEN-PHASE4.md.
[0.24.0] — 2026-09-10
Übernahme aus dem Digitalisierungsportal gegen die Produktivquelle geprüft, Startziel der Anliegen-Gruppe nach Recht.
- digi: Übernahme aus dem Digitalisierungsportal um fünf Spalten erweitert, die die Gegenprobe des Probelaufs gemeldet hatte. Archivstand (
archived_at), Adresse der erfassenden Person (created_by_email, neue Spalte am Anliegen), internes Kennzeichen (internalaus der Spalte statt aus der Kategorie geraten), Adresse an der Nachricht (comments.author_email) und Zieldatum der Planung (target_date) kommen mit — und sind zu sehen: Archivdatum und „Erfasst von" auf der Vorgangsseite, der Hinweis „intern erfasst" für das Team, die Adresse im Nachrichtenfaden, das Zieldatum in Priorisierung und Sprintplanung. „Meine Anliegen" findet einen Vorgang jetzt auch über die Adresse der Person, die ihn stellvertretend erfasst hat. Ein zweiter Lauf trägt alles an vorhandenen Vorgängen nach; ein im Portal aus dem Archiv geholter Vorgang wird nicht erneut archiviert. Ein Status, den die Liste nicht kennt, wird vor „Erledigt" eingehängt statt hinten angehängt. Übersprungene Planungszeilen nennen ihren Grund (verwaist, Zweig ohne Tabelle, unbekannter Zweig, Probelauf). - digi: Der Menüpunkt „Anliegen" öffnet „Alle Boards", wenn die Person das Recht dafür hat — vorher führte er immer zu „Einreichen", dem ersten Kind.
/digiund die Startkachel folgen derselben Regel;/digi/einreichenbleibt direkt erreichbar. Die Seitenleiste bevorzugt dafür die eigene Zieladresse eines Moduls vor dessen erstem Kind — Module kennen ihre Rechte und ihren Arbeitsablauf, die Leiste nicht. Nebenbei repariert: Das Newsletter-Sync-Modul trug einen toten Präfix als Gruppenziel. - deploy:
tools/deploy/altquelle-digi.shträgt den Lesezugang zur Datenbank des Digitalisierungsportals in die dev-.env ein (per FTPS aus dessen Konfiguration, beide Portale liegen auf demselben Plesk), spiegelt die Anhänge per Tar-Strom nach dev (das dev-Abonnement darf nicht in den fremden Vhost lesen) und startet den Probelauf bzw. mit--scharfdie Übernahme.
[0.23.0] — 2026-09-09
Bestand mit Namen, Verbindungsprüfung ohne Fehlalarm, Berechtigung berichtigt.
- verwaltung: Personensuche im Bestand der Mitgliederverwaltung. Der Bestand zeigte nur Kennungen. Neu ist ein Suchformular über der Liste: E-Mail, Vor-/Nachname, Geburtsdatum und Telefon werden mit denselben Normalisierungs- und Hash-Funktionen wie beim Abgleich in Prüfsummen verwandelt; die Vorauswahl läuft weiterhin ausschließlich über die Hash-Spalten, entschlüsselt werden nur die höchstens fünfzig Treffer, und jede Einsicht steht mit Trefferzahl und Merkmalsnamen — ohne Eingabe und ohne Hash — in der Prüfspur. Abgesendet wird per POST mit Weiterleitung, damit kein Personenmerkmal in einer Adresse steht; während einer Suche gibt es keine Ausfuhr. Die neue Spalte „Konto" zeigt ohne jede Entschlüsselung, wo ein Portalkonto zugeordnet ist, und verlinkt das Datenblatt. Dafür kennt das Listengerüst jetzt ein Kopfformular (
kopfformular(),POST /admin/{flaeche}/kopfformular). - core: Die Verbindungsprüfung der Mitgliederverwaltung ruft genau eine Seite ab statt bis zur Seitengrenze zu blättern. Mit Seitengröße 1 lief sie bei jeder großen Quelle in die Grenze und meldete „unvollständig", obwohl die Anbindung stand — 36 Sekunden und zwei Alarme für nichts. Der Befund nennt jetzt die Gesamtzahl laut Betreiber. Die Seitengrenze (
PHOENIX_MAX_SEITEN, 200 statt 50) meldet im Fehlerfall angekündigte Seitenzahl und tatsächlich gelieferte Seitengröße, damit ein ignorierteslimitsofort auffällt. - core: Berechtigung für den Profilbild-Abruf berichtigt. Doku und Meldungen nannten
User.ReadBasic.All; laut Microsoft istProfilePhoto.Read.Alldie Anwendungsberechtigung mit den wenigsten Rechten,User.Read.Alldeckt sie ebenfalls ab. - deploy:
tools/deploy/phoenix-live.shschaltet dev aufliveund übernimmt Schlüssel und Basis-Adressen aus der Konfiguration des Vorgängerportals, ohne dass ein Wert auf dem Bildschirm erscheint. - Zählung: Fassungen laufen bis zum Livegang unter 0.x weiter (Hinweis im Kopf dieser Datei).
[0.22.0] — 2026-09-09
Oberflächenrunde nach dem Vorbild des Vorgängerportals. Sechs Punkte, die der Auftraggeber an Bildschirmfotos markiert hat, ein Bugfix und eine Zusammenlegung in der Verwaltung.
- core: Das Hintergrundbild steht wieder auf jeder Seite. Zwischenzeitlich lief es nur noch auf den Gastseiten, weil es auf der Arbeitsfläche unter Karten durchlief. Der Auftraggeber wollte es zurück — exakt wie im Vorgängerportal, mit Seitenleisten-Versatz ab 900px. Karten, Tabellen, Seitenleiste und Kopfleiste tragen weiterhin eigene deckende Hintergründe.
- core: Kopfmenü zeigt Namen nur, wer die Erklärungen eingeschaltet hat. Ist der Schalter aus, stehen in der Kopfleiste nur noch die Symbole mit ihren Zähler-Blasen — kein
display:none, der Text bleibt der Vorlesehilfe erhalten und kommt zusätzlich alstitleam Zeiger zurück. - core: Der Inhalt füllt die Arbeitsfläche randvoll. Der Deckel von 1560px ließ auf einem 2000px-Fenster links und rechts breite Leerstreifen stehen. Der Container nutzt jetzt immer die volle Breite; die Lesbarkeit einzelner Absätze regeln weiterhin
--lesebreiteund.fliesstext. - core: Reiter stehen linksbündig, wie im Vorgängerportal. Vorher wurden zwei oder drei Reiter auf die ganze Zeile gestreckt und zentriert. Jetzt sind sie nur so breit wie ihr Text, umbrechend statt gequetscht — Board-Auswahl, Verwaltungs- und Anmeldeseite eingeschlossen.
- core/digi: Kachelraster nutzen die Breite sinnvoll, die Zweig-Kacheln tragen ein Symbol.
auto-filllegte auf breiten Schirmen leere Spalten an, drei Kacheln standen klein und linksbündig vor einer leeren Fläche.auto-fitmit einer Obergrenze je Kachel (30rem) füllt die Zeile, ohne dass eine einzelne Kachel ausufert — einheitlich für Startseite, Profil und Digi-Start. Die drei Zweig-Kacheln unter „Anliegen einreichen" bekommen ein Symbol vor der Überschrift (Zweig::symbol()). - core: Eine Kastenbreite für alle erklärenden Kästen, eine Lesebreite für allen Fließtext. Hilfe-Block, Hinweiskasten und Meldung endeten an drei verschiedenen Kanten (84ch neben verstreuten 68ch/46rem).
--kastenbreiteist jetzt an--lesebreitegekoppelt (Lesebreite + Kastenpolster), die Textkante eines Kastens liegt damit auf der Kante des Fließtexts daneben. Abschnitt „Breiten" inKONVENTIONEN.md. - core: Profilbild aus Microsoft. Wer sich über das Benutzerkonto der Organisation anmeldet, bekommt sein dort hinterlegtes Profilbild ins Portal — beim Anmelden und auf Knopfdruck im Profil („Aus Microsoft übernehmen"). Das Bild wird wie ein Upload neu gerechnet (quadratisch, 320 Pixel, ohne Aufnahmeort). Ist bei Microsoft kein Bild hinterlegt, sagt das Portal genau das; ein Fehlschlag hält niemanden von der Anmeldung ab. Der Abruf läuft über die Anmelde-App, nicht über die Mail-App — deren Zugriff ist auf das Absender-Postfach beschränkt (Warnung schon im Vorgängerportal). Ab Werk aus (
ENTRA_PHOTO_SYNC, BerechtigungUser.ReadBasic.Allmit Administrator-Zustimmung, Einzelheiten inDEPLOY.md); die Selbstprüfung sagt, ob sie vorliegt. Bestandskonten holtphp artisan portal:profilbilder-pruefen --entranach. Der Weg zu Microsoft Graph liegt jetzt einmal im Portal (App\Services\Graph) statt zweimal — Mailversand und Bildabruf teilen sich die Token-Beschaffung. - verwaltung: Eine Gruppe „System" statt „Konfiguration" und „Betrieb". Vier Menüpunkte: Übersicht, Einstellungen (Einstellungen · Texte & Inhalte · Rollen & Rechte), Protokolle (Prüfspur · Mail-Protokoll · Job-Läufe) und Zustand (Selbstprüfung · Kennzahlen · Bestand der Mitgliederverwaltung). Jeder Menüpunkt ist eine Seite mit Reitern über seine Flächen. Alle Adressen bleiben: Jeder Reiter ist weiterhin eine eigene Fläche mit eigenem Recht unter
/admin/<schluessel>; Reiter ohne Recht fehlen, ohne jedes Recht fehlt der Menüpunkt. Menüpunkt und Reiter entstehen aus denselben Registern wie die Adressen (sektion()+menuegruppe()), der Menüpunkt ist auf jedem seiner Reiter markiert, die Krume nennt beide Stufen („Start › System › Protokolle › Mail-Protokoll").
[2.21.0] — 2026-09-08
Aufgeräumte Arbeitsflächen — nach dem Vorbild des Vorgängerportals. Zwei Bildschirmfotos derselben Kontenliste nebeneinander: Das alte Portal zeigte Suchzeile, Auswahl und Knopf in einer Reihe direkt über der Tabelle, keine Zwischenüberschrift, enge Zeilen, die Kennung als Verweis. Das neue verbrauchte denselben Platz für ein Klappfeld „Filter & Ansicht", eine Überschrift „9 Einträge", einen Knopf „Öffnen" am Zeilenende — und die Kennung brach mitten im Wort um. Weil alle Flächen der Verwaltung und der Module dasselbe Listengerüst benutzen, ist der Umbau einmal gemacht und gilt überall.
- verwaltung: Kennung und Name führen zum Datensatz. Das Gerüst verlinkt jetzt alle festen Spalten (die, die den Eintrag benennen), nicht nur die erste. Wer auf den Namen klickte, traf bisher ins Leere. Die Knöpfe „Öffnen" und „Ansehen" am Zeilenende sind dort weg, wo ein Zeilenziel sie ersetzt: Kontenliste, Rollen-Bestätigungen, Rollen, Sprints, Akkreditierungs-Anträge und -Veranstaltungen, Zuordnungsprüfung. Was etwas tut (Bestätigen, Löschen, Nachricht), bleibt als Aktion stehen.
- verwaltung: Die Filterzeile steht offen. Suchfeld, Filter und „Suchen" in einer Leiste über der Tabelle; „Zurücksetzen" und „Excel-Export" daneben. Ein Filter, den man erst aufklappen muss, wird seltener benutzt als einer, den man sieht — und der Platz, den das Klappfeld sparte, war ohnehin leer.
- verwaltung: Die Zahl der Einträge ist eine Angabe, keine Überschrift. Vorher eine H2 in Titelgröße unter dem Seitentitel; jetzt leise neben dem Spaltenwähler. Weniger Luft auch um Titel, Krume, Meldungen und Karte; engere Zeilen, Kopfzeile in Kapitälchen wie im Vorgänger.
- verwaltung: Kennungen brechen nicht mehr um. „BTV-" in der einen und die Nummer in der nächsten Zeile ist keine Kennung mehr, sondern ein Rätsel. Verlinkte Zellen und Kennungsspalten bleiben einzeilig.
- core: Rollen tragen die Farbe ihrer Familie —
App\Support\Rollenfarbe, an jeder Stelle dieselbe: Kontenliste, Datenblatt, Rollen-Bestätigungen, Profil, Musterseite. Super-Admin rot, Admin/GS-Admin orange, Hauptberuf blau, Referent/in violett, Ehrenamt grün, je Modul eine eigene Farbe (Anliegen gelb, Akkreditierung türkis, Newsletter rosa). Neue Modulrollen bekommen die Farbe ihres Moduls von allein. Eine angefragte, noch nicht bestätigte Rolle trägt dieselbe Farbe gestrichelt. Die Farbe ist ein Zusatz — der Name steht immer daneben (WCAG 1.4.1). - verwaltung: Musterseite zeigt die Rollenmarken aller Familien.
Prüfstand: 2600 statt 2595 Tests, alle grün.
[2.20.0] — 2026-09-08
Lizenzabgleich mit der Mitgliederverwaltung. Die Lizenzen standen seit dem ersten Tag im Profil — geschrieben vom Erstabgleich, vom Referentenabgleich oder von der Datenübernahme. Danach fasste sie nichts mehr an: Wer nach der Verknüpfung eine Lizenz erwarb, verlängerte oder verlor, sah im Profil den Stand vom Tag der Registrierung, und die Verwaltung sah dasselbe. Die Hilfe versprach „erscheint beim nächsten Abgleich auch hier" — einen nächsten Abgleich gab es nicht. Die Lizenz-Schnittstelle von it4sport läuft seit heute verlässlich (Datensatzzahl stimmt mit der Anwendung überein, Filter nach Gültigkeitsende), und damit ist der Weg frei.
- core: Dienst
Lizenzabgleich. Liest die Lizenzen der verknüpften Person aus dem Abgleich-Index und schreibt sie ins Profil. Drei Regeln, jede mit Grund: Die Mitgliederverwaltung führt — bei Lizenzen ersetzt sie, weil eine abgelaufene Lizenz, die stehen bliebe, eine falsche Aussage über eine Qualifikation wäre. Eine Lücke im Index ist keine Aussage — steht die Person nicht darin, wird nichts geleert. Nur gebundene Konten — ein Namenstreffer genügt nicht. Gerechnet wird gegen den Index, nicht gegen die Schnittstelle: Die Lizenzquelle kennt keine Abfrage je Person, und ein Abgleich je Knopfdruck kostete Kontingent für alle. Im Protokoll stehen Zahlen (neu, entfallen), nie Lizenzen. - core: Job
phoenix_lizenzen. Führt die Lizenzen aller verknüpften Konten nach, sobald der Index erneuert wurde — und nur dann. Er ist nachphoenix_syncangemeldet, damit er nie gegen den Stand von gestern rechnet. - core: „Lizenzen jetzt abgleichen" im Profil. In der Kachel „Beim Verband", nur für verbundene Zugänge, gedrosselt je Konto. Darunter steht, wann zuletzt abgeglichen wurde; die Rückmeldung nennt den Stand der Quelle. Neue Spalte
profiles.lizenzen_stand_at— eine Lizenzliste ohne Datum ist eine Behauptung, keine Auskunft. - verwaltung: Block „Mitgliederverwaltung" im Datenblatt des Kontos. Verbindung (mit Bestätigungsdatum), Prüfhinweis, jede Lizenz mit Nummer und Gültigkeit, Zeitpunkt des letzten Abgleichs, Stand der Quelle. Dazu die Aktion „Lizenzen abgleichen" — sichtbar nur bei Verbindung, Recht
users.manage, die Vorbedingung wird beim Klick erneut geprüft. - verwaltung: Spalte „Lizenzen" in der Kontenliste, standardmäßig ausgeblendet. Ein Konto ohne Verbindung zeigt „nicht verbunden" statt eines Strichs — ein Strich hieße „keine Lizenz", und das wäre eine Aussage über etwas, das nie geprüft wurde.
- **core:
.env.examplekennt jetzt diePHOENIX_*-Schlüssel.** Sie fehlten dort vollständig; wer die Anbindung einrichten wollte, musste sie ausconfig/phoenix.phpzusammensuchen. Mit dem Hinweis, dass die Lizenzquelle eine eigene Basisadresse hat (Subdomain-Schema).
Prüfstand: 2595 statt 2579 Tests, alle grün.
[2.19.1] — 2026-09-08
Ein Rundgang durch die laufende Anwendung statt durch den Prüfstand: Portal starten, sich als Gast, Mitglied, Verwaltung, Super-Admin, Anliegen-Bearbeitung und Akkreditierung wirklich anmelden, jedem Verweis folgen, jedes Formular abschicken. Rund 2.100 Seitenaufrufe über sechs Rollen, dazu die Kernwege als echte Einreichung: Registrierung von der Adresse bis zum fertigen Konto, „Passwort vergessen" bis zur neuen Anmeldung, Anliegen einreichen und steuern, Akkreditierung vom öffentlichen Antrag über Rückfrage und Nachreichen bis zum Ausweis, Newsletter-Probelauf, Cron zweimal hintereinander, Altquellen-Abgleich im Probelauf.
Der Leitbefund dieser Runde ist ein anderer als der der 2.19.0: Was der Prüfstand nicht ansieht, sieht niemand an. Kein einziger der Befunde unten wäre einem Dienst-Test aufgefallen — jeder liegt genau dort, wo Code und Oberfläche aufeinandertreffen, und drei von ihnen standen sogar unter einer grünen Prüfung, die daneben zielte.
Prüfstand: 2579 statt 2572 Tests, alle grün.
Wege, die ins Leere führten
- core: Die Krume verlinkt keinen Modul-Präfix mehr, den es als Seite nicht gibt. Auf jeder Seite des Newsletter-Bereichs stand „Start › Newsletter-Sync › …", und die mittlere Stufe war ein Verweis auf
/admin/newsletter— eine Adresse, die es nicht gibt. Der Code daneben sagte ausdrücklich das Gegenteil zu („der Präfix ist selbst keine Seite, die Krume verlinkt ihn deshalb nicht"); die Prüfung dahinter,Navigation::istAdresse(), löste den Platzhalter der Routeadmin/{flaeche}aber als „irgendein Segment" auf und ignorierte diewhere-Einschränkung, die genau diese Route trägt. Wer Platzhalter auflöst, muss auch die Bedingung auflösen, unter der sie gelten — sonst ist jede Adresse eine Adresse. - core: Die Anmeldeseite verweist auf die Nutzungsbedingungen statt auf eine 404-Seite. Unter dem Anmeldeknopf stand „Nutzungshinweise" und dahinter ein von Hand geschriebener Pfad, den keine Route kennt. Die erste Seite, die jeder Gast sieht, trug damit einen toten Verweis. Jetzt steht dort der Routenname: Ein falscher Name wirft beim Rendern, ein falscher Pfad schweigt.
- verwaltung: „Konto ansehen" führt in den Rollen-Bestätigungen wieder auf das Konto. Der Zeilenknopf zeigte auf
/admin/konten/{kennung}— die Adresse der abgelösten Fremdoberfläche. Dieselbe Stelle war in den Klärfällen längst nachgezogen und dort ausdrücklich kommentiert; hier ist sie beim Abbau liegen geblieben.
Was die Seiten sagten und was sie meinten
- digi: Drei Vorgangsflächen nennen den Vorgang wieder in der Überschrift. „Steuern:", „Nachricht zu:" und „Inhalt bearbeiten:" brachen nach dem Doppelpunkt ab. Die Ursache ist in allen drei Fällen dieselbe: Gelesen wurde
$vorgang->titel, die Spalte heisst abertitle— und Eloquent liefert für einen Namen, den es nicht gibt, wortlosnull. Die vierte Fläche derselben Familie, „Bewerten", stand daneben richtig. - digi: Der Statuswechsel meldet nur dann eine Benachrichtigung, wenn eine hinausging. „Der Status hat sich geändert — die einreichende Person wurde benachrichtigt" stand nach jedem Wechsel da. Ob wirklich eine Mail entsteht, entscheidet aber die Mail-Auswahl des Boards, und die darf leer sein. Wer sich auf die Meldung verliess, wartete auf eine Antwort zu Post, die es nie gab.
Benachrichtigungen::statuswechsel()gibt jetzt Auskunft darüber, ob es eingereiht hat; beide Aufrufer — Steuerungsfläche und Board — sagen, was wirklich passiert ist. Im Board ersetzt das das bisherige „sofern dieser Schritt dafür vorgesehen ist": ehrlich, aber unbestimmt, obwohl die Antwort vorlag. - akkreditierung: Die Einlassprüfung hat eine Hauptüberschrift. Sie war die einzige Seite des Portals ohne
h1. Am Bildschirm trägt das grosse Wort „Gültig" die Aussage — eine Vorlesehilfe springt aber über Überschriften und fand hier keine. Die Überschrift stehtnur-vorlesen; die Fläche sieht unverändert aus. Der Wächter „jede Modulseite beginnt mit dem Held" prüft jetzt den sichtbaren Fall: Eine Überschrift, die nur der Vorlesehilfe gilt, ist kein zweites Muster für den Seitenanfang, sondern der Ersatz für einen, den es hier bewusst nicht gibt.
Der Prüfstand selbst
- prüfstand: Die Detailflächen werden mit dem Parameter aufgerufen, den sie lesen.
JedeSeiteHatIhrenOrtTestrief sechs Flächen mit?nummer=beziehungsweise?konto=auf — Namen, die keine Fläche liest; überall heisst der Parameterkennung. Die Seiten antworteten trotzdem mit 200, nämlich in ihrem Leerzustand („Zu dieser Adresse gibt es keinen Vorgang"), und genau den hat der Fall dann geprüft. Deshalb konnte die abgebrochene Überschrift oben monatelang unter einer grünen Prüfung stehen. Ein Prüfstand, der die leere Fassung einer Seite ansieht, sagt über die volle nichts. - prüfstand:
/healthprüft seine Zusage statt seiner Umgebung. Der Fall bestand aus einem Aufruf und war nur deshalb grün, weil die Herzschlag-Datei des Cron auf einem Entwicklungsrechner meist gar nicht existiert — dann gilt „noch nie gelaufen" als in Ordnung. Wer einmalportal:cronvon Hand startete, hatte den Fall zehn Minuten später rot. Jetzt setzt der Fall das Lebenszeichen selbst und prüft beide Richtungen: frischer Lauf → 200, überfälliger Lauf → 500. - prüfstand: Ein neuer Fall hält die sechs Befunde oben fest (
GesamttestVonAussenTest) — jeder durch die Route, keiner am Dienst vorbei.
[2.19.0] — 2026-09-08
Ein vollständiger Funktionsabgleich des Altportals v1 (v0.108.0) gegen den Neubau — Route für Route, in fünf Bereichen: Kern und Konto, Verwaltung, Medienakkreditierung, Anliegen und Newsletter, Navigation und Oberfläche. Dazu die Übernahme aus den beiden Original-Altquellen.
Der Leitbefund ist derselbe wie bei der Abnahme: Der Dienst war gebaut, der Weg dorthin fehlte. Ein gutes Dutzend Klassen hatte außer dem eigenen Testfall keinen einzigen Aufrufer — sauber geschrieben, grün geprüft und im Portal nicht erreichbar. Ein Test, der den Dienst prüft, verdeckt den fehlenden Weg, statt ihn zu zeigen. Jede Reparatur dieser Runde hat deshalb einen Weg von der Oberfläche und einen Testfall, der durch diesen Weg geht.
Prüfstand: 2572 statt 2409 Tests, alle grün.
Kern und Konto
- core: Wer sein Konto sucht, findet es auch mit einer anderen Schreibweise. Anmeldung, „Passwort vergessen" und „Anmelde-Code verloren" suchten stur nach der eingetippten Adresse. Wer sich als
a.b@gmail.comangelegt hatte undab@gmail.comtippte, kam nicht hinein, bekam keine Zurücksetz-Mail und wurde bei einer Neuanmeldung als Dublette abgewiesen — eine Sackgasse, aus der nur der Hilfe-Kontakt herausführte. Alle drei Wege gehen jetzt überAuth\Kontosuche, dieselbe Regel, die die Registrierung längst anwandte. Die exakte Adresse gewinnt dabei immer, und eine Schreibweise, die kanonisch auf mehrere Konten passt, findet keines — sonst könnte ein Rateweg dafür sorgen, dass die Anmeldebremse oder die Zurücksetz-Mail ein fremdes Konto trifft. - core: „Passwort vergessen" hat drei Ausgänge statt einem. Ein Konto, das sich über die Organisation anmeldet, bekam einen Zurücksetz-Verweis — der ihm nicht half und ihm einen zweiten Zugangsweg in die Tabelle geschrieben hätte; jetzt steht dort der Hinweis, wo sein Passwort liegt. Eine bestätigte, nie fertig gestellte Registrierung bekommt den Wiedereinstieg statt eines Verweises auf ein Passwort, das es nicht gibt. Die Antwort auf der Seite bleibt in allen Fällen dieselbe.
- core: Ein geretteter Formularentwurf kommt jetzt auch zurück. Er wurde gespeichert, lief nach einem Tag ab und erreichte niemanden: Die Middleware schrieb den Schlüssel ohne führenden Schrägstrich, alle lesenden Stellen erwarteten ihn mit — zwei Schreibweisen derselben Kennung, kein Fehler, Tests grün. Dazu drei fehlende Wege: Die Rettung greift jetzt beim Sitzungsablauf (dort ist die Person noch bekannt; an der bisherigen Stelle ist sie es gerade nicht mehr), die Anmeldung springt zum Formular zurück, und Stammdaten wie E-Mail-Änderung füllen die Felder wieder aus. Ein Rücksprung geht nur auf Pfade, die sich auch anzeigen lassen. Gerettet wird ausschliesslich auf den Kernwegen (Registrierung, Profil, Stammdaten, E-Mail-Änderung): In der Verwaltung stehen in den Formularen die Daten anderer Personen, und die gehören nicht einen Tag lang in einen Entwurfsspeicher.
- core: Eine Passwortänderung meldet sich an die hinterlegte Adresse. Weder der Zurücksetz-Verweis noch das Formular im Profil schickten etwas. Das ist die einzige Meldung, an der jemand merkt, dass ein Fremder sein Konto übernommen hat — und der Grund, warum ein Zurücksetz-Verweis per Mail überhaupt tragbar ist. Ohne sie wäre die Übernahme am unbeaufsichtigten Bildschirm spurlos.
- core: Nach einem Notfall-Code führt der Weg in die Neu-Einrichtung. Bisher landete man auf der Startseite und behielt einen zweiten Faktor, den man nicht mehr erzeugen kann — bei jeder Anmeldung wurde der nächste Code verbraucht, bis keiner mehr da war und das Konto zu. Ein Notfall-Code bedeutet fast immer einen Gerätewechsel; das Portal sagt das jetzt und führt hin. Dazu die Mail „Anmeldung mit Notfall-Code" mit Restzahl: Auf dem Bildschirm steht die Warnung sonst vor dem Falschen.
- core: Der Abbruch einer Anmelde-Code-Zurücksetzung bestätigt sich per Mail. Bisher stand die Bestätigung nur auf dem Bildschirm — und der Abbruchverweis wird gerade von einem fremden Gerät aus angeklickt. Die Mail ist der Beleg für den Kontoinhaber, dass sein Konto unverändert ist.
- core: Kein Zwischenspeichern auf Seiten mit einem Verweis im Pfad. Die Passwort-Landeseite und die Entsperr-Seite gaben ihre Ansicht ohne
Cache-Control: no-storezurück — als einzige unter allen Token-Landeseiten. Der Verweis steht im Pfad; ohne die Kopfzeile liegt er im Zwischenspeicher und im Verlauf, und auf einem geteilten Rechner reicht danach der Zurück-Knopf. Der Test prüft die Regel jetzt als Schleife über alle solchen Seiten. - core: Die bebilderte Anleitung zum Anmelde-Code ist öffentlich und dreifach verlinkt. Sie stand in der Gruppe für angemeldete Seiten — nicht aus einem Grund, sondern weil sie zwischen den übrigen Code-Routen lag; der Ort in der Datei hatte die Zugriffsregel bestimmt. Gebraucht wird sie von jemandem, der gerade nicht angemeldet ist: in der Code-Abfrage.
- core: Auch die erfolgreiche Verknüpfung mit der Mitgliederverwaltung meldet sich. Das Lösen einer Verbindung schickte seit jeher eine Mail, das Verbinden nicht — eine Asymmetrie ohne Grund. Die Mail nennt keine Trefferdetails: Sie geht an eine Adresse, von der wir gerade erst erfahren haben, dass sie zu diesem Eintrag gehört.
- core: Die Selbstprüfung warnt vor dem Ablauf des Anmeldeschlüssels. Ein abgelaufener Schlüssel legt zwei Dinge gleichzeitig still, die nichts miteinander zu tun zu haben scheinen: die interne Anmeldung und den Mailversand. Wer beides ausfallen sieht, sucht zuerst überall sonst. Ohne hinterlegtes Ablaufdatum (
ENTRA_CLIENT_SECRET_ABLAUF) wird gewarnt statt geschwiegen.
Navigation und Oberfläche
- core: Aus jedem Verwaltungsformular führt wieder ein Weg zurück. Rund 25 Detailflächen zeigten nur „Start › Konto" — die Listenebene fehlte, und der einzige Rückweg war der Browser-Knopf. Ursache: Ihre Adressen sind Geschwister ihrer Listen, keine Unterpfade, und die Suche nach dem Bereich fand deshalb nie etwas. Jede Fläche nennt jetzt ihre Liste (
elternflaeche()); daraus entstehen die Zwischenstufen des Pfads und der aktive Menüpunkt. Eine Angabe, zwei Wirkungen — und keine zweite Stelle, an der sie auseinanderlaufen kann. - core: Öffentliche Seiten führen nicht mehr in die Anmeldung zurück. Der Navigationspfad begann überall mit „Start" — auch auf dem Akkreditierungsantrag, den Newsletter-Formularen und den Rechtstexten. „Start" liegt hinter der Anmeldung: Eine Journalistin, die den Antrag ausfüllte, sah einen Weg zurück, der sie auf die Anmeldeseite warf. Ohne Konto gibt es jetzt keinen Pfad.
- core: Jede Seite sagt jetzt, wo sie ist. Fünf angemeldete Seiten trugen die volle Oberfläche und keinen Navigationspfad — die Zwei-Faktor-Strecke und die Bestätigung der neuen E-Mail-Adresse. Gemerkt hat es niemand: Eine nicht gesetzte Variable war ein lautloses Nichts. Ein View-Composer trägt den Pfad jetzt nach, wenn eine Seite keinen mitbringt — die Krume ist die Vorgabe, ihr Fehlen die Ausnahme. Dazu sind die drei letzten von Hand geschriebenen Krumen auf
Navigation::krume()umgestellt: Es gibt genau einen Weg, einen Pfad zu setzen, und erst das lässt den Composer überhaupt greifen. - core: In der Bereichsliste ist immer genau ein Punkt der aktuelle. Auf „Rollen-Bestätigungen" leuchteten zwei Menüpunkte gleichzeitig (eine Vorlesehilfe sagte zweimal „aktuelle Seite"), auf allen Detailformularen keiner — die Ortsangabe fehlte genau dort, wo man sie am dringendsten braucht. Verglichen wurde ein Adressanfang ohne Trennzeichen, und zwar in jeder Vorlage neu. Die Antwort kommt jetzt aus der Navigation: der genaueste Treffer gewinnt, und wenn keiner passt, entscheidet der Navigationspfad. Auch Profil, Postfach und Konto-Sicherheit sind jetzt markiert.
- core: „Kein Zugriff" ist keine Sackgasse mehr. 403, 404 und 419 waren eigenständige HTML-Seiten ohne Menü, mit genau einem Knopf: „Zur Startseite". Der häufigste Fall einer 403 ist aber ein Menüpunkt, den man sehen, aber nicht betreten darf — wer dort landet, will zurück in seinen Bereich und nicht an den Anfang. Diese drei tragen jetzt Kopf- und Bereichsleiste (bzw. den Gast-Kopf). 500 und 503 bleiben bewusst ohne: Dort kann die Datenbank der Grund sein, und eine Fehlerseite, die am Fehler scheitert, zeigt gar nichts.
- core: Die Anleitung am Einlass ist wieder sichtbar. Den Erklärkasten gab es zweimal — im Baukasten und noch einmal in den Modulen, mit gegensätzlicher Regel für Gäste. Die Kern-Fassung blendete Gäste aus, „auf öffentlichen Seiten gibt es nichts zu erklären". Zwei Seiten widerlegen das: die Bedienanleitung für die Wettkampfleitung, die per Link und ohne Konto am Einlass arbeitet, und der Kasten auf „Anmelde-Code verloren". Beide standen im Quelltext und erschienen nie — geschrieben genau für Menschen ohne Konto, unsichtbar genau für sie. Jetzt ein Baustein, eine Regel: Wer nichts abschalten kann, bekommt die Erklärung.
- core: Jede Modulseite beginnt gleich. Es gab drei Muster für denselben Anfang — den Held des Baukastens auf zwei Seiten, eine eigene Modul-Kopfzeile auf zwei weiteren, und auf allen übrigen ein nacktes
<h1>. Das Modulbild ist im Held aufgegangen (modul="…"), und wo kein Bild liegt, entsteht ein Emblem aus den Initialen. Eine tote Vorlage (views/start.blade.php) ist entfernt — sonst wird beim nächsten Umbau die falsche Datei bearbeitet. - core:
JedeSeiteHatIhrenOrtTestbewacht das dauerhaft — über die Routentabelle statt über eine Liste von Hand, je Seite als Gast und als breitestes mögliches Konto. Was neu dazukommt, ist automatisch dabei; eine parametrisierte Route ohne Fixture ist ein eigener Befund und fällt nicht stillschweigend aus der Prüfung.
Verwaltung
- verwaltung: Antworten aus dem Portal erreichen jetzt jemanden. Die Verwaltung konnte schreiben, die Person antworten — und die Antwort las niemand: keine Fläche, keine Zahl, kein Hinweis. Neu die Liste „Nachrichten" mit dem Stand „wartet auf Antwort", die Fläche „Unterhaltung" mit Verlauf und Antwortfeld, ein Weg vom Datenblatt des Kontos und eine Zeile auf der Startfläche. Die Antwort geht ins Portal und als Mail hinaus, mit dem Team-Postfach als Antwortadresse. Ein Kanal, den man nur in eine Richtung bedienen kann, ist schlimmer als keiner — er lädt dazu ein, ihn zu benutzen.
- verwaltung: Unbeantwortete Nachrichten leuchten am Menüpunkt. Die Zahl stand zuerst nur auf der Startfläche der Verwaltung — dort findet sie, wer ohnehin hinsieht, und wer ohnehin hinsieht, braucht sie nicht. Sie kommt jetzt über
Arbeitsliste::kennzeichen()aus der Fläche selbst; jede Arbeitsfläche kann so eine Zahl tragen, damit die nächste nicht wieder an zwei Stellen gepflegt wird. Gezählt wird dafür gezählt und nicht geladen — und nur dort, wo die Zahl auch erscheint: Fehlerseiten tragen die Leiste ohne Kennzeichen, sonst zählte jede 404 den ganzen Nachrichtenbestand mit. - verwaltung: Den täglichen Bericht über offene Freigaben gibt es wirklich. Die Einstellung „Postfach des Prüfteams" gab es von Anfang an, und die Selbstprüfung sagte den Bericht ausdrücklich zu — der Job dazu fehlte. Ohne ihn bleiben Konten liegen, solange niemand ins Portal sieht. Er geht höchstens einmal am Tag und nur, wenn es offene Fälle gibt; die Wiederholsperre ist sein eigener Eintrag in der Prüfspur, denn eine zweite Merkspalte daneben liefe auseinander.
- verwaltung: Angefangene Registrierungen verschwinden nicht mehr kommentarlos. Der Löschjob war da, die Erinnerung davor nicht — wer seine Adresse bestätigt hatte, fand Wochen später weder Konto noch Hinweis. Die Erinnerung geht sieben Tage vor der Löschung raus, mit Fortsetzungslink und genau einmal je Vorgang. Der Stichtag rechnet sich aus der Frist, statt fest im Code zu stehen: Sonst käme er nach der ersten Friständerung zu spät.
- verwaltung: Mit der Referenten-Rolle kommen die Stammdaten mit. Der Dienst dafür war gebaut und hatte keinen einzigen Aufrufer — der Leitbefund dieser Runde, eine Ebene tiefer. Gefüllt werden nur leere Felder. Dazu der ausdrückliche Knopf „Stammdaten neu holen", der auch belegte Felder ersetzt — nie aber bestätigte: Die Bestätigung ist ein Nachweis mit Zeit und Adresse.
- verwaltung: Mit der Rolle „Referent" fällt auch die Verknüpfung zur Mitgliederverwaltung. Bisher blieb die Kennung stehen und zog bei jedem späteren Abgleich weiter Fremddaten an ein Konto, das die Rolle gar nicht mehr hat. Die übernommenen Angaben bleiben — sie gehören inzwischen der Person.
- verwaltung: Der Notzugang lässt sich nicht mehr aussperren. Seine Admin-Rolle steht in der Konfiguration und nicht in der Rollentabelle — folglich zählte der Letzter-Admin-Schutz ihn nicht mit und schützte ihn nicht. Ein Verwaltungskonto konnte den Weg zurück zumauern; danach half nur noch die Datenbank.
- verwaltung: Ein Wächter statt vier. Eigenes Konto, Notzugang und letzte Verwaltung wurden an vier Stellen in vier eigenen Formulierungen geprüft. Zwei Wächter über derselben Regel sind einer zu viel, sobald sie Verschiedenes sagen; jetzt antwortet der Fachdienst allen Wegen — Sperren, Deaktivieren, Löschen und der Sammelaktion.
- verwaltung: „Fehlende Angaben nachfragen" geht nur einmal. Der Vermerk am Abgleich wurde gesetzt und nie gelesen — dieselbe Person ließ sich beliebig oft mit derselben Bitte anschreiben. Jetzt sagt die Meldung, wann schon gefragt wurde, und verweist auf die Rückfrage im Wortlaut.
- verwaltung: Fünf Einstellungen, die niemand einstellen konnte. Spamschutz (Mindestdauer, Versuche je Stunde), der Selbstservice für den Anmelde-Code samt Wartefrist und die Domänen der internen Anmeldung wurden zur Laufzeit gelesen und standen in keinem Formular. Besonders der Selbstservice ist ein Notschalter: Er soll sich ohne Auslieferung umlegen lassen. Die Domänen werden beim Speichern normalisiert — „ BTV.de" hätte „…@btv.de" nie getroffen, und das sieht man am Feld nicht.
- verwaltung: Geburtsdatum und Land lassen sich berichtigen. Ein Zahlendreher im Geburtsdatum blockiert den Abgleich mit der Mitgliederverwaltung — genau der Fall, für den es diesen Weg gibt, und ausgerechnet das Feld fehlte.
- verwaltung: Wer in den Bestand der Mitgliederverwaltung sieht, hinterlässt eine Spur. Auch ohne Klardaten führt er Merkmale von Personen, die vom Portal nichts wissen. Protokolliert werden Größe des Bestands und ob gesucht wurde — nie das Suchwort.
- verwaltung: Deaktivieren geht nur noch mit Grund. Die Direktaktion am Datenblatt erhob keinen; je nach Weg stand danach im Konto etwas oder nichts, obwohl der Sperrgrund genau das ist, was die betroffene Person später erfragt. Sie entfällt; Deaktivieren läuft über den Reiter „Zugang". Übrig bleibt „Entsperren", das nichts wegnimmt.
- verwaltung: Die Adressen des Vorgängersystems führen weiter. Zehn Pfade, die in Anleitungen, Lesezeichen und älteren Mails stehen, antworteten mit 404 — das sieht aus, als sei die Funktion weg. Jetzt 301 auf das jeweilige Gegenstück, ohne Anmeldepflicht: Die Anmeldung gehört an die Zieladresse, sonst landet man nach dem Anmelden auf der Startseite statt am gesuchten Ort.
Medienakkreditierung
- akkreditierung: Der Nachreichen-Link wird jetzt ausgestellt. Die Rückfrage-Vorlage erzeugt ihn beim Öffnen, wenn keiner gilt — vorher ging die Rückfrage-Mail mit einer leeren Zeile hinaus, und die ganze öffentliche Strecke „Unterlagen nachreichen" war von außen unerreichbar. Ausgestellt wird beim Öffnen und nicht beim Absenden: Sonst gäbe die absendende Person einen Text frei, den sie nie gesehen hat. Ein noch gültiger Link bleibt stehen, damit die Mail von gestern nicht entwertet wird.
- akkreditierung: Nachgereichte Unterlagen melden sich. Sie schreiben einen Verlaufseintrag und eine Info an den Fachbereich — vorher lagen sie in der Ablage, der Antrag stand weiter auf „Rückfrage offen", und niemand erfuhr, dass die Antwort da war. Der Text ist unter „Textbausteine" pflegbar.
- akkreditierung: Nach dem Nachreichen steht eine eigene Seite da. Vorher landete man auf der Dankeseite der Antragstellung — Titel „Antrag eingegangen", darunter ein Absatz über eine Antragsnummer, die dort leer war. Die neue Seite nennt die bestehende Nummer und sagt ausdrücklich, dass das noch keine Zusage ist.
- akkreditierung: Nach einem Statuswechsel steht die passende Nachricht am Kopf des Antrags. Für Rückfrage, Ablehnung und Widerruf musste man bisher „Nachricht schreiben" öffnen und die Vorlage selbst suchen; die Zuordnung gab es längst und las niemand.
- akkreditierung: Die Ausweis-Mail hängt den Ausweis an und hält den Versand fest. Vorher versprach sie „anbei" und schickte nichts, und die Übersicht der Wettkampfleitung sagte danach „vor Ort ausgeben" statt „vorab per Mail". Ohne fertigen Ausweis geht sie gar nicht mehr hinaus.
- akkreditierung: „Zugang an die Ansprechperson mailen" vermerkt die Anträge als „Wettkampfleitung informiert" — nur die mit Zutritt. Das Häkchen ließ sich bisher nur von Hand je Antrag setzen und blieb in der Praxis leer; die Ausfuhrspalte dazu war eine Spalte ohne Auskunft.
- akkreditierung: Der öffentliche Bestätigungs-Endpunkt der Wettkampfleitung hat eine Bremse — 120 je Anschluss und Stunde, über den Spamschutz des Kerns. Wer den Schlüssel hatte, konnte vorher unbegrenzt schreiben.
- akkreditierung: Die beiden Löschfristen des Moduls stehen im Reiter „Aufbewahrung" und lassen sich dort pflegen. Zwei Läufe löschten Nachweise und ganze Anträge nach Zahlen, die in keiner Fläche standen — eine Frist, die niemand nachsehen kann, ist keine Entscheidung, sondern eine Überraschung.
- akkreditierung: Vier Kennzahlen werden wieder gezählt — eingegangene Anträge, vor Ort erfasste Anträge, verschickte Nachrichten je Art und die Info an die Wettkampfleitung.
Anliegen
- digi: Lesezeichen aus dem Altportal führen wieder irgendwohin. Die Umrechnung der alten Adressen (
/anfrage/424242,/it-board/…) war fertig gebaut und getestet — aufgerufen hat sie niemand außer dem Testlauf. Jeder Verweis aus einer alten Mail, aus Besprechungsnotizen und aus den Lesezeichen des Teams lief ins Leere. JetztGET /digi/alt/{pfad}/{nummer}. Zweiter Teil desselben Fehlers: Die Board-Pfade zeigten auf/digi/vorgang/…, eine Adresse, die es seit der Filament-Ablösung nicht mehr gibt — selbst mit Route wäre die Hälfte auf 404 gelandet. Der Testfall dazu prüfte die Zeichenkette und nicht die Erreichbarkeit und hat den falschen Zustand zementiert. - digi: Die Rolle „Anliegen — Bearbeitung" kann wieder bearbeiten. Steuerung, Inhalt, Nachricht ans Team, internes Erfassen und der Prozessschritt in der Zeile verlangten
digi.verwalten— obwohl der Rechtekatalog des Modulsdigi.bearbeitenausdrücklich als „Boards sichten und steuern" beschreibt und die mitgelieferte Rolle genau dieses Recht trägt. Sie sah die Boards und konnte nichts tun. Ein Text, der etwas anderes zusagt als der Code tut, ist schlimmer als ein fehlender Text; der Code richtet sich nach der Konfiguration und nicht umgekehrt. Löschen bleibt als einzige Aktion beim Verwaltungsrecht: Es ist die einzige, die einen Vorgang aus der Welt nimmt. - digi: Die Planungsflächen prüfen die Board-Freigabe, bevor sie schreiben. Bewerten, Rang, Sprintzuordnung und Arbeitsstand verlangten nur das Fachrecht. Eine Person, deren Freigabe allein „IT" nennt, konnte Digitalisierungs-Vorgänge bewerten, umsortieren, einem Sprint zuordnen und ihre Arbeitsstufe setzen. Im Altportal prüfte jeder dieser Handler die Freigabe. Zusätzlich schneidet die Planungsliste jetzt auf die freigegebenen Boards — sehen ist breit, schreiben ist eng.
- digi: Kein 403 mehr auf den eigenen Menüpunkt. Der Elternpunkt der Seitenleiste zeigt auf
/digi. Ein Konto mit Board-Recht, aber ohnedigi.einreichenbekam dort eine verschlossene Tür, obwohl das Portal selbst dorthin geführt hat. Jetzt führt der Einstieg ins Board — bei genau einem freigegebenen Board direkt hinein. Wer einreichen darf, sieht weiterhin die Einreichen-Seite.
Newsletter
- newsletter: Die Katalogspalte „Herkunft" zeigte für jede Zeile „Array".
Herkunft::bestimmen()liefert{art, text, link}; die Liste castete das nach String. Folge: Die Spalte war wertlos, die Marke fiel immer auf dieselbe Farbe, und der Filter darüber traf nie — seine fünf deutschen Wörter gibt der Dienst gar nicht zurück. Gefiltert wird jetzt auf die Art, angezeigt der Satz, denHerkunftdazu geschrieben hat („Abgleich · Übungsleitungen"). - newsletter: Zwei Verweise aus dem Katalog endeten auf 404. Sie hießen
/admin/newsletter/verbindungenund/admin/newsletter/formulare; die Verwaltungsroute kennt nur einsegmentige Flächenschlüssel. Aufgefallen ist es nie, weil der Verweis hinter der kaputten Spalte lag — ein toter Verweis hinter einem toten Feld. - newsletter: Die Herkunft eines Kennzeichens lässt sich wieder von Hand vermerken. Der Dienst war fertig und getestet, aufgerufen hat ihn nur der Testlauf. Damit war der Zweck der Katalogfläche halbiert: Ein herrenloses Kennzeichen ließ sich finden, aber nicht als geklärt markieren — und stand beim nächsten Aufruf wieder da. Neue Fläche
newsletter-herkunft, erreichbar über einen Knopf in der Zeile. - newsletter: Herrenlose Kennzeichen stehen jetzt im Katalog. Die Rechnung dafür gab es von Anfang an — die Klassendoku nennt diesen Block selbst „die eigentlich interessante Fundstelle": Jemand wird danach sortiert, und niemand weiß mehr, wonach. Die Liste verwendete nur den anderen Zweig der Antwort.
- newsletter: Der Katalog sagt, ob der Abgleich ein Segment überhaupt erreicht. Die Erreichbarkeitsstufe wurde bei jedem Lesevorgang gerechnet und stand nirgends. Genau der Fall, den sie beschreibt — „das Segment bricht unbemerkt weg, sobald jemand zwei Lizenzen hat" —, blieb damit unsichtbar, bis ein Newsletter an niemanden geht.
- newsletter: Vorschau auf die Quelle, bevor zum ersten Mal in einen fremden Verteiler geschrieben wird. Der Probelauf liefert nur Summen — „0 Empfänger" und „die Gegenstelle antwortet nicht" sehen darin gleich aus. Die neue Fläche zeigt die ersten zwanzig Datensätze, so wie der Abgleich sie liest, und markiert die ohne Adresse. Kein Export: Es sind Adressen, sie sollen nirgends liegen bleiben.
- newsletter: Der Zeitplan „Wöchentlich" läuft jetzt auch. Er war im Verbindungsformular wählbar und in der Liste beschriftet, und die Fälligkeit kannte nur „täglich": Eine aktive Verbindung mit diesem Zeitplan wurde nie abgeglichen, ohne dass irgendwo etwas gemeldet hätte. Der Testfall dazu führte „wöchentlich" ausdrücklich als Beispiel eines unbekannten Zeitplans.
- newsletter:
newsletter-katalogundnewsletter-auskunfthaben eigene HTTP-Tests. Der generische Rundlauf ruft jede Fläche auf, aber mit leerer Datenlage — der Katalog baute dabei keine einzige Zeile. Eine Fläche, die nur leer geprüft wird, ist nicht geprüft.
Übernahme aus den Original-Altquellen
- core:
portal:altquelle {digi|akkreditierung|alle}liest direkt die Originalquellen — das Digitalisierungsportal und das Presseportal — statt den Umweg über das v1-Portal zu gehen. Der Umweg hätte gereicht, wenn man sich darauf verlassen könnte, dass der damalige Import nichts ausgelassen hat. Kann man nicht: Was jener Import übersehen hat, ist über ihn nie wieder erreichbar, und eine unvollständige Übernahme sieht genauso aus wie eine vollständige.--probelaufliest und rechnet, ohne zu schreiben;--quelle=nimmt einen eingespielten Abzug,--dateien=das Anhangverzeichnis. Die ganze Beschreibung steht indocs/ALTQUELLEN-IMPORT.md. - core: Ein Abgleich, kein Import. Wiedererkannt wird über eine eigene Zuordnungstabelle (
altquelle_zuordnung), die allein der Übernahme gehört und sich nach dem letzten Lauf wegwerfen lässt. Steht dort nichts, schließt der Lauf an vorhandene Legacy-Kennungen und fachliche Schlüssel an — beide Wege dürfen nebeneinander laufen, ohne dass etwas doppelt entsteht. Was im Ziel gelöscht wurde, kommt nicht zurück: Der Bericht meldet den Fall und legt nichts an. Und es entsteht kein Rumpfkonto ohne Treffer — der SSO-Login verwirft unbestätigte Rümpfe und legt ein frisches Konto an; die Verknüpfung zeigte danach ins Leere. - core: Übernommene Mails stehen nie als
queued. Diemailsdes Neubaus ist eine Outbox — was dort mitqueuedsteht, verschickt der Cron-Worker. Jahre alte Bestätigungen gingen sonst erneut hinaus, ausgelöst von einem Abgleich, den jemand „nur zum Ansehen" gestartet hat. Was nie hinausging, wird als Fehler geführt und nicht als gesendet: Das wäre eine Behauptung über etwas, das nicht stattgefunden hat. - akkreditierung: Ausweis-PDFs kommen nicht mit, sie werden neu erzeugt. Die alten tragen Layout und Prüf-Link des Presseportals, dessen QR-Code nach der Abschaltung ins Leere zeigt. Der Erstellungsstand kommt mit, damit der Fachbereich sieht, wo er steht. Anträge über der Aufbewahrungsfrist werden gar nicht erst angelegt — sonst schriebe die Übernahme Namen, Adressen und Telefonnummern in eine Tabelle, aus der der nächste Cron-Lauf sie wieder entfernt.
- digi: Was das Portal nicht kennt, geht sichtbar verloren statt still. Die Planner-Felder wandern in die internen Notizen, ein unbekannter Status wird in der Statusliste des Zweigs ergänzt (sonst fiele der Vorgang beim nächsten Speichern lautlos zurück), und jede fehlende Datei ist ein Befund im Bericht und kein Abbruch. Die Befunde werden nicht gekürzt — ein Lauf, der hundert Hinweise auf drei zusammenfasst, verschweigt siebenundneunzig.
Zwei Tests, die selbst kaputt waren
D2NewsletterTesttrug ein festes Datum — eine Zeitbombe, die an einem bestimmten Tag rot geworden wäre, ohne dass sich am Code etwas geändert hätte. Ein Testlauf, der vom Kalender abhängt, sagt am Tag des Ausfalls nichts über die Software.P4VerwaltungsjobsTestschrieb das Cron-Lebenszeichen in den Betriebspfad. Die Datei überlebte den Testlauf, und beim nächsten Lauf war ihr Zeitstempel überfällig —/healthantwortete mit 500, obwohl nichts kaputt war. Sie liegt jetzt wie in den übrigen Cron-Fällen in einer Wegwerfdatei.
Bewusst nicht in dieser Runde
Entscheidungen, keine Restposten:
MailAdresseundEmailAdressebleiben nebeneinander. Sie zusammenzulegen hieße, Registrierung, E-Mail-Änderung und Dublettenprüfung gleichzeitig anzufassen;Auth\Kontosuchebindet sie an der einen Stelle zusammen, an der es zählt.- Der Registrierungs-Entwurf wird weiterhin nicht vorbefüllt. Anzeigeort und Absendeort des Formulars müssten dafür getrennt geführt werden — das gehört in eine Runde an der Registrierungsstrecke.
- Kein Datei-Upload bei der Vor-Ort-Erfassung. Ein Handyfoto vom Presseausweis am Tisch ist eine Ausweiskopie: Sie läge danach in der Ablage, müsste in die Löschläufe und belegt nichts, was der Name der prüfenden Person nicht besser belegt. Wer eine Datei hat, reicht sie über den Nachreichen-Link nach — den gibt es jetzt wieder.
- Die Namenssuche im Bestand der Mitgliederverwaltung kommt nicht zurück. Die v1-Fläche zeigte Klarnamen Dritter; die neue zeigt Kennungen, Quellen und Zeitpunkte. Die Absenkung des Rechts auf
system.viewist indocs/ENTSCHEIDUNGEN.mdbegründet und durch die neue Prüfspur ausgeglichen. - Die WL-Mail bleibt eine Ein-Klick-Aktion statt eines Editors für Empfänger, Betreff und Text wie in v1; der Wortlaut ist über die Textbausteine pflegbar (2.10.0).
aria-current="page"bleibt an drei Stellen erlaubt — Menüpunkt, Krumenspitze und offener Reiter beantworten verschiedene Fragen. Eindeutig sein muss nur „welcher Menüpunkt ist meiner"; dort zählt der Test.- Kein Modul-Beitrag zum Kennzahlen-Katalog. Ein Modul, das sich einzeln in den Kernkatalog schreibt, wäre die erste Hälfte einer Lösung; die richtige ist ein Vertrag dafür, und das ist eine Kernänderung.
- Ein Pflichtfeld, das ein Leerzeichen annimmt („Identität geprüft"), bleibt stehen: Eine Mindestlänge ist eine fachliche Festlegung, keine Reparatur.
- Der Weg zur Übernahme aus dem Digitalisierungsportal in der Oberfläche wartet auf die Entscheidung über die Abschaltung des Altportals. Der Befehl ist da; ein Knopf dafür setzt einen Termin voraus, den es noch nicht gibt.
[2.18.0] — 2026-08-06
Nachbesserung zu 2.17.0. Dort liefen die Felder über flex-wrap — sie füllten die Zeile, wie es gerade passte. Das Ergebnis war an drei Stellen schlechter als vorher, und alle drei haben dieselbe Ursache: Fließen ist keine Anordnung.
- core: Nur was fachlich zusammengehört, steht nebeneinander. Vier Felder standen in einer Reihe, die miteinander nichts zu tun haben — „Vorname" neben „Redaktion, Agentur oder Verein", und das nächste Feld je nach Fensterbreite woanders. Jetzt ausdrücklich gesetzte Reihen (
.feldreihe-2,-3,-schmal-breit); im Gerüst gruppiert'zusammen' => 'name'. Ein Formular ist keine Bildergalerie. - core: Die Eingabefelder einer Reihe liegen auf einer Linie. Sie versetzten sich um genau die Höhe des Hilfetexts: Ein Feld mit Erklärung beginnt tiefer als eines ohne.
subgridgibt allen Feldern einer Reihe dieselben Zeilen für Beschriftung, Hilfe, Bedienelement und Fehler. - core: Alle Bedienelemente sind gleich hoch. Ein Auswahlfeld war sichtbar flacher als das Textfeld daneben — der Browser rechnet bei
selectandere Innenabstände. Dazu ein eigener Auswahlpfeil aus der Marke: Der Systempfeil ist je nach Betriebssystem verschieden groß und sitzt verschieden weit innen. - core: Kästchen sind ankreuzbare Flächen, keine Liste nackter Häkchen. Die ganze Fläche ist das Ziel (WCAG 2.5.5) statt des winzigen Punkts, und die Auswahl zeigt sich an Rahmen und Fläche — nie an der Farbe allein.
- Ein
fieldsetnimmt immer die ganze Reihe. Der Kästchensatz „Welche Systeme sind betroffen?" landete rechts neben dem Suchfeld, das ihn filtert, und ließ eine halbe Karte leer; die Linkgruppe „Weiterführende Links" ebenso. Beides gehört unter das Feld, zu dem es gehört.
[2.17.0] — 2026-08-06
- core:
input[type="url"]sah aus wie kaputt — und war es fast. Die Feldstile standen als Aufzählung der Arten da:text,email,password,date,tel,number,search. Was fehlte, blieb ungestaltet — undurlfehlte. Im Anliegen-Formular standen deshalb neben ordentlichen Feldern zwei winzige graue Kästchen in Browser-Vorgabe, keine 150 Pixel breit. Jetzt eine Ausschlussliste: Ausgenommen sind nur die Arten, die gar keine Textfelder sind. Eine Aufzählung ist hier die falsche Form — es kommen laufend Arten dazu, und jede vergessene sieht nicht falsch aus, sondern kaputt. - core: Ein Feld ist so breit wie das, was hineingehört. Vorher war jedes Feld 100 % breit — auf einem 1600-Pixel-Schirm bekam „Vorname" dieselben 1400 Pixel wie eine mehrzeilige Beschreibung. Das ist nicht nur verschwenderisch: Die Feldbreite ist der stärkste Hinweis darauf, wie viel erwartet wird, und ein riesiges Feld für „PLZ" führt in die Irre.
In einer .feldreihe stehen kurze Felder jetzt nebeneinander und rutschen auf schmalen Geräten von selbst untereinander — über flex-basis, ohne einen einzigen Media Query. Die Breite leitet Feldbreite::fuer() aus Feldart und Feldname ab; ein Formular kann sie mit 'breite' => 'kurz' übersteuern. Abgeleitet und nicht in vierzig Formularen eingetragen: Der umgekehrte Weg wäre einmal viel Arbeit und danach eine Quelle für Uneinheitlichkeit, weil die nächste Fläche wieder rät.
- Kästchenlisten stehen in Spalten. Untereinander gestapelt nahm eine Liste mit zwölf kurzen Möglichkeiten zwölf Zeilen ein und schob alles Folgende aus dem Bild. Lange Beschriftungen — etwa die Kandidaten einer mehrdeutigen Zuordnung — behalten die ganze Zeile: In einer schmalen Spalte bräche jede über vier Zeilen um und die unterscheidende Angabe stünde ganz unten.
- Eine Zeile je Link statt fünf. In „Weiterführende Links" standen Beschriftung, Adresse und zwei Wortknöpfe untereinander — drei Linkzeilen füllten einen ganzen Bildschirm für sechs Angaben. Die Knöpfe tragen jetzt Pfeile; ihr Text bleibt für die Vorlesehilfe stehen und war ohnehin die einzige Auskunft, die zählt.
[2.16.1] — 2026-08-06
- core: Ohne Fachbereiche ist die Seite nicht mehr 250 Pixel breit. Das Raster der Arbeitsfläche steht auf zwei Spalten — 250 Pixel Leiste, Rest Inhalt. Wer keine Fachbereiche sieht, bekommt keine Leiste; das Raster blieb aber zweispaltig, und der Inhalt rutschte als erstes Kind in die schmale Spalte. Die ganze Seite stand als 250-Pixel-Streifen neben einer riesigen leeren Fläche.
Aufgefallen ist es in der Sicht „Ehrenamt", und dort trifft es am härtesten: Konten ohne Fachbereiche sind neue Konten — für sie ist genau das der erste Eindruck des Portals.
Die Vorlage entscheidet jetzt (rumpf-mit-leiste) statt eines :has() im Stylesheet: Das Ergebnis ist in jedem Browser dasselbe, und die Vorlage weiß es ohnehin. Die Bereiche werden dabei einmal geholt und durchgereicht statt zweimal je Seitenaufruf abgefragt.
[2.16.0] — 2026-08-05
- core: Ein Fangnetz für Erprobungsumgebungen —
PORTAL_MAIL_NUR_AN. Steht dort etwas, bekommt nur diese Adressen (oder ganze Domains als@beispiel.de) echte Post; alles andere landet vollständig nachlesbar in der Ablage des Modussimulate. Leer — und so im Betrieb — ändert sich nichts.
Der Anlass ist die dev-Instanz mit echtem Versandweg: Sie verschickt mit denselben Zugangsdaten und damit unter demselben Absender wie das echte Portal, und dort liegen übernommene Konten mit echten Adressen. Eine Mail von dev ist für den Empfänger von einer echten nicht zu unterscheiden — ohne diese Liste schickt eine einzige unbedachte Aktion („Erinnerung an alle überfälligen Anträge") echte Post an echte Menschen aus einer Umgebung, in der gerade jemand etwas ausprobiert.
Umgeleitet, nicht verworfen: Eine still fallengelassene Mail wäre die schlechteste Variante — im Protokoll stünde „gesendet", und niemand käme je an den Text. Die Prüfung sitzt in Versand::senden(), dem einen Punkt, durch den jede Nachricht geht.
[2.15.1] — 2026-08-05
- core: Ein Profilbild-Eintrag ohne Datei zeigt jetzt die Initialen statt eines kaputten Bildes. Bei der Übernahme aus dem Altsystem kam
profiles.avatar_extmit, die Bilddateien nicht — auf dev trugen drei Konten eine Endung, zu der es nie ein Bild gab. Jede Anzeigestelle fragte die Spalte statt die Datei, und so stand an drei Stellen gleichzeitig das kaputte Bildsymbol des Browsers: Kopfleiste, Profilkopf und Profilbild-Abschnitt. Die Adresse/profil/bildantwortete dabei völlig korrekt mit 404; gefragt hatte nur niemand vorher, ob es etwas auszuliefern gibt. - Die Entscheidung steht jetzt einmal in
<x-portal.avatar>statt dreimal im Markup — dass alle drei Stellen dasselbe von Hand nachbauten, war der zweite Teil des Befunds. Der Knopf „Bild entfernen" erscheint ebenfalls nur noch, wenn es etwas zu entfernen gibt. portal:profilbilder-pruefenräumt die Datenlage auf: Es meldet Einträge ohne Datei (mit--anwendenentfernt es die Endung) und Dateien ohne Eintrag. Die zweite Richtung wird nur gemeldet, nie gelöscht — eine Datei ohne Eintrag kann der Rest eines abgebrochenen Uploads sein oder das Bild einer Person, deren Eintrag gerade fehlt; das ist eine Frage, die dieser Befehl nicht beantworten kann.
[2.15.0] — 2026-08-05
- core: Die Oberfläche hat ein Maßraster. Farben kamen aus Tokens, alles andere aus freien Zahlen — in jeder Regel ein eigener Wert (.7rem, .75rem, .8rem, .9rem …). Was dabei entsteht, ist kein Rhythmus, sondern Rauschen: Zwei Karten untereinander hatten verschiedene Innenabstände, und niemand konnte sagen, ob das Absicht war. Neu sind Raumleiter, Schriftskala, Lese- und Arbeitsbreite und Dauern — im Kern, nicht in der Marken-Datei: Eine Marke entscheidet über Farbe, Schrift und Rundung, nicht über den Rhythmus der Seite.
- Hierarchie entsteht nicht mehr nur über Farbe. H1 und H2 waren beide blau und fast gleich groß; „Mein Profil", „Profilbild" und die Begrüßung wirkten gleich wichtig. Jetzt trennen sie Größe, Gewicht und Laufweite, und die dritte Ebene verlässt das Blau — sie ist eine Zwischenüberschrift, kein Seitentitel.
- Fließtext hat eine Lesebreite. Auf der Startseite standen über 120 Zeichen je Zeile. Der Deckel gilt für das, was man liest — nicht für Daten in Tabellen und Kacheln.
- core: Ein dunkles Schema, das der Systemeinstellung folgt und sich im Nutzermenü übersteuern lässt: System · hell · dunkel. Drei Zustände, weil ein Schalter mit nur zweien die Systemeinstellung nie wieder loslässt. Gesetzt wird es von
schema.js, dem einzigen Skript ohnedefer— sonst blitzt bei jedem Seitenwechsel das helle Schema auf. - core: Der Rahmen gibt dem Inhalt den ersten Bildschirm zurück. Auf dem Telefon standen Symbolreihe, Erklärungs-Schalter, Name mit Rolle, Sichtwahl und die vollständige Bereichsliste untereinander — der Seitentitel begann bei etwa 520 Pixeln. Beide klappen dort jetzt zu, mit einem Knopf, den man als Knopf erkennt. Das Zuklappen macht
app.js: Ein geschlossenes<details>versteckt seinen Inhalt selbst, und keindisplayvon außen holt ihn zurück — ohne Skript bleibt alles offen und bedienbar wie bisher. - Die Symbole der Kopfleiste tragen ihr Wort, sobald Platz ist. Vorher waren es vier unbeschriftete Zeichen; wer sie täglich benutzt, lernt sie, alle anderen raten.
- core: Ein Baukasten aus neun Blade-Komponenten — Karte mit Kopf und Fuß, Kennzahl, Verlauf, Held, Schnellaktion, leerer Zustand, Auswahl als Karten. Dazu die Musterseite
/admin-muster: jeder Baustein in seinen schwierigen Zuständen. Sie ist Dokumentation, die nicht veralten kann, weil sie aus demselben Code besteht wie das Portal. - Die Dateiauswahl trägt Markenkleidung. Der rohe Systemknopf war die Stelle, an der eine sorgfältig gebaute Seite billig wirkte. Über
::file-selector-buttonstatt versteckter Eingabe — so bleibt der Dateiname sichtbar, auch ohne Skript. - core: Die Startseite beantwortet zuerst „muss ich hin?". Der Seitenkopf ist eine Farbfläche mit der Illustration darin, darunter die Kennzahlen der Module, dann erst die Kacheln. Der Modul-Vertrag trägt dafür zwei neue Zusagen:
kennzahlen()undschnellaktionen(), beide mit leerem Standard — ein Modul, das nichts meldet, fällt nicht aus, es erscheint nur nicht. Anliegen und Medienakkreditierung liefern echte Zahlen. - Das Hintergrundbild bleibt auf den Gastseiten. Hinter der ganzen Anwendung lief es unter Karten durch, schnitt Überschriften an und füllte die Fehlerseite als großflächiges Motiv ohne Bezug. Eine Illustration, die überall ist, ist nirgends eine Entscheidung.
- Rot steht dort, wo es hingehört. Gefährliche Sammelaktionen sind umrandet statt gefüllt — „Zugang sperren" war der roteste und größte Knopf einer Listenseite, optisch das Wichtigste und tatsächlich das Seltenste. Als Fläche ist Rot nicht mehr das Signalrot
#E3000B: Weiße Schrift darauf war in der geometrischen Ersatzschrift kaum zu entziffern. Neu ist die Gefahrenzone für das, was sich nicht zurücknehmen lässt. - core: Ballast raus. 4,2 MB Filament-Reste unter
public/js,public/cssundpublic/fonts, auf die seit der Ablösung (2.0.0) niemand mehr verweist — dazu das ungenutzte Tailwind- und Vite-Gerüst: Es stand inpackage.json, wurde aber nirgends benutzt. Zu entfernen und nicht zu aktivieren, denn Utility-Klassen im Markup würden die Trennung zwischen austauschbarer Marke und Kern aufheben, die A10 verlangt.
[2.14.0] — 2026-08-05
Abgleich des Moduls Anliegen mit dem abgelösten Digitalisierungsportal (btv-Digitalisierungsanforderungen). Fünf Lücken, und wieder dasselbe Muster wie im ganzen Neubau: Was fehlte, war meist nicht das Bauteil, sondern der Weg dorthin.
- digi: Ein Anliegen lässt sich intern erfassen. Das Kennzeichen
internalgab es von Anfang an — gesetzt hat es allein die Datenübernahme. Es kam also nur noch aus der Vergangenheit und nie aus dem Betrieb. Im Original war das je Board ein „Internes Anliegen anlegen"; ohne diesen Weg steht das Team vor der Wahl, ein am Telefon gemeldetes Anliegen entweder gar nicht zu erfassen oder die meldende Person zu bitten, es noch einmal selbst einzugeben — im Betrieb ist beides dasselbe.
Neu ist /admin/digi-anliegen-neu, ein Reiter je Board. Zwei Entscheidungen macht die Fläche sichtbar, statt sie zu verstecken: wem der Vorgang gehört (intern = dem Team, sonst der genannten Person, die ihn dann unter „Meine Anliegen" findet) und ob Post hinausgeht — das Original verschickte bei interner Anlage grundsätzlich nichts, was als Vorgabe richtig ist und als Zwang falsch.
Der Reiter entscheidet, in welchem Board der Vorgang entsteht — deshalb gilt hier der Rückfall der Grundklasse nicht. Ein gesperrtes Board endet mit 403 statt still beim ersten erlaubten: Wer für „IT" absendet, ohne es zu dürfen, bekäme sonst eine Erfolgsmeldung, und der Vorgang stünde unter „Digitalisierung".
- digi: Kopieren und Aufteilen. Im Original seit dessen v1.11.0, hier überhaupt nicht. Der Inhalt wandert mit, die Steuerung nicht: Felder, erwarteter Nutzen und Verweise beschreiben das Anliegen, Status und Zuständigkeit seine Bearbeitung — und die beginnt für den neuen Vorgang von vorn. Beide Seiten bekommen einen Verlaufseintrag, damit man vom einen zum anderen findet. Die Kopie eines intern erfassten Vorgangs bleibt intern, sonst erschiene sie plötzlich unter „Meine Anliegen" einer Person, die sie nie eingereicht hat.
- digi: Das Team schreibt der einreichenden Person — mit einer Art. Bisher gab es nur den Weg, auf dem die einreichende Person schreibt. Das Original kannte drei Vorlagen (Rückfrage, Abschluss, Information), und der Unterschied liegt nicht im Text, sondern im Betreff: „Rückfrage zu Deinem Anliegen" verlangt eine Antwort, „Dein Anliegen ist erledigt" schliesst ab. Unter einem gemeinsamen Betreff müsste die lesende Person aus dem Fliesstext erraten, ob sie am Zug ist. Drei pflegbare Textpaare, nicht drei Kopien im Code; die Art wird nicht gespeichert, denn sie steuert den Betreff und sonst nichts.
- digi: Der Prozessschritt lässt sich in der Zeile setzen. Die Gesamtsicht des Altportals konnte das. Die Steuerungsfläche bleibt der Ort für eine Entscheidung — dort steht der Vorgang mit Beschreibung und Verlauf —, aber das Sichten einer frisch eingegangenen Liste ist keine Entscheidung dieser Art, sondern dreissigmal dieselbe Handbewegung. Auswahlfeld plus Knopf, kein Feld, das sich selbst absendet (WCAG 3.2.2): Beim Durchblättern der Werte mit der Tastatur ginge sonst für jeden Zwischenschritt eine Mail hinaus. Wer nur lesen darf, bekommt die Spalte nicht.
- digi: Grundsätze, Ablauf und Prüfliste vor dem Formular. Das Original hatte je Zweig eine eigene Seite mit drei festen Abschnitten. Die Seite gibt es hier bewusst nicht mehr; der Inhalt stand dort vor der Einreichung und steht deshalb jetzt dort — klappbar, pflegbar, eine Zeile je Punkt. Ein Satz wie „Eine Einreichung bedeutet noch keine Umsetzung" beugt genau der Erwartung vor, an der sich später jemand stört. Dazu die Prozessübersicht als hinterlegbare Bildadresse je Board (nur
http(s), beim Speichern und beim Lesen geprüft — der Wert landet in einemsrc).
- digi: Der Namensabgleich hat einen Weg. Er war gebaut und ausschliesslich aus einem Testfall heraus erreichbar. Er deckt jetzt auch
responsible_internalab — im Original war das eine eigene Wartungsaktion, und aus gutem Grund: An diesem Feld hängt ein Filter des Boards, und steht dieselbe Person einmal als Name und einmal als Adresse darin, findet der Filter jeweils nur die halbe Arbeit. Als Aktion in den Modul-Einstellungen, mit Probelauf vorweg;updated_atbleibt unangetastet.
- digi: Priorisierung und Sprintplanung lassen sich filtern und durchsuchen. Board, Priorität, Dringlichkeit, Verantwortlich — die Filter, die das Original in seiner v1.13.0 nachgerüstet hat, weil ein Backlog ab ein paar Dutzend Zeilen ohne sie eine Wand ist.
Planung::liste()nahmprio,qundzweigevon Anfang an entgegen; übergeben hat sie nie jemand.
„Nicht bewertet" ist dabei ein echter Wert und keine leere Zeichenkette: Der Listenzustand verwirft leere Filterwerte, bevor sie ankommen — und genau dieser Filter beantwortet die Frage, woran noch niemand gearbeitet hat.
Das Spaltenboard der Sprintplanung baut seine Spalten selbst und ging an den Filtern vorbei; es wendet sie jetzt an. Sonst hätte ein Filter die Zahl in der Überschrift geändert und die Karten darunter nicht — schlimmer als kein Filter.
Bewusst nicht übernommen: die Microsoft-Planner-Anbindung (Übergabe und Rücksynchronisierung über Graph). Der Neubau schreibt Planner-Verknüpfungen beim Umzug in Verweise um. Am 05.08.2026 ausdrücklich so entschieden — das ist damit keine offene Lücke des Abgleichs, sondern der Stand: Wer die Anbindung später vermisst, findet hier die Entscheidung und nicht ein Versehen.
Ebenfalls nicht im Modul, weil im Kern vorhanden: Mail-Protokoll, Prüfspur, Selbstprüfung, Rollenpflege, Datenbanksicherung.
[2.13.0] — 2026-08-05
Zweiter Abgleich der Medienakkreditierung mit dem Vorgängersystem btv-akkreditierung, Route für Route gegen dessen Routentabelle. Der erste Durchgang (2.12.0) hat die fehlenden Wege geschlossen; was jetzt gefunden wurde, war kein fehlender Knopf mehr, sondern eine Zusage, die nicht stimmte.
- akkreditierung: Die Veranstaltungsliste ist jetzt wirklich die Importvorlage. Sie hat es behauptet — im Kommentar an
ausfuhr()und inSaisonkalender::SPALTEN— und war es nicht: Der Importer suchtVon,AnsprechpartnerundAktiv, die Ausgabe schriebBeginn,AnsprechpersonundBuchbar;BisundE-Mailgab es dort überhaupt nicht. Wer exportierte, in Excel nachtrug und zurückspielte, leerte damit Zeitraum und Kontaktadresse und stellte jede stillgelegte Veranstaltung wieder ins öffentliche Formular — bei einem Import, der „aktualisiert" meldete. Beide Seiten waren für sich richtig; kaputt war nur der Weg von der einen zur anderen, und den prüfte niemand. Ein Wächtertest hält Überschriften und Erwartung jetzt zusammen, ein zweiter spielt die echte Ausgabe der Liste durch den Importer. - akkreditierung: Der Importer versteht seine eigene Ausgabe. „—" gilt als leer (vorher: „„—" ist kein Datum" — eine Fehlermeldung, die nach einem Tippfehler der Anwenderin aussah und keiner war), und „nicht buchbar" zählt als abgeschaltet.
- akkreditierung: Der Zeitraumfilter der Antragsliste — im Original die Felder „von" und „bis". Gefiltert wird nach Überschneidung, nicht nach Enthaltensein: Wer nur am Samstag kommt, gehört in die Liste für die Turnwoche. Leer heisst „alle"; die Monatsvorgabe der Kennzahlenfläche wäre hier falsch, sie versteckte die Hälfte, ohne dass es auffiele.
- akkreditierung: Drei Spalten der Ausfuhr nachgezogen — Ansprechperson der Veranstaltung, „Nachweis vorhanden" und „Wettkampfleitung informiert". Das letzte ist ein gepflegtes Feld, das in keiner Spalte stand und damit in keiner Datei ankam. „Nachweis vorhanden" kennt eine dritte Antwort, die das Original nicht hatte: „vor Ort geprüft" — es schrieb „nein", wo jemand den Presseausweis am Tisch gesehen hatte.
- core: Das Löschen eines Vorgangs anonymisiert seine Mails sofort. Bisher griff nur die allgemeine Frist (12.5.4, ein Jahr) — die Akkreditierung löscht ihre Anträge aber nach einem halben. Dazwischen standen Name, Adresse und Text der antragstellenden Person weiter im Protokoll, obwohl der Antrag längst weg war; bei der von Hand ausgelösten Löschung, der Vorgabe des Datenschutzbeauftragten, bis zu einem Jahr lang. Das Vorgängersystem hat an dieser Stelle anonymisiert. Die Zeile bleibt — sie ist der Nachweis, dass etwas hinausging —, nur der Personenbezug geht. Wartende Mails bleiben unangetastet: Wer ihnen den Inhalt nimmt, stellt einer echten Person eine leere Mail zu.
- akkreditierung: Ein eigenes Mail-Protokoll für den Fachbereich. Im Vorgängersystem sah es jede board-berechtigte Person; im Neubau hing es am Kernrecht
mails.view, das keine der beiden Akkreditierungsrollen trägt — die Funktion war für genau die Menschen verschwunden, die sie benutzt haben.mails.viewnachzureichen wäre die falsche Reparatur gewesen: Es öffnet die Post des ganzen Portals. Die neue Fläche zeigt über den Vorgangsbezug nur die eigene, erbt Spalten und Fehlerdeutung vom Kern und lässt die portalweite Sammelaktion „alle abhaken" bewusst weg.
[2.12.0] — 2026-08-04
- core: Das Mailprotokoll kennt den Vorgang. Bisher stand in
mailsnur, an wen etwas ging. „Welche Nachrichten gehören zu diesem Antrag?" liess sich damit nur raten — über die Empfängeradresse (dann kommt Post aus fremden Modulen mit) oder über die Antragsnummer im Betreff (dann verschwindet eine Mail, sobald jemand{nummer}aus der Vorlage nimmt, und die Vorlagen sind seit 2.10.0 pflegbar). Eine Vorgangsakte, die je nach Wortlaut einer Vorlage mal vollständig ist und mal nicht, ist keine.
Neu sind subject_type und subject_id — dieselbe Form wie bei documents: eine fachliche Kennung (akkreditierung_antrag), kein Klassenname, und kein Fremdschlüssel. Das Protokoll soll ohne das Modul lesbar bleiben, das es geschrieben hat, und die Zeile darf nicht mitgelöscht werden, wenn der Vorgang nach Ablauf der Aufbewahrung verschwindet — sie ist gerade der Nachweis, dass etwas hinausging. Ein halber Bezug (Typ ohne Nummer) wird nicht gesetzt: Er sähe in einer Akte aus wie eine Zuordnung und wäre keine.
- core: Der Altbestand wird einmalig nachgezogen. Sonst fehlten alle Nachrichten von vor dieser Fassung, ausgerechnet an der Stelle, die zeigen soll, was einer Person mitgeteilt wurde. Zugeordnet wird nur, was eindeutig ist: Für Post an die antragstellende Person müssen Adresse und Antragsnummer zusammenpassen; für alles andere — etwa die Eingangs-Info an den Fachbereich, dessen Adresse bei jedem Antrag dieselbe ist — zählt allein die Antragsnummer, und nur wenn genau eine im Text steht. Die Erinnerung an überfällige Anträge zählt mehrere auf und bleibt deshalb ohne Bezug: Sie gehört zu keinem einzelnen, und über den ersten Treffer zugeordnet hinge sie am falschen. Lieber eine alte Mail ohne Bezug als eine am falschen Antrag.
- akkreditierung: Die Mails am Antrag hängen jetzt am Vorgang. Damit steht auch die interne Info an den Fachbereich in der Akte: „Wurde der Fachbereich überhaupt benachrichtigt?" ist genau die Frage, die später kommt. Die Erinnerung an überfällige Anträge bleibt ausdrücklich ohne Bezug — sie zählt viele Vorgänge auf und gehört zu keinem.
[2.11.0] — 2026-08-04
- akkreditierung: Die Antragsseite zeigt endlich den Antrag. Sie hatte Status, Nachweise und die Entscheidungsknöpfe — aber weder Name noch Redaktion noch Zeitraum. Wer „Abgelehnt" wählte, entschied über eine Nummer. Jetzt stehen die Angaben oben, unveränderlich: Name, Funktion, Redaktion, Telefon, E-Mail, Veranstaltung, Ort, Zeitraum, Eingang, Entscheidung und die Bemerkung der antragstellenden Person.
- Zustimmungen mit Zeitpunkt, nicht als Häkchen. „Ja" beantwortet die Frage nicht, die später gestellt wird — die lautet wann.
- Der Statusverlauf steht auf der Seite. „Warum steht der Antrag auf abgelehnt?" ist die häufigste Rückfrage, und sie liess sich bisher nur in der Datenbank beantworten.
- Mails zu diesem Antrag. Erkannt an Adresse und Antragsnummer, weil die Mailtabelle den Vorgang nicht kennt: Das kann eine Mail übersehen, ordnet aber nie eine fremde zu — und nur über die Adresse zu gehen zöge Post aus anderen Modulen mit herein. In diese Richtung ist ein Fehler der harmlosere.
- Die Dublettenwarnung erscheint.
istDublette()war gebaut und wurde von niemandem aufgerufen. Zwei Anträge derselben Adresse zur selben Veranstaltung sind fast immer ein zweiter Anlauf, weil der erste nicht anzukommen schien — wer das nicht sieht, akkreditiert dieselbe Person zweimal. - Die Steuerfelder haben einen Weg.
steuerungSetzen()stand samt Prüfung im Modul, und keine Fläche rief es auf: interne Bemerkung, „Nachweis geprüft von", „Wettkampfleitung informiert". Sie werden immer gespeichert und nicht nur beim Statuswechsel — wer nur eine Bemerkung ergänzt, bekam sonst „nichts geändert" und einen verlorenen Text. Neu dabei: „Ausweis vor Ort ausgegeben", und zwar nur, wenn das Feld auch mitkommt; ein Aufruf ohne diesen Schlüssel darf die Markierung nicht stillschweigend zurücknehmen. - Der Ausweis lässt sich herunterladen — frisch gezeichnet, ohne den Umweg über die Mail an die antragstellende Person.
Drei der sechs Punkte waren wieder fertige Bauteile ohne Weg dorthin, und ihre Prüfungen sicherten jeweils den Dienst statt den Weg. Im Formular-Gerüst neu: die Feldarten angaben (Bezeichnung/Wert, nur zum Lesen) und chronik (eine nummerierte Abfolge — bei einem Verlauf ist die Reihenfolge die Aussage).
[2.10.0] — 2026-08-04
Abgleich mit dem Vorgängersystem btv-akkreditierung, Funktion für Funktion. Drei Lücken kamen dabei heraus — und zwei davon waren keine fehlenden Bauteile, sondern fertige Bauteile ohne Weg dorthin. Dieselbe Fehlerklasse wie schon mehrfach in diesem Projekt.
- akkreditierung: Die Mailvorlagen ließen sich pflegen und wirkten nicht. Der Inhalts-Editor legt gepflegte Texte unter
inhalt.<schlüssel>ab; die Mailvorlage las den blanken Schlüssel. Wer die Genehmigungsmail umschrieb, bekam eine gespeicherte Änderung angezeigt und verschickte weiter den Auslieferungstext. Ein Editor, der sich speichern lässt und nichts bewirkt, ist schlimmer als keiner — er sieht nach getaner Arbeit aus. Gelesen wird jetzt über denselben Dienst, der schreibt. - akkreditierung: Die Textbausteine stehen im Modul. Sie lagen allein unter Konfiguration → Texte & Inhalte, und die verlangt
settings.manage. Der Fachbereich Kommunikation hatakkreditierung.verwalten— er kam an seine eigenen Mailvorlagen also gar nicht heran. Jetzt als eigener Reiter unter „Einstellungen": je Vorlage ein aufklappbarer Block mit Betreff und Text, jede mit den Platzhaltern, die in ihr etwas ersetzen ({wl_link}gibt es nur in der Info an die Wettkampfleitung,{nachreichen_link}nur an einem Antrag — eine gemeinsame Liste verführte dazu, einen in die falsche Vorlage zu setzen, und dann stünde die geschweifte Klammer wörtlich in einer echten Mail). Ein leeres Feld setzt auf den mitgelieferten Entwurf zurück; er steht blass im Feld. Gespeichert wird über denselben Dienst wie im Kern-Editor — zwei Ablagen für denselben Text hiessen, dass eine davon wirkt und niemand weiss, welche. - akkreditierung: Die Info an die Wettkampfleitung kommt aus ihrer Vorlage.
wl_infostand samt Platzhaltern im Modul und wurde von niemandem benutzt; verschickt wurde ein fest verdrahteter Text. Jetzt trägt die Mail die Zahlen (genehmigt/offen) und lässt sich pflegen. Der ausgelieferte Text verspricht außerdem keine Anwesenheitsliste im Anhang mehr — es ging nie eine mit, und die lebende Liste hinter dem Link ist ohnehin aktueller. - akkreditierung: Nachweise und ganzer Antrag lassen sich von Hand löschen. Im Vorgängersystem eine ausdrückliche Vorgabe („separat löschbar"), in v2 gab es bisher nur die automatischen Aufbewahrungsläufe. Ein Presseausweis darf weg, sobald er geprüft ist — lange bevor die Frist für den Antrag läuft. Ginge nur alles auf einmal, bliebe er liegen, weil niemand den ganzen Vorgang wegwerfen will. Die Löschung steht mit Namen im Verlauf: Sonst weiss später niemand, ob der Nachweis nie da war oder ob ihn jemand entfernt hat. Den ganzen Vorgang löscht nur die Modulverwaltung; danach führt der Weg zurück zur Liste statt auf eine 404.
- akkreditierung: QR-Code zum Antragsformular — allgemein oder je Veranstaltung, mit Menüpunkt. Der Code je Veranstaltung öffnet das Formular mit vorausgewählter Veranstaltung, für den Aushang am Akkreditierungspunkt. SVG für den Druck, PNG fürs Netz: Ein Aushang wird auf A3 vergrößert, und ein unscharfer QR-Code ist einer, den das Handy an der Halle nicht liest. Das SVG entsteht ohne zweite Bibliothek aus der Matrix, die die vorhandene schon liefert — als ein Pfad statt tausend Rechtecke, weil Drucktreiber benachbarte Rechtecke gern mit einer Haarlinie absetzen und genau die aus einem lesbaren Code ein Muster macht.
Im Formular-Gerüst neu: aufklappbare Abschnitte (natives <details>, also auch ohne Skript und mit der Tastatur), die Feldart bild, und absendbar() für Flächen ohne Bestand — „Du darfst nichts ändern" wäre dort falsch, es liegt nicht am Recht. Das mehrzeilige Feld zeigt jetzt ebenfalls den blassen Standardtext; ausgerechnet die langen Texte, um die es im Inhalts-Editor geht, zeigten bisher nicht, worauf ein Leeren zurückfällt.
Alles Übrige des Vorgängersystems ist da und wurde gegengeprüft: öffentlicher Antrag, Dankeseite, Merkblatt, Einlassliste samt Ausweis-Download, Prüfseite, Nachreichen, Board mit Sammelaktionen, Ausweis, Druckliste, Sammelausweise, Mailprotokoll, Ausfuhr, Erinnerungslauf, Selbstprüfung.
[2.9.0] — 2026-08-04
- akkreditierung: Der Saisonkalender lässt sich aus einer Excel-Datei einlesen — in zwei Schritten, und der erste schreibt nichts. Ein Kalender bringt dreißig Termine auf einmal mit. Ginge er direkt in die Datenbank, wäre eine verrutschte Spalte dreißig falsche Veranstaltungen, und jede davon stünde danach im öffentlichen Anmeldeformular. Also erst die Vorschau: was neu ist, was sich ändert, was nicht geht — mit den Zeilen im Klartext, nicht nur als Anzahl. Übernommen wird mit einem zweiten, eigenen Griff, und die Vorschau ist danach verbraucht, damit ein zweiter Klick nicht dieselben Termine ein zweites Mal anlegt.
- Erkannt wird an Name und Ort. Der Zeitraum gehört ausdrücklich nicht dazu: Er ist das, was sich ändert, und wäre er Teil der Erkennung, entstünde bei jeder Terminverschiebung ein Doppel statt einer Korrektur.
- Fehlerhafte Zeilen halten den Rest nicht auf. Ein Kalender mit einem Tippfehler in Zeile 14 gar nicht einzulesen hiesse, dass jemand ihn außerhalb korrigiert und danach hofft. Sie stehen mit Zeilennummer und Grund in der Vorschau — mit der Nummer, die Excel anzeigt.
- Die Vorlage ist die Ausgabe der Veranstaltungsliste selbst. Wer sie herunterlädt, ergänzt und wieder einliest, braucht keine zweite Wahrheit darüber, wie die Spalten heißen.
Neu im Unterbau: Tabellenleser liest .xlsx ohne zusätzliche Abhängigkeit — aus demselben Grund wie das Schreiben. Alles kommt als Zeichenkette zurück; was eine Zahl ist und was ein Datum, entscheidet der Fachdienst. Excel legt Datumsangaben als Tage seit dem 30.12.1899 ab, „14.08.2026“ kommt also als 46248 an — der Saisonkalender rechnet beides um, denn wer die Vorlage in einem anderen Programm bearbeitet, bekommt Text. Externe Entitäten bleiben beim Lesen aus (XXE), und mehr als 500 Zeilen lehnt der Leser mit Ansage ab statt still abzuschneiden.
Die Feldart hinweis im Formular-Gerüst kann jetzt eine Aufzählung tragen. Ein Zwischenstand, der nur „3 Zeilen“ sagt, ist keine Auskunft: Wer übernimmt, muss sehen, *was* geschrieben wird.
[2.8.0] — 2026-08-04
- akkreditierung: Eine neue Veranstaltung übernimmt aus einer vorhandenen — Name, Ort und Ansprechperson. Ein Saisonkalender wiederholt sich: dieselbe Halle, dieselbe Ansprechperson, nur ein anderes Wochenende. Die Datumsfelder bleiben leer; sie sind das, was sich von Jahr zu Jahr ändert, und ein übernommener Termin von letzter Saison wäre der Fehler, den niemand bemerkt. Angeboten wird die Übernahme nur beim Anlegen — an einer bestehenden Veranstaltung wäre sie ein Knopf, der Eingegebenes ohne Rückfrage überschreibt.
- akkreditierung: Die Veranstaltungsliste lässt sich ausgeben. Sie ist zugleich die Vorlage für den Saisonkalender-Import.
Das Formular-Gerüst kennt dafür die Feldart uebernehmen: eine Klappliste mit eigenem Knopf, die dieselbe Fläche vorbefüllt neu lädt. Kein Feld, das sich selbst absendet (WCAG 3.2.2) — und ein eigenes <form>, weil ein Formular im Formular ungültiges Markup ist und der Browser das innere verwirft.
[2.7.0] — 2026-08-04
- akkreditierung: Ein Antrag lässt sich intern erfassen — für Anfragen, die telefonisch, per Mail oder über die Pressestelle hereinkommen. Der Antrag nimmt danach den normalen Lauf.
Eigene Fläche neben „Vor Ort nachpflegen", nicht dieselbe mit Schaltern. Die beiden beschreiben zwei Lagen: Vor Ort steht die Person am Tisch, der Ausweis liegt vor, die Veranstaltung läuft womöglich schon — dort darf der Zeitraum zurückliegen und es geht keine Mail hinaus. Intern erfasst heißt: dieselbe Prüfung wie im öffentlichen Formular, dieselben Fristen, dieselben Mails. Zusammengelegt trüge eine Fläche vier Schalter, von denen drei fast immer falsch stehen.
- Der Anmeldeschluss gilt auch hier. Sonst wäre diese Fläche der Weg daran vorbei — und niemand hätte das beschlossen. Wer nach Ablauf erfassen muss, nimmt „Vor Ort nachpflegen".
- Die Zustimmungen werden verlangt, nur erklärt sie die Verwaltung. Sie sind der rechtliche Kern des Antrags; sie wegzulassen, weil intern erfasst wird, hieße den Antrag ohne seine Grundlage anzulegen. Der Nachweis, dass das Merkblatt in *dieser Sitzung* geöffnet wurde, entfällt dagegen: Gelesen haben muss es die antragstellende Person, nicht die Sachbearbeitung.
- Die Eingangsbestätigung ist eine Entscheidung, keine Nebenwirkung. Wer telefonisch beantragt hat, erwartet sie; wer einen Altbestand nachträgt, nicht. Das Kästchen ist vorbelegt — der Normalfall ist die Bestätigung. Die interne Meldung an den Fachbereich geht in jedem Fall hinaus.
[2.6.0] — 2026-08-04
- core: Der Navigationspfad hing an der Adresse statt am Menü. Ein Menüpunkt zählte nur zum Modul, wenn seine Adresse mit der Moduladresse anfing. Das passt für Module mit gemeinsamem Pfad (
/digi/boardunter/digi) und für kein anderes: Die Medienakkreditierung führt ihre Flächen als Geschwister unter/admin/, also fiel jede durch die Prüfung. „Vor Ort nachpflegen" stand ohne Zusammenhang direkt unter „Start", und wo es auffiel, half sich der Seitentitel mit einem Gedankenstrich selbst („Medienakkreditierung — Veranstaltungen"). Wer im Menü unter einer Gruppe steht, gehört zu ihr — das ist die Aussage des Menüs, und es ist die ehrlichere Auskunft: Man ist über diesen Menüpunkt hergekommen. Die Hilfstitel sind entfallen. - akkreditierung: Entscheiden und Bescheid geben stehen am Kopf. Der Ablauf besteht aus je zwei Handgriffen — genehmigen und Genehmigungsmail, Ausweis erstellen und Ausweis-Mail. Sie lagen an drei Stellen verteilt: Aktion oben, Status unten im Formular, Mail als Verweis mittendrin. Wer zwanzig Anträge bearbeitet, sucht dreimal je Antrag. Der Statuswechsel verschickt weiterhin nichts — das ist Absicht, und die Paare stehen nebeneinander, damit der zweite Schritt nicht vergessen wird.
- verwaltung: Die erste Spalte einer Arbeitsliste führt zum Datensatz. Sie trägt die Nummer oder den Namen — das, worüber man den Eintrag erkennt, und worauf die Hand ohnehin zielt. Ein „Ansehen" ganz rechts zwingt den Blick über die ganze Zeile und zurück; bei achtzig Zeilen ist das die Bewegung, die man achtzigmal macht. Die Zeilenaktionen bleiben, wo sie sind: Sie tun etwas, der Verweis führt nur hin.
[2.5.2] — 2026-08-04
- akkreditierung: Das SAFE-SPORT-Merkblatt ist ein PDF und öffnet in einem neuen Tab. Zwei Anläufe hat das gebraucht, und beide gingen am Kern vorbei. Zuerst war es ein gewöhnlicher Verweis — der Klick verließ das ausgefüllte Formular. Dann ein Absendeknopf, der die Eingaben zwischenspeicherte; das rettete sie, führte aber weiterhin auf eine andere Seite. Gemeint war beides nicht: Das Merkblatt ist ein Dokument. Als PDF im neuen Tab wird die Seite mit dem Formular gar nicht erst verlassen — es gibt nichts zu retten. Der Nachweis „geöffnet" hängt unverändert am Abruf beim Server.
- Der Wortlaut steht an einer Stelle (
Merkblatttext) und speist Seite wie PDF. Zwei Fassungen desselben Textes laufen auseinander — und bei einem Text, dessen Kenntnisnahme jemand bestätigt, wäre bestätigt dann die eine und gelesen die andere. Ein Testfall vergleicht beide.
[2.5.1] — 2026-08-04
- akkreditierung: Der Weg zum SAFE-SPORT-Merkblatt kostete alle Eingaben. Es ist eine eigene Seite, und das aus gutem Grund: Der Nachweis „geöffnet" hängt an einem echten Aufruf, ein Kästchen allein belegt nichts. Der Weg dorthin war aber ein Verweis — wer ihn anklickte, verließ das ausgefüllte Formular, und beim Zurückgehen war alles weg. Ein halb ausgefüllter Antrag, den man zweimal tippt, wird beim zweiten Mal nicht besser. Jetzt ist es ein Absendeknopf: Das Formular geht mit, die Eingaben landen in der Sitzung und stehen beim Zurückkommen wieder da. Der Nachweis bleibt unverändert serverseitig. Der Knopf trägt
formnovalidate— sonst hielte der Browser an den Pflichtfeldern an, und man käme nie zum Merkblatt. Nicht zu retten ist eine bereits ausgewählte Datei — das verbietet der Browser aus gutem Grund. Ein Hinweis am Knopf sagt das.
[2.5.0] — 2026-08-04
- akkreditierung: Die Datumsfelder einer Veranstaltung tragen einen Kalender. Hier stand die umgekehrte Entscheidung, mit einem richtigen Einwand: Ein Datumswähler wäre eine zweite Wahrheit über das erlaubte Format. Der Einwand trifft auf ein eigenes Bauteil zu, nicht auf
input type="date"— das zeigt die Schreibweise des Geräts (deutsch also TT.MM.JJJJ) und schickt immer ISO, genau das, was die Prüfung des Fachdienstes ohnehin annimmt. Sie bleibt die Instanz, die entscheidet. Der Wechsel verlangte eine zweite Änderung: Die Werte kommen jetzt als ISO in die Maske. Mit dem deutschen Format wäre das Feld stumm leer geblieben — und wer nur den Ort ändert, hätte beim Speichern unbemerkt die Daten gelöscht. - akkreditierung: Die Adresse der öffentlichen Anmeldung steht an der Veranstaltung — mit dieser Veranstaltung vorausgewählt, absolut und zum Weitergeben. Sie wird an Redaktionen geschickt und in Einladungen gesetzt; sie aus dem Kopf zusammenzusetzen ist eine Fehlerquelle mit Kennung darin. Das Merkblatt steht daneben.
Das Formular-Gerüst kennt dafür die Feldart datum.
[2.4.1] — 2026-08-04
- verwaltung: Der Filterschalter lag über dem Filterbereich. Er war absolut positioniert und die Reiterzeile hielt ihm mit
padding-rightPlatz frei — auf einer Fläche ohne Reiter (der Priorisierung etwa) gab es diesen Platz nicht, und der Schalter lag auf Suchfeld und Knopf. Jetzt liegt er im Fluss: Reiter links, Schalter rechtsbündig auf eigener Zeile, der Filterbereich darunter über die volle Breite. Das kann sich nicht mehr überlagern. - verwaltung: „Filter & Ansicht" stand wörtlich auf dem Schirm. Der Titel war als
&in einem{{ }}-Ausdruck geschrieben — Blade maskiert dort ohnehin, also ein zweites Mal. Kein Testfall bemerkt das, weil das Markup gültig bleibt; gesehen hat es ein Mensch. Ein Fall bewacht es jetzt.
[2.4.0] — 2026-08-04
Sprintplanung und Sprintboard stehen als Spaltenboard mit Ziehen — wie im Altsystem.
- digi: Die Sprintplanung ist ein Board. Backlog links, die Sprints daneben, an jeder Spalte die Aufwandssumme. Die Frage dieser Fläche ist die Verteilung — wie voll ist welcher Sprint, was liegt noch im Backlog. Das beantwortet eine Tabelle erst, wenn man nach Sprint sortiert und Zeilen zählt.
- digi: Das Sprintboard zeigt alle Arbeitsstufen nebeneinander. Die Reiter aus 1.8.0 sind weg. Die Sorge dahinter war richtig — ein Board zum Ziehen ist mit der Tastatur nicht bedienbar —, die Folgerung nicht: Reiter zeigen immer nur eine Stufe, und die Frage eines Sprintboards ist gerade der Vergleich. Wo staut es sich, ist „In Umsetzung" überfüllt.
- Ziehen ist Zugabe, nicht Ersatz. Jede Karte trägt weiterhin ihre Klappliste mit „setzen". Das Ziehen füllt genau dieses Formular aus und schickt es ab — ein Endpunkt, eine Prüfung, ein Verhalten. Ohne JavaScript bleibt die Klappliste; auf dem Telefon und mit der Tastatur ist sie der Weg (WCAG 2.1.1).
- digi: Der Grund einer Blockade war nirgends zu sehen. Drei Stellen lasen
blocked_reason— ein Feld, das es nie gab; die Spalte heißtblocked_note. Das Board zeigte nur „wartet", und das Arbeitsstand-Formular kam mit leerem Grundfeld hoch, obwohl einer gespeichert war. Dieselbe Fehlerklasse wiebacklog_rank. Eine Blockade überlebt jetzt auch den Stufenwechsel: Sie gehört zum Vorgang, nicht zur Stufe.
Das Listen-Gerüst kann dafür jetzt ein Spaltenboard (board(), karte(), boardVerschieben()) — dieselbe Fläche, dieselben Rechte, andere Darstellung.
[2.3.0] — 2026-08-04
- digi/verwaltung: Der Excel-Export liefert jetzt eine echte
.xlsx. Der Knopf hiess so, die Datei war eine CSV — und Excel fragt dabei je nach Fassung nach Trennzeichen und Zeichensatz, deutet Nummern als Datum und schneidet fuehrende Nullen ab. Genau dagegen trug die CSV eine Byte-Reihenfolge-Marke und Semikolon: lauter Notnaegel fuer ein Format, das nicht gemeint war. Geschrieben ohne zusaetzliche Abhaengigkeit (App\Support\Tabellendatei, rund 200 Zeilen) — die ueblichen Pakete bringen Diagramme und Formelrechner mit. Nur echte Zahlen werden Zahl: „007" bleibt „007". Kopfzeile fest, Autofilter gesetzt. Fehlt die ZIP-Erweiterung, bleibt der CSV-Weg; die Selbstpruefung meldet sie jetzt mit. - digi: Die Lupe lag weiterhin ueber dem Platzhaltertext. Das Symbol allein hat es nicht behoben:
.filter-panel input[type="search"]schlaegt.board-suche inputin der Spezifitaet und setzte den linken Innenabstand zurueck. - verwaltung: Die Spaltenwahl lief rechts aus dem Fenster. Sie oeffnet jetzt nach links — der Knopf sitzt am rechten Rand — und begrenzt Breite und Hoehe.
- digi: Die Priorisierung wird in der Zeile entschieden. Prioritaet, Aufwand und Zieldatum stehen als Felder in der Tabelle; gespeichert wird einmal unten. Wer ein Backlog priorisiert, vergleicht Zeilen miteinander — vorher fuehrte jede Bewertung auf eine eigene Flaeche und die Vergleichsgrundlage war weg. Bei dreissig Vorgaengen sind das sechzig Seitenwechsel. Kein Feld sendet sich selbst ab (WCAG 3.2.2), und unveraenderte Zeilen erzeugen keinen Eintrag im Verlauf.
Das Listen-Geruest kann dafuer jetzt ein Zeilenformular: ein <form> neben der Tabelle, dessen Felder in den Zellen stehen und es ueber ihr form-Attribut nennen. HTML erlaubt kein Formular ueber Tabellenzeilen — der Browser zieht es heraus, und die Felder darin gehoeren dann zu nichts.
[2.2.0] — 2026-08-04
- core: Die Anmeldeseite hatte auf dem Server ihre halbe linke Spalte verloren — keine Überschrift, keine Einleitung, keine Nutzenpunkte. Das war eine Folge von 2.0.1: Seitdem ruft die Auslieferung
artisan optimize, und mitroute:cachewerden die Routendateien nicht mehr ausgeführt. Inroutes/portal.phpstand aber der Aufruf, der die Texte der Anmeldeseite an die Registry meldet. Ohne ihn kenntInhalte::lesen()die Schlüssel nicht und liefert eine leere Zeichenkette — kein Fehler, keine Meldung, ein grüner Testlauf. Die Anmeldung meldet sich jetzt im Service-Provider an. - Ein Testfall bewacht die ganze Fehlerklasse (
RoutendateienTest): Was in einer Routendatei steht und keine Route ist, läuft im Betrieb nicht. - core:
/ist die Anmeldeseite. Vorher lagen zwei Seiten hintereinander — eine Vorstellung unter/und die Anmeldung unter/login. Wer ankam, musste erst einen Knopf drücken, um dorthin zu gelangen, weswegen er gekommen war; die Anmeldeseite trägt dieselbe Vorstellung längst in ihrer linken Spalte./loginbleibt bestehen und zeigt dieselbe Fläche: Die Adresse steht in Mails, Lesezeichen und in der Weiterleitung nicht angemeldeter Aufrufe. - core: Die Betreiber-Angabe der alten Startseite steht jetzt links auf der Anmeldeseite — sie war der einzige Inhalt, den die zusammengelegte Seite sonst verloren hätte.
[2.1.0] — 2026-08-04
Testplan „Integration Digi & IT Portal" — dreizehn Punkte, alle umgesetzt.
- digi: Ein Einstieg für alle Boards statt einer je Board. Jedes Board stand zusätzlich einzeln im Menü; die Wahl war damit zweimal da — einmal im Menü, einmal als Reiter im Board. Der Menüpunkt entfällt nur, weil es den Weg im Board nachweislich gibt; ein Testfall hält beides fest.
- digi: „Als CSV ausgeben" heißt „Excel-Export" — im Board und im Verwaltungsbereich. Die Datei war schon vorher auf Excel ausgelegt (Semikolon, Byte-Reihenfolge-Marke); nur der Knopf sagte es nicht.
- digi: „Status" heißt durchgängig „Prozessschritt" — Spalte, Filter, Hilfetexte und die Kopfzeile der Excel-Ausgabe. Eine Spalte, die in der Datei anders heißt als auf dem Schirm, kostet beim nächsten Abgleich mehr Zeit als die Umbenennung gespart hat.
- digi: Die Suchvorschläge nennen auf der Gesamtsicht ihr Board. Auf einem einzelnen Board waren sie immer schon darauf beschränkt; über alle Boards hinweg sah ein richtiger Treffer aus einem anderen Board wie ein Fehltreffer aus. Dabei kam eine zweite, tote Fassung derselben Bedienung zum Vorschein (
app.js): Sie suchte ihre Liste über einlist-Attribut, das die Vorlage nie setzt, und stieg deshalb bei jedem Aufruf still wieder aus. Wer den Fehler suchte, fand zuerst die tote — sie ist entfernt. - digi: Die Lupe im Suchfeld lag über der Eingabe. Sie war das Schriftzeichen „⌕", das in den geometrischen Ersatzschriften fehlt; was einsprang, war breiter als der eingeplante Platz. Jetzt ein Symbol mit fester Größe.
- digi: Der Prozessschritt hebt sich in der Liste ab. „Schritt 3/6" stand im selben blassen Grau wie der Statusname daneben — beim Überfliegen verschwand damit genau das, wofür die Spalte da ist.
- digi: Dringlichkeit farbig — aber nur dort, wo es drängt. „Hoch" und „Kritisch" bekommen eine Marke, alles andere bleibt Text; färbte man jede Stufe, wäre die Spalte eine Ampelwand, in der nichts heraussticht. Sortiert wird nach Dringlichkeit statt alphabetisch.
- digi: „Meine Anliegen" hat einen Filter — Prozessschritt, Bereich und die Umschaltung alle/aktiv/archiviert. Zur Auswahl steht nur, was in den eigenen Anliegen auch vorkommt: Ein Filter mit zwölf Werten, von denen zwei belegt sind, lässt zehnmal ins Leere greifen.
- digi: Der Einstieg erklärt die drei Anliegenarten und weist darauf hin, dass akute Störungen weiterhin über die bekannten Supportwege laufen. Der Hinweis steht über den Kacheln: Wer eine Störung hat, soll es lesen, bevor er ein Formular ausfüllt, das ihm gerade nicht hilft.
- digi: Jedes Einreichformular erklärt, was in seine Anliegenart gehört. Alle diese Texte sind über die Einstellungen pflegbar (Gruppe „Anliegen: Texte der Einreichung") — die Fachseite formuliert, nicht die Programmierung, und sie soll es ohne Auslieferung ändern können.
Zwei Dinge stehen bewusst nicht darin. Die Entwürfe im Testplan zeigen eine Stufe über dem Prozessschritt („EINGANG", „UMSETZUNG"); ein solches Konzept gibt es weder im Neubau noch im Altportal — welche Prozessschritte zu welcher Stufe gehören, ist eine fachliche Entscheidung und keine Programmieraufgabe. Und die ausführlichen Texte sollten aus dem Digitalportal kommen; das wird abgelöst, deshalb ist dorthin kein Verweis gebaut — ein Testfall bewacht das. Die mitgelieferten Texte sind ein Entwurf und gehören fachlich gegengelesen.
[2.0.2] — 2026-08-04
Registrierungs- und Anmeldestrecke geprüft. Beide tragen — der eine Befund ist klein, seine Fehlerklasse nicht.
- core: Die Bestätigungsseite nennt ihr Formularziel. Sie war die einzige von 53 Vorlagen mit leerem
action. Das funktioniert — ein leeres Ziel sendet an die aufgerufene Adresse — und ist trotzdem genau das Muster, das bei Fläche 6 einen halben Tag gekostet hat: Ein Ziel, das sich aus dem aktuellen Pfad ergibt, verliert stillschweigend, was in der Adresse steht. Die Vorlage bedient zwei Strecken (bestätigen und fortsetzen); jede übergibt jetzt ihre eigene Adresse. - Zwei Fälle laufen die Strecken mit den Adressen ab, die die Seite ausliefert (
RegistrierungswegAusDerSeiteTest,AnmeldewegAusDerSeiteTest). Die vorhandenen Fälle prüfen die Strecken inhaltlich dicht, posten aber an selbst gebaute Adressen — ein Formular, das ins Leere zeigt, bliebe damit unbemerkt. Der Unterschied ist klein und entscheidend: Ein Fall, der die Adresse selbst baut, belegt nicht, dass die Seite sie baut. - Der Prüflauf selbst hat zwei Lehren geliefert, beide als Kommentar festgehalten: Eine fehlgeschlagene Formularprüfung leitet zurück auf dieselbe Seite —
assertRedirectauf die Etappenadresse ist dann auch bei Ablehnung erfüllt, es brauchtassertSessionHasNoErrors(). Und wer mehrere Formulare nur am CSRF-Feld sucht, trifft das erste beliebige: Auf der Startseite ist das die Inline-Hilfe, nicht das Abmelden.
Nicht verändert, weil in Ordnung: Ungültige und verbrauchte Links aus Mails zeigen auf beiden Landeseiten eine Erklärung samt Weg nach vorn statt eines Formulars, und /login/2fa ohne Wartezustand führt zurück zur Anmeldung.
[2.0.1] — 2026-08-03
Abfragelast. Keine Fläche ändert sich, keine Zahl auf dem Bildschirm wird eine andere — die Seiten kommen nur mit deutlich weniger Datenbankabfragen zustande. Gemessen an denselben Seiten, vorher und nachher:
| Seite | vorher | nachher | |---|---|---| | /start | 65 | 19 | | /profil | 69 | 11 | | /admin/konten | 76 | 13 | | /admin/rollen | 66 | 7 | | /admin/freigaben | 68 | 8 | | /admin/pruefspur | 68 | 9 |
Dass gerade der portaleigene Verwaltungsbereich so deutlich gewinnt, ist kein Zufall: Er prüft feiner. Jede Liste, jede Spalte, jede Zeilenaktion fragt nach einem Recht — und jede dieser Fragen las bisher die Rollen des angemeldeten Kontos neu aus der Datenbank.
- core: Die Rechteauflösung liest die Rollen einmal je Aufruf statt bei jeder Prüfung. Das war der ganze Unterschied. Keine einzelne Aufrufstelle sah falsch aus; der Fehler war nirgends, er war in der Summe. Wer Rollen schreibt, verwirft den Zwischenspeicher;
UserRoletut das über Modellereignisse von selbst. Die beiden Wege, die daran vorbeigehen —upsert()und die Massenlöschung — leeren ihn ausdrücklich, weil der Query-Builder keine Modellereignisse auslöst. - core: Die Einstellungen kommen in einer Abfrage statt einer je Schlüssel.
- core:
Schema::hasTable()fragt nicht mehr bei jedem Seitenaufbau nach. Der Aufruf sieht billig aus, fragt aber jedes Malpg_class. Gemerkt wird nur das Ja (App\Support\Schemapruefung): Eine Tabelle, die es gibt, verschwindet im laufenden Prozess nicht — eine, die es noch nicht gibt, kann währendmigrateentstehen, und ein gemerktes Nein würde die Einrichtung still auf die Notfallwerte zurückwerfen. - core: Die Zählwerke der Kopfzeile laufen einmal statt zweimal. Kopfleiste und Kopf-rechts bauen beide die Kopfzeile. Der Zwischenspeicher hängt am Request-Objekt und nicht nur am Dienst — der Dienst ist ein Singleton und überlebt in Testläufen mehrere Aufrufe hintereinander.
- deploy: Die Auslieferung legt den Zwischenspeicher wieder an. Sie räumte ihn bisher nur weg (
optimize:clear) und rief nieoptimize— jeder Aufruf las danach alle Dateien ausconfig/und baute die Routentabelle neu. Kalt gemessen: 144 ms gegen 122 ms je Aufruf. Der Schritt läuft nachmigrate, damit eine gescheiterte Migration nicht mit einer halb passenden Konfiguration im Zwischenspeicher endet. - core: Zwei
env()-Aufrufe außerhalb vonconfig/entfernt (Pfeffer der Datenübernahme). Sie waren ohnehin unerreichbar — der Standard ist'', nichtnull, also griff das??nie — und wären mit zwischengespeicherter Konfiguration still leer gewesen, weil.envdann gar nicht mehr gelesen wird. - Ein Testfall bewacht das Ergebnis (
AbfragelastTest): Keine Abfrage darf sich beim Aufbau einer Seite wiederholen, die Rollen werden genau einmal gelesen, und eine abgelehnte Seite kostet höchstens vier Abfragen. Ein Zwischenspeicher, den niemand bewacht, verschwindet beim nächsten Umbau — und der Rückfall fällt nicht auf, weil die Seite weiterhin das Richtige anzeigt, nur langsamer.
[2.0.0] — 2026-08-03
Die Fremdoberfläche ist weg. app/Filament/ gibt es nicht mehr, filament/filament ist aus composer.json entfernt, und der Verwaltungsbereich läuft vollständig portaleigen — in derselben Hülle wie das übrige Portal, mit derselben Kopfleiste, Seitenleiste und Arbeitslisten-Mechanik.
- core: Der zweite Faktor fehlte vor der Verwaltung. Das Step-up-Gate hing an der Middleware der Fremdoberfläche; die portaleigenen Verwaltungsrouten liefen seit der ersten abgelösten Fläche ohne ihn. Wer angemeldet war und ein Verwaltungsrecht hatte, kam ohne Anmelde-Code hinein. Behoben — alle
/admin-Routen tragen jetztzweifaktor. - core: Die gelockerte Inhaltsrichtlinie ist entfallen.
unsafe-evalwar der Preis für Alpine in der Fremdoberfläche. Der Verwaltungsbereich trägt jetzt dieselbe strenge Richtlinie wie das Portal. - verwaltung:
/administ ein Weg, kein Ort. Der Pfad führt zur ersten Fläche, die diese Person sehen darf, statt auf eine Startseite, die ein Recht verlangen müsste. - verwaltung: Die Betriebsübersicht ist portaleigen — als Liste unter „Betrieb" statt als Kachelwand. Jede Zeile hängt weiterhin an ihrem eigenen Recht.
- core: Elf Pakete weniger. Mit Filament sind auch Livewire, die Blade-Icons und acht weitere Abhängigkeiten entfallen.
[1.8.0] — 2026-08-03
Ablösung der Fremdoberfläche, siebter Teil. In app/Filament/ liegt keine Arbeitsfläche mehr — nur noch Widget, Einstieg und Infrastruktur.
- digi: Priorisierung, Sprintplanung und Sprintboard sind portaleigen. Aus drei Seiten wurden acht Flächen; die Sprints haben jetzt eine eigene Liste mit Inhalt, Punktsumme und Fortschritt je Sprint.
- digi: Die Spalte „Rang" zeigte immer „—". Sie las
backlog_rank, ein Feld, das es nie gab — die einzige Zahl, um die es in der Priorisierung geht. Der Fehler stammt aus der Fremdoberfläche und ist niemandem aufgefallen. - digi: Die Arbeitsstufen des Sprintboards stehen als Reiter statt als Spalten zum Ziehen. Der aktive Reiter steht in der Adresse: verlinkbar, mit dem Zurück-Knopf bedienbar, mit der Tastatur erreichbar.
- digi: Sprints pflegt man an einem Sprint. Vorher waren es drei Fenster am Kopf der Planungstabelle, und das Bearbeiten lief über eine Klappliste, die beim Wechseln die Felder nachlud — ohne JavaScript wirkungslos.
- digi: „Wartet auf etwas" verlangt jetzt einen Grund. Ein Vermerk ohne Inhalt beantwortet die einzige Frage nicht, die dazu kommt.
- digi: Drei Portaladressen leiteten nur auf die Fremdoberfläche um —
/digi/planung,/digi/sprints,/digi/sprintboard. Sie sind entfallen; das Modul-Menü zeigt direkt auf die portaleigenen Flächen.
[1.7.0] — 2026-08-03
Ablösung der Fremdoberfläche, sechster Teil. In app/Filament/ liegen noch drei Flächen.
- verwaltung: Der Rollen-Editor ist portaleigen. Aus vier Dateien wurden zwei Flächen: die Rollenliste und ein Editor, der anlegt oder bearbeitet, je nachdem ob eine Kennung in der Adresse steht.
- verwaltung: Ein Menüpunkt stand doppelt. „Benutzerverwaltung" war von Hand in die Seitenleiste eingetragen und kam zugleich aus dem Register — einmal oben, einmal in der Gruppe „Konten". Ein Testfall hielt das fest, statt es zu melden.
- verwaltung: Listen unter „Konfiguration" hatten keinen Menüpunkt. Die Seitenleiste las dort nur das Formularregister; der Rollen-Editor ist die erste Liste in dieser Sektion und wäre unerreichbar geblieben.
- verwaltung: Jedes Recht trägt seine Erklärung im Kästchen. Die Fremdoberfläche hatte je Kästchen eine eigene Beschreibungszeile; portaleigen steht sie in der Beschriftung. Ein technischer Name allein sagt niemandem, was er bewirkt.
[1.6.0] — 2026-08-03
Ablösung der Fremdoberfläche, fünfter Teil. In app/Filament/ liegen noch vier Flächen.
- verwaltung: Die Benutzerverwaltung ist portaleigen, samt aller sechzehn Aktionen. Sie zerfällt in vier Flächen: die Kontenliste, ein Datenblatt am Konto (Zustand, Konto, Stammdaten, Rollen, Bereiche, Aufbewahrung als durchsuchbare Zeilen), eine Entscheidungsfläche mit acht Reitern und die Sammelsperre.
- verwaltung: Ansehen und Entscheiden hängen jetzt an getrennten Adressen. Das Datenblatt verlangt
users.view, das Entscheidenusers.manage, der Prüfreiterusers.review. Vorher lagen alle drei auf einer Seite, und das schwächste Recht öffnete sie. - verwaltung: Die Zuständigkeitsbereiche werden je Art gesetzt statt über eine Liste von Zeilen. Eine entfernte Zeile musste vorher gesondert abgeräumt werden — wurde sie es nicht, blieb die Einschränkung bestehen, während die Oberfläche sie nicht mehr anzeigte.
- verwaltung: Zwei Verweise auf die Konto-Detailseite sind nachgezogen — die Zeilenaktion „Prüfen" der Freigaben und die Kachel des Betriebs-Widgets zeigten auf
/admin/konten/{kennung}, die Adresse der Fremdoberfläche. - verwaltung: Die Sammelsperre nennt vorher jedes Konto beim Namen und sagt, welche sie auslässt: das eigene und die letzte aktive Verwaltung. Vorher meldete sie hinterher „12 Konten geändert" und verschwieg die übersprungenen.
[1.5.0] — 2026-08-03
Ablösung der Fremdoberfläche, vierter Teil. In app/Filament/ liegen noch fünf Flächen.
- verwaltung: Ein Formular am Datensatz verlor beim Absenden seinen Datensatz. Das gerenderte Ziel hiess
…/digi-steuerungstatt…/digi-steuerung?kennung=X; gespeichert wurde nichts, gemeldet wurde „gibt es nicht mehr", und jede Aktion antwortete mit 404. Betroffen war alles, was über?kennung=läuft — die Vorgangssteuerung und das Berichtigen des Inhalts waren im Browser unbenutzbar, obwohl die Abnahme grün war: Sie hängte die Kennung selbst an die Adresse und prüfte damit den Dienst, nicht den Weg. - verwaltung: Neue Feldart
verweise. Eine Fläche am Datensatz muss auf Zugehöriges zeigen können — eingereichte Nachweise, eine Vorlage, die den Text vorfüllt. Als umrandete Verweise und nicht als Knöpfe: Ein Bedienelement, das die Seite neu lädt, um ein Feld zu füllen, sendet sich selbst ab (WCAG 3.2.2). - akkreditierung: Die Anträge sind portaleigen, samt aller acht Aktionen. Aus fünf Fenstern über einer Tabelle wurden drei Flächen am Datensatz: der Antrag selbst (Status, Vermerk, Nachweise, Ausweis erstellen und einziehen), die Nachricht und die Sammelaktion. Wer über einen Antrag entscheidet, sieht dabei, worüber er entscheidet.
- akkreditierung: Die Sammelaktion zeigt jetzt vorher, wen sie anfasst. Der Fachdienst sah das von Anfang an vor — „erst einteilen und zeigen, dann ausführen" —, die Fremdoberfläche meldete es aber erst hinterher. Wer zwanzig Anträge markiert, liest die Wirkung sonst am Posteingang der Empfänger ab, und dort ist sie nicht zurückzuholen. Jeder Eintrag ist ein Verweis auf seinen Antrag, samt Grund für das Überspringen.
- akkreditierung: Die Vorlage einer Nachricht kommt ohne JavaScript hinein. Vorher war es ein Feld, das beim Ändern Betreff und Text nachlud; jetzt ist jede Vorlage ein Verweis auf dieselbe Fläche. Was danach im Feld steht, hat ein Mensch gesehen.
- akkreditierung: Zwei Verweise führten in die Liste statt zum Antrag. Die Erinnerung an überfällige Anträge und der Verweis in den Modul-Mails suchten den Antrag über
?tableSearch=— eine Schreibweise der Fremdoberfläche, die portaleigen nichts gefunden hätte. Dasselbe galt für den Filter der Aufgaben-Kachel. - akkreditierung: Die CSV-Ausfuhr folgt jetzt den eingestellten Filtern. Vorher lieferte sie einen eigenen Spaltensatz aus einem eigenen Dienst; der ist entfallen. Eine Ausfuhr, die etwas anderes enthält als die Liste darüber, fällt erst auf, wenn jemand mit der Datei weiterarbeitet.
[1.4.0] — 2026-08-03
Ablösung der Fremdoberfläche, dritter Teil. In app/Filament/ liegen noch sechs Flächen.
- verwaltung: Selbstprüfung portaleigen. Der Schlüssel
selbstpruefungblieb erhalten — die Kopfzeile führt unter „System & Protokolle" genau dorthin, und ein neuer Name hätte den am häufigsten benutzten Weg gekappt. Sortiert wird über einen Rang statt über das Statuswort: Die Frage lautet nie „was ist in Ordnung", sondern „was nicht". - akkreditierung: Vor-Ort-Nachpflegen portaleigen. Die Felder für Name und Ort einer Veranstaltung stehen jetzt immer da statt sich ein- und auszublenden — eine Sichtbarkeitsregel zwischen Feldern braucht JavaScript und wäre ohne es eine Falle.
- digi: Das Anliegen-Board ist portaleigen, samt aller sechs Aktionen. Steuern und Inhalt berichtigen sind Flächen am Vorgang geworden: Wer über Status und Zuständigkeit entscheidet, sieht dabei, worüber er entscheidet. Verschieben, Archivieren und Löschen hängen als Aktionen daran.
- digi: Der Vorgangs-Link in internen Mails zeigte ins Leere — auf die Adresse der Fremdoberfläche. Es ist die dritte Adresse, die dieser Link hatte; er nutzt jetzt die benannte Route, sodass ein Umbenennen einen Fehler wirft statt eine Mail zu verschicken, die niemanden weiterbringt.
- digi: Ein Feld, das nicht mitkam, ist unverändert — nicht geleert. Beim Berichtigen eines Vorgangs hätte ein unvollständiger Absender sonst die halbe Beschreibung geleert, und im Verlauf stünde eine Änderung, die niemand vorgenommen hat.
[1.3.0] — 2026-08-03
- core: Fußzeile nach dem Vorbild des Altportals. Ihr fehlten der Namensvorspann und der Verweis auf die Änderungen. Neu steht dort
<Portalname> · <Betreiber>und am Ende der Changelog mit der laufenden Version. Die Hilfe-Adresse und das Telefon bleiben, wo sie waren — sie stehen im Original nicht in der Fußzeile, sind aber genau das, was jemand sucht, der nicht weiterweiß (Konzept 13). - core: Der Betreiber kommt aus der Konfiguration, nicht aus der Vorlage.
PORTAL_BETREIBERwar vorgesehen und nirgends gesetzt; im Altportal stand „Bayerischer Turnverband" fest im Layout. Eine Zweitinstallation hätte damit den falschen Verband in der Fußzeile geführt. - core: Impressum und Datenschutz folgen jetzt auch in der Fußzeile der zentral gepflegten Adresse. Ist eine hinterlegt, verweist die Fußzeile dorthin und sagt an, dass ein neuer Tab aufgeht; sonst auf den eigenen Text. Vorher zeigte sie immer auf die eigene Seite — zwei Rechtstexte, von denen einer veraltet.
- core:
/changelogals Seite. Sie rendertCHANGELOG.mdselbst, ohne Markdown-Bibliothek und ohne rohes HTML durchzulassen: Überschriften, Listen, Absätze,codeund Fettes — mehr braucht ein Änderungsprotokoll nicht, und alles andere wäre eine Einlassstelle für fremdes Markup. - core: Die Fußzeile steht jetzt auch unter den verbliebenen Flächen der Fremdoberfläche. Sie hatte dort gar keine — wer in der Verwaltung landete, verlor Impressum und Datenschutz.
- core: Erklärung zur Barrierefreiheit auf dem Stand dieser Anwendung. Vorher stand dort ein Platzhalter. Sie nennt nach BITV 2.0, was umgesetzt ist — Bedienung ohne Maus und ohne JavaScript, sichtbarer Fokus, Farbe nie als einzige Auskunft, Kontraste ab 4,5:1 — und ebenso, was nicht barrierefrei ist: die erzeugten PDF-Dateien und die Teile des Verwaltungsbereichs, die noch auf der Fremdkomponente laufen. Eine Erklärung, die nur aufzählt, was gut ist, hilft bei der Entscheidung nicht weiter, ob jemand das Portal benutzen kann.
- core: Längere Rechtstexte liegen als Datei unter
resources/rechtstexte/. Mehrere Seiten HTML als String-Literal in der Inhalts-Registry wären unlesbar, und jede Fortschreibung ginge in maskierten Anführungszeichen unter. Die Vorlage nennt keinen Auftraggeber: Betreiber, Adresse und Rückmeldeweg setzt sie aus der Konfiguration ein. Sonst trüge eine Zweitinstallation den falschen Verband in ihrer eigenen Barrierefreiheitserklärung.
[1.2.0] — 2026-08-02
Ablösung der Fremdoberfläche, zweiter Teil — Stand 23 von 34 Flächen.
- verwaltung: Bestand der Mitgliederverwaltung, Prüfmaske und Kennzahlen sind portaleigen. Damit liegen die drei Kern-Sichten der Anbindung in derselben Hülle wie das übrige Portal.
- verwaltung: Das Listen-Gerüst kann Unterreiter und einen Zeitraum. Manche Flächen beantworten ihre Frage nicht mit einer Tabelle, sondern mit dreien; Suche, Sortierung und Blättern beziehen sich aber immer auf eine.
- verwaltung: Neue Feldart
auswahlliste. In einer Klappliste ist immer etwas ausgewählt, auch wenn niemand gewählt hat — wer absendet, bestätigt dann den ersten Eintrag. Bei einer mehrdeutigen Zuordnung ist genau das der Fehler, um den es geht. - verwaltung: „Angaben anfordern" war unbenutzbar. Die Aktion las ihren Text aus der Anfrage, in der nie einer stand: Eine Zeilenaktion ist ein Knopf ohne Feld. Jetzt eine eigene Fläche — was Eingaben braucht, braucht ein Formular.
- core: Die versprochene Sicherheitsabfrage vor folgenschweren Aktionen kam nie.
data-rueckfragestand im Markup, ausgewertet hat es kein Skript.
[1.1.0] — 2026-08-02
Ablösung der Fremdoberfläche, erster Teil (Variante C: ersetzen statt angleichen). Anlass war die Optik — dieselbe Aufgabe sah in zwei Anwendungen verschieden aus.
- verwaltung: Listen- und Formular-Gerüst portaleigen. Eine Beschreibung je Fläche, die Mechanik einmal für alle: Filter, Sortierung, Blättern, Ausfuhr, Rechte. Dreißig handgeschriebene Listen wären nach der zehnten auseinandergelaufen.
- verwaltung: 20 Flächen abgelöst — Prüfspur, Mail-Protokoll, Job-Läufe, der komplette Einstellungsblock, Freigaben, Rollen-Bestätigungen, das Newsletter-Modul und die Akkreditierungs-Veranstaltungen.
- kern: Volle Breite für Tabellen, gestaltete Filterleiste, ein Regelwerk fürs Stapeln auf schmalen Geräten.
- digi: Board und Detailseite nach dem Vorbild des Altportals.
[1.0.0] — 2026-08-01
Der Neubau geht auf dev.btv-portal.de in Betrieb.
- Datenübernahme aus dem Altsystem durchgeführt und gegen die Quelle geprüft — 17 Tabellen, 0 Abweichungen. Verschlüsselte Spalten werden umgeschlüsselt, nicht kopiert.
- sso: Interne Anmeldung über Entra ID.
- oberflaeche: Portal-Schale, Marken-Assets und Kacheln nach dem Vorbild des Altportals — der Kern trägt keine Farbe, ein Austausch der Marke reicht.
- Alle 26 Abnahme-Befunde geschlossen, Funktionsabgleich Modul für Modul. Der Leitbefund: Über zwanzigmal war der Fachdienst gebaut und es gab keinen Weg dorthin. Wer den Neubau prüft, prüft die Wege, nicht die Klassen.
- Prüfstand gegen das Altsystem: 20 Aspekte, 163 Fälle, 0 unerklärte Unterschiede.
- Optimierungen O001–O100 gegen den Neubau triagiert und eingebaut.
[0.9.0] — 2026-07-31
Der Neubau entsteht in fünf Phasen — Laravel 13, PostgreSQL 17, PHP 8.5.
- Phase 1: Fundament. Entscheidungen A1–A11, Konventionen, 52 Portal-Tabellen gegen PostgreSQL migriert.
- Phase 2: Fachlogik in sechs Paketen. Geheimnisspeicher, Rechte-Auflösung, Prüfspur, TOTP und zweiter Faktor, Passwörter, Anmeldebremse, Sitzungshärtung.
- Phase 3: Oberfläche. Anmeldung, Registrierung in sechs wiederaufnehmbaren Etappen, Profil, Startseite, Hilfe.
- Phase 4: Datenübernahme, wiederholbar und mit Bericht.
- Phase 5: Fachliche Abnahme automatisiert.
- Fachmodule: Anbindung an die Mitgliederverwaltung, Akkreditierung, Anliegen, Newsletter.
Die 545 Testfälle des Originals waren dabei die Spezifikation. Aufgefallen sind 29 Fehler des Originals, mehrere davon im Betrieb.