Stand 27.10.2026 21:52
01. Einführung und Ziele
Aufgabenstellung
Das RAL Gütezeichen Anhörungsportal (CAF.Applications.RAL.QualityMarks.HearingPortal) bildet
das Anhörungsverfahren für RAL-Gütezeichen digital ab: Ein Verfahren wird angelegt, Institutionen
und deren Kontakte werden als Teilnehmer aufgenommen, Unterlagen werden zusammengestellt und nach
Vier-Augen-Freigabe versendet, Teilnehmer geben über die Benutzerkonten ihrer Institution
Stellungnahmen ab (RAL legt je Institution dedizierte Konten an, mehrere Benutzerkonten pro
Institution — feste Bindung gemäß RAL-QM-HP-31), das Verfahren wird intern beantwortet,
beschieden und schließlich abgeschlossen und archiviert. Der Lebenszyklus verzweigt je nach
gewählter Abschlussvariante (US-33):
Draft → PendingApproval → Approved → Dispatched → Adjudication → Completed (zweistufig)
Draft → PendingApproval → Approved → Dispatched ─────────────→ Completed (einstufig)
└────────────────────── benannte Rücksprünge/Abbruch nach Fachregel ──────────────────────┘
Bei der einstufigen Variante entfällt der eigene Adjudication-Status: Bescheidung und
Endfassung gehen in einem Vorgang hinaus. Details zur Wahl der Variante stehen in
Laufzeitsicht.
Die Anwendung ist Teil des CAF-Monorepos: eines modularen ABP-/.NET-10-Monolithen mit
wiederverwendbaren, anwendungsneutralen Bausteinen (CAF.Modules.Authentication,
CAF.Modules.Documents[.Contracts], CAF.Modules.UI.Blazor) und der einzigen aktuell
existierenden Anwendung, dem Anhörungsportal, unter applications/RAL/QualityMarks/HearingPortal/src/.
Das Portal ist damit gleichzeitig Referenzanwendung für die No-Layer-Architektur des Monorepos und
Träger der eigentlichen Fachlogik. Details zu Modulschnitt und Abhängigkeitsrichtung stehen im
Bausteinsicht; die noch offenen Bereiche und ihre Nachweislücken benennt
Risiken und technische Schulden.
Wesentliche fachliche Ziele
- Durchgängiger, nachvollziehbarer Anhörungsprozess: Von der Anlage über Vier-Augen-Freigabe, zuverlässigen Versand, Fristen/Erinnerungen, Stellungnahmen und internen Kritikdialog bis zu Bescheidung, Abschluss/Archiv oder kontrolliertem Abbruch — jeder Statuswechsel läuft über benannte Operationen, nie über einen frei setzbaren Status.
- Dedizierte Institutionskonten statt Linkzugang: RAL legt je Institution dedizierte
Benutzerkonten an — mehrere pro Institution (je Kontakt eines, korreliert über den stabilen
OIDC-
sub), keine Selbstregistrierung, kein anonym erreichbarer Link, kein Rückfallweg, sofort wirksamer Entzug (Bereich „Institutionszugang neu“, US-22/US-22a/US-22b/US-22c). Der frühere Gastlink ist durch RAL-QM-HP-31 ohne Zugriffsrecht stillgelegt; interne Rollen (Administrator, Referent, Geschäftsführung) erhalten nur die ihnen erlaubten Aktionen. - Verlässliche Institutions- und Kontaktverwaltung: Institutionen mit Anschrift, Kreis, Pflichtpartner-Kennzeichen und mehreren Kontakten pflegen, samt CSV-Import/-Export und geschütztem Löschen erst nach Nutzungsprüfung.
- Kontrollierte Kontoprovisionierung: Institutionskontakte und Mitarbeitende werden über explizite, auditierte Wege zu Keycloak-Konten und genau einer Produktrolle zugeordnet — ohne Dublettenkonten oder automatische Rollenvergabe.
- Betriebsfähigkeit ab Tag eins: Health-Endpunkte, PII-arme Kennzahlen mit Korrelationsverfolgung vom Versandfehler bis zur Nachricht, sowie ein bei jedem Push laufendes automatisches Qualitätsgate.
Qualitätsziele (Top-Prioritäten)
| Rang | Qualitätsziel | Motivation / Ausprägung |
|---|---|---|
| 1 | Sicherheit & Autorisierung | Jede geschützte Operation prüft Permission und Objektzugriff serverseitig; eine DocumentId, URL oder ein Dateiname verleiht nie Zugriff. Dokumentzugriffswege (intern und Institutionskonto; Gast- und Direkt-Share-Pfade sind im Host gesperrt) revalidieren bei jedem Zugriff neu; ein versteckter Button ist keine Autorisierung. |
| 2 | Nachvollziehbarkeit & Integrität des Verfahrens | Freigabe erzwingt eine andere handelnde Person als die Einreichung, sperrt die geprüfte Zusammensetzung über eine Kompositionsprüfsumme; Versand läuft über eine persistente Outbox mit Idempotency Keys statt „best effort“; eine PII-arme fachliche Historie ergänzt das ABP-Audit-Log. |
| 3 | Modularität & Wartbarkeit | No-Layer-Architektur mit klaren, architekturtestgesicherten Modulgrenzen (Contracts/Runtime/Blazor je Feature); CAF.Modules.* bleiben anwendungsneutral und dürfen nie von der Anwendung abhängen; Cross-Module-Referenzen laufen ausschließlich über IDs und Contracts, nie über fremde Entities oder Tabellen. |
| 4 | Verifizierbarkeit / Testtiefe | Fach-, Komponenten- und SQL-Server-Tests belegen die Funktionen. Echte Browserprüfungen sind optional und standardmäßig aus; fehlende Browsernachweise werden benannt. Das automatische Qualitätsgate blockiert Pushes bei roten oder übersprungenen Pflichtprüfungen und ausstehenden EF-Modelländerungen. |
| 5 | Bedienbarkeit & Barrierefreiheit | Einheitliche Cohesion-Oberfläche auf Deutsch, WCAG 2.1 AA (axe, serious/critical als Fehler) über alle Fach- und Portalseiten, responsive und tastaturbedienbar; Datenseiten behandeln Loading/Empty/Error/Forbidden/Validation/Saving/Stale-Concurrency konsistent. |
Diese Rangfolge steuert Zielkonflikte: Sicherheits- und Integritätsanforderungen sind nicht verhandelbar und gehen im Zweifel vor Bedienkomfort oder Implementierungsaufwand. Die geforderte Nachweistiefe je Änderungsart steht im Entwicklungsleitfaden §15.1; Qualitätsszenarien mit konkreten Ereignis/Antwort-Paaren stehen im Qualitätsanforderungen.
Stakeholder-Überblick
| Rolle | Erwartungshaltung |
|---|---|
| Interne Benutzer (Administrator, Referent, Geschäftsführung) | Verfahren anlegen, bearbeiten, freigeben, versenden, bescheiden, abschließen oder abbrechen — jeweils nur mit den ihrer Rolle zugewiesenen Rechten; Administrator und Geschäftsführung dürfen zusätzlich laufende Verfahren abbrechen. |
| Externe Teilnehmer (Institutionskontakte) | Über ihr persönliches, von RAL angelegtes Benutzerkonto ihrer Institution (/portal/zugang-uebernehmen; mehrere Konten je Institution) fristgerecht Stellungnahmen abgeben, eigene Unterlagen einsehen/herunterladen und interne Antworten auf die eigene Kritik sehen — ohne Einblick in fremde Teilnehmerdaten. |
| Fachadministration / Mitarbeitendenkonten-Verwalter | Mitarbeitende über /administration/mitarbeitendenkonten kontrolliert anlegen, genau eine Produktrolle zuweisen, wiedereinladen sowie app-lokal sperren/entsperren. |
| Betrieb | Lokalen Stack (SQL Server, Keycloak, Mailpit) über doctor.cmd/setup.cmd/start.cmd reproduzierbar betreiben; Gesundheitszustand über /health/live und /health/ready, Versand-/Fristenprobleme über PII-freie .NET-Kennzahlen mit Korrelationskennung verfolgen. |
| Entwicklungsteam | Modulgrenzen, No-Layer-Konventionen und das bei jedem Push laufende Qualitätsgate einhalten; verbindliche Regeln stehen im Entwicklungsleitfaden und in conventions/. |
| Keycloak (technischer Stakeholder) | Alleiniger OIDC-Token-Issuer und Identitätsquelle; die Anwendung selbst betreibt keinen lokalen OpenIddict-Server. |
Weiterführend: Randbedingungen, Kontextabgrenzung, Lösungsstrategie sowie die Betriebs- und Startpfade in ../GETTING-STARTED.md und im Portal-README.
02. Randbedingungen
Dieses Kapitel fasst die Vorgaben zusammen, innerhalb derer Architektur- und Implementierungs-
entscheidungen getroffen werden. Sie sind größtenteils verbindlich gesetzt (Technologie-,
Team- und Prozessvorgaben) und nicht das Ergebnis einer freien Architekturwahl. Details zu Ownership
und Modulschnitt stehen im Entwicklungsleitfaden; Begründungen je
Einzelkonvention in docs/conventions-decisions.md.
1. Technische Randbedingungen
| Bereich | Vorgabe | Bindend seit |
|---|---|---|
| Runtime/Sprache | .NET 10, C# mit Nullable enable |
Projektstart |
| Anwendungsarchitektur | ABP Single-Layer-/No-Layer-Template — bewusst kein klassisches 8-Projekt-Layering (Domain.Shared/Domain/Application.Contracts/…); ein Feature besteht aus {Feature}.Contracts + Runtime, optional .Blazor |
ABP-Vorgabe, siehe AGENTS.md |
| UI-Technologie | Blazor Server, ausschließlich InteractiveServer (kein WebAssembly, kein @rendermode in Feature-Code) |
Architekturtest-erzwungen |
| UI-Komponentenbibliothek | Cohesion (Syncfusion-Basis) ist verpflichtend für jede CAF-/GZ-Oberfläche; MudBlazor/Syncfusion/Blazorise dürfen im Anwendungscode nicht direkt gerendert werden. Ausnahme: allein die MVC-Razor-Pages unter /Account/** auf dem LeptonX-MVC-Theme. Blazor-seitig wird keine Vendor-Komponente gerendert; Blazorise kommt transitiv ueber ABPs Blazor-Theming-Paket mit und wird im Bundle wieder entfernt |
AGENTS.md Abschnitt „Architektur der Benutzeroberfläche" |
| Persistenz | EF Core, SQL Server als einziger Provider; PascalCase-Tabellennamen mit Owner-Präfix (RALQM…, CAF…); ein Modul besitzt seine Entities und Configure{Feature}()-Erweiterung, der Host bleibt Migration Host |
DEVELOPMENT-GUIDE.md Abschnitt 9 |
| Authentifizierung/Autorisierung | Keycloak als OIDC-Server via OpenIddict-Client-Integration (CAF.Modules.Authentication); ABP Identity/Permission Management führt lokale Benutzer, Rollen und Permissions. Kein lokaler OpenIddict-Server, kein Feature Management ohne nachgewiesenen Bedarf |
AGENTS.md |
| Nicht zugelassene Infrastruktur | PostgreSQL, Redis, RabbitMQ, Kafka, Hangfire, Elsa, GraphQL, DMS oder Microservices ohne ausdrückliche Nutzerfreigabe und belegten Use Case | DEVELOPMENT-GUIDE.md Abschnitt 11/16 |
| Paketverwaltung | Central Package Management (Directory.Packages.props), packageSourceMapping in NuGet.Config (u. a. Cohesion exklusiv auf internem Feed) |
docs/conventions-decisions.md N-01/N-02 |
| Build-Qualität | TreatWarningsAsErrors=true plus .NET-Analyzer; Restore/Build/Test müssen mit null Warnings/null Errors durchlaufen |
DEVELOPMENT-GUIDE.md Abschnitt 15.2 |
Diese Vorgaben sind in Architekturtests kodifiziert (z. B. Verbot CAF.Modules.* →
CAF.Applications.RAL.QualityMarks.HearingPortal.*, InteractiveServer-only, Cohesion-only-UI) — sie werden nicht
gelockert, nur Pfad-Literale bei struktureller Umbenennung nachgezogen.
2. Organisatorische Randbedingungen
Sprache
- UI-Texte: Deutsch (Produktsprache), über
IStringLocalizer<T>und paritätische DE-/EN-Localization-JSON je owning Modul — keine hartkodierten UI- oder Business-Exception-Texte. - Code-Identifier und Kommentare: Englisch.
- Logs: strukturiert und Englisch (
ILogger<T>mit Templates, nie String-Interpolation, nie direkte Serilog-Referenz).
Diese Dreiteilung gilt repositoryweit, siehe conventions/baseline.md.
Konventionen und Entscheidungsprozess
- Themenspezifische Coding-Konventionen liegen in
conventions/(C#, EF Core, Blazor, ABP, Tests, Git, Security, PowerShell, CI/CD, MSBuild/NuGet) und sind bewusst knapp gehalten. - Die repo-spezifische Adopt/Reject-Entscheidung je Konvention — inklusive Vor-/Nachteil — steht in
docs/conventions-decisions.md; das ist die maßgebliche Quelle, welche geteilte Konvention hier tatsächlich gilt (z. B. explizite Typen stattvarund das StyleCop-Set sind bewusst abgelehnt,IClock/IGuidGenerator,ConcurrencyStampund die Security-Baseline sind übernommen). - Quellenpriorität bei Konflikten: aktuelle Benutzeranweisung → nächstgelegene
AGENTS.md→ repositoryweite Arbeitsgrundlage → aktuelle Architektur/Entwicklungsleitfaden. Nur dieses verlinkte Kernset gibt Repository-Regeln vor; Code und ausführbare Nachweise bestimmen den Implementierungsstand. - Strukturelle Änderungen (Modulgrenze, Sicherheit, Persistenz, Abhängigkeit, Betrieb) ziehen Architektur, Arbeitsgrundlage und durchsetzende Tests im selben Änderungssatz mit; es wird keine parallele Entscheidungsdokumentation gepflegt.
Git-Workflow
- Conventional Commits:
feat|fix|refactor|docs|test|chore(scope): subject, imperativ, Subject ≤ 50 Zeichen. mainist geschützt: kein Direct-Push, kein Force-Push; Änderungen ausschließlich per Merge Request mit Review.- Branch-Namen kebab-case (
feature/…,fix/…,chore/…), nach Merge gelöscht. - Betroffene Gates bei jedem Push: versionierte Git-Hooks (
tools/git-hooks, aktiviert übersetup.cmd) bestimmen aus allen gepushten Ref-Diffs und dem Projektgraphen die betroffenen Apps. Deren serverseitige Tests und übrige Pflichtschritte bleiben verbindlich. Browser-, axe-, Tastatur- und Browser-Berechtigungsprüfungen sind optional und standardmäßig aus, auch beim Push; reine Dokuänderungen prüfen Links und Reporting. Ein rotes, fehlendes oder zum falschen Commit gehörendes Ergebnis blockiert den Push. Der Commit prüft nur den gestageten Diff auf gesperrte Pfade, Secrets und Konfliktmarker.git push --no-verifyist eine dokumentierte Ausnahme, kein Arbeitsweg. Details:DEVELOPMENT-GUIDE.mdAbschnitt 15.2 undGETTING-STARTED.md.
Agenten als Mitwirkende
- Claude Code und Codex arbeiten nach denselben Quellen wie menschliche Entwickler; es gibt
bewusst kein tool-spezifisches Regel-Duplikat. Claude Code liest
CLAUDE.md, einen reinen Zeiger aufAGENTS.md; Codex liest diese Root-AGENTS.mddirekt, weil seine Projekt-Discovery im Repositorywurzelverzeichnis beginnt. - Jeder Implementierungs- oder Prüfagent liest vor einer Codeänderung die repositoryweite
Arbeitsgrundlage, die aktuelle Architektur, den Entwicklungsleitfaden und die nächstgelegene
AGENTS.md.
3. Namens- und Strukturkonventionen (Randbedingung für jede Erweiterung)
- Anwendungsspezifische persistierte Identifier tragen den Präfix RALQM (Tabellen
RALQMHearings/RALQMInstitutions, Error CodesRALQM.<Feature>:, Permission-GruppeRALQM, RollenRALQMAdministrator/RALQMCaseOfficer/RALQMManagement). - Technische Slugs bleiben lowercase (
ral-qualitymarks). - Wiederverwendbare CAF-Module behalten den
CAF-Präfix (CAFDocuments*). modules/*darf nicht von der Anwendung abhängen — durch Architekturtests erzwungen.- Umbenennungen sind stets datenerhaltend; historische EF-Migrationen behalten ihre alten Identifier bei.
Diese Randbedingungen sind Grundlage für die Lösungsstrategie und die Bausteinsicht; technische Details zu Setup und Betrieb stehen im Schnelleinstieg und im Entwicklungsleitfaden.
03. Kontextabgrenzung
Dieses Kapitel zieht die Systemgrenze um das eine fachliche Deployable
CAF.Applications.RAL.QualityMarks.HearingPortal (RAL Gütezeichen Anhörungsportal, „RALQM") und
benennt seine externen Nachbarn — fachlich (wer interagiert wozu) und technisch (über welche
Schnittstelle). Die Modul-interne Gliederung folgt in der Bausteinsicht;
die Begründung für „ein Deployable, eine Anwendungsdatenbank" steht in der
Lösungsstrategie.
3.1 Systemgrenze
Es gibt genau ein fachliches Anwendungs-Deployable: den RALQM-Host, eine ASP.NET-Core-/Blazor-
Web-App mit Interactive Server. Keycloak, SQL Server und der SMTP-Provider sind Infrastruktur —
keine weiteren GZ-Fachservices. Die Anwendung besitzt genau einen HearingPortalDbContext und
einen Migration-Host im Host-Projekt; Feature-Application-Services laufen im selben Prozess wie
die Blazor-UI (kein separater API-Tier). Details zum Ablauf eines Requests innerhalb der Grenze
stehen in der Laufzeitsicht.
flowchart TB
Staff["Interne Mitarbeitende\nAdministrator / CaseOfficer /\nManagement"] --> App
Guest["Externe Teilnehmer\nInstitutionskonten (mehrere\nBenutzerkonten je Institution)"] --> App
ShareRecipient["Empfänger eines direkten\nDokumentenlinks"] --> App
App["RALQM HearingPortal\nBlazor Web App (Interactive Server)"] <-->|"OIDC Code + PKCE"| Keycloak["Keycloak\nIdentity Provider"]
App -.->|"schmaler Admin-Port"| Keycloak
App --> GzDb[("RALQM-Anwendungs-\ndatenbank (SQL Server)")]
App --> Mail["SMTP-Provider\nlokal: Mailpit"]
Keycloak --> KcDb[("Keycloak-Datenbank\nSQL Server, separat")]
classDef system stroke-width:3px
class App system
Lokal liegen die RALQM- und die Keycloak-Datenbank auf derselben SQL-Server-Instanz; fachlich und
technisch bleiben es getrennte Datenbanken mit getrennten Principals (Keycloak-eigener Login vs.
dedizierter ralqm-Datenbankprincipal für die Anwendung).
3.2 Fachlicher Kontext
| Nachbar/Akteur | Rolle | Fachliche Interaktion |
|---|---|---|
Interne Mitarbeitende — Administrator (RALQMAdministrator) |
Verwaltungsrolle ohne Verfahrens- und Freigaberechte (seit RAL-QM-HP-18) | Stammdaten (Institutionen/Kontakte), Mitarbeitendenkonten und Institutionskonten, Wertelisten, Ablage, Vorlagen, Postausgang und Störungen; keine Fallarbeit im Anhörungsprozess |
Interne Mitarbeitende — Sachbearbeitung (RALQMCaseOfficer) |
vollständige Fallbearbeitung ohne Freigabe | Anhörungen anlegen/bearbeiten/einreichen/versenden, Institutionen/Kontakte pflegen, Dialog mit Teilnehmern, Bescheidungsübermittlung (Adjudicate) und Abschluss (Complete) nach RAL-QM-HP-46 Regel 1/O1 und RAL-QM-HP-51 O2 |
Interne Mitarbeitende — Geschäftsführung (RALQMManagement) |
Lesezugriff plus Vier-Augen-Entscheidungen | Freigabe (Approve) und Nachversand-Freigabe (Supplemental.Approve), dazu Abbruch laufender Verfahren; darf keine eigene Einreichung selbst freigeben; bescheidet und schließt nicht ab |
| Institutionsvertreter — Institutionskonto | angemeldeter Nutzer eines von RAL angelegten Benutzerkontos seiner Institution (mehrere Konten je Institution, je Kontakt eines; Einstieg /portal/zugang-uebernehmen, keine Selbstregistrierung) |
Konto übernehmen, Dokumente einer Anhörung einsehen, eigene Stellungnahme anlegen/ändern, sieht Meine Teilnahmen (nur die eigene Institution, US-22c) |
| Empfänger eines direkten Dokumentenlinks | anonymer Empfänger eines CAF-Share-Tokens | Download eines einzelnen freigegebenen Dokuments über ein befristetes, widerrufbares Secret; kein Ersatz für den Teilnahmezugang über das Institutionskonto |
| Keycloak | Identitätsquelle | authentifiziert alle Benutzer zentral; ABP projiziert lokale Benutzer/Rollen über den stabilen OIDC-sub |
Objektzugriff, Verfahrensstatus und Teilnehmerzuordnung werden zusätzlich je Feature geprüft; Details zu Rollen, Grants und den vier getrennten Dokument-Zugriffswegen stehen in den querschnittlichen Konzepten (Kapitel 8).
3.3 Technischer Kontext
| Nachbar | Schnittstelle/Protokoll | Zweck | Richtung |
|---|---|---|---|
| Endnutzer-Browser | HTTPS, Blazor-Interactive-Server-Circuit (SignalR) | UI-Rendering und Interaktion; JS-Interop nur nach interaktivem Rendern | eingehend |
| Keycloak (Login) | OIDC Authorization Code + PKCE über HTTPS | Authentifizierung, Token-Issuer für interne und kontogebundene externe Nutzer | bidirektional |
| Keycloak (Admin-API) | schmaler, kontrollierter Admin-Port (CAF.Modules.Authentication-Provisioning) |
kontrollierte Kontoprovisionierung für Mitarbeitende und Institutionskontakte; scheitert bei mehrdeutiger Identität geschlossen, vergibt nie automatisch eine Fachrolle | ausgehend |
| SQL Server — RALQM-Anwendungsdatenbank | Tabular Data Stream (ADO.NET/EF Core) | Persistenz über HearingPortalDbContext; Migrationen laufen ausschließlich im Host |
ausgehend |
| SQL Server — Keycloak-Datenbank | Tabular Data Stream | eigene Persistenz von Keycloak; lokal gleiche Instanz, getrennte Datenbank und Principals, keine GZ-Fachdaten | Keycloak-intern |
| SMTP-Provider | SMTP | Versand der Hearing-Outbox (Einladungen, Nachrichten je Verfahrensschritt) über ABP Emailing; lokal Mailpit als Development-Fänger | ausgehend |
| BLOB-Inhalt (Dokumente) | SQL-Server-BLOB-Provider (ABP BLOB Storing Database) | physischer Dateiinhalt liegt in derselben RALQM-Anwendungsdatenbank; keine zweite Dokumentablage | ausgehend |
Lokale Development-Endpunkte (siehe GETTING-STARTED):
Der Stack-Descriptor besitzt APP_PORT, KEYCLOAK_PORT (Realm ral),
MAILPIT_WEB_PORT, MAILPIT_SMTP_PORT und SQLSERVER_PORT; status.cmd zeigt
die wirksamen Adressen. Jeder Worktree-/Branch-Kontext hat eigene Endpunkte. Alle Compose-Ports
sind nur an Loopback gebunden (siehe
applications/RAL/QualityMarks/HearingPortal/etc/docker/development/docker-compose.yml);
Produktionsendpunkte
und -zugangsdaten werden außerhalb dieser lokalen Dateien betrieben.
3.4 Bewusst keine weiteren Nachbarn
Die Systemgrenze umfasst keinen zweiten Anwendungsservice, kein externes DMS, keine Microservice-Nachbarn und keine zweite GZ-Datenbank — ein neuer externer Nachbar braucht zuerst einen konkreten, getesteten Anwendungsfall. Details zu bewusst nicht vorhandener Infrastruktur stehen in den Randbedingungen.
04. Lösungsstrategie
Dieses Kapitel bündelt die grundlegenden Entscheidungen, die den Lösungsraum aufspannen und in allen Folgekapiteln als gesetzt vorausgesetzt werden. Die begründete Langform je Entscheidung steht in den Architekturentscheidungen; die Abwägung gegen externe Konventionsvorlagen in docs/conventions-decisions.md.
4.1 Modularer Monolith statt Microservices
Genau ein Deployable (CAF.Applications.RAL.QualityMarks.HearingPortal) und eine
Anwendungsdatenbank bilden die gesamte Lösung. Microservices, ein zweites GZ-Datenbankschema,
Message-Broker (RabbitMQ/Kafka) oder ein API-Gateway sind bewusst nicht Teil der Architektur
(siehe Qualitätsanforderungen §10.3
und Risiken §Bewusst nicht als Schulden geführt).
Der Grund ist Betriebsökonomie für ein Fachportal dieser Größe: ein
Deploy-Artefakt, eine Migration Pipeline, ein Health-Check. Die fachliche und im Quellcode
erzwungene Modultrennung (siehe 4.3) hält die Option auf spätere Auskopplung offen, ohne sie
vorwegzunehmen — Cross-Modul-Kommunikation läuft bereits heute über schmale Contracts und IDs,
nicht über gemeinsame Entities.
4.2 „No-Layer" statt klassischer 8-Projekt-ABP-Schichtung
Die strikte ABP-Standardaufteilung (Domain.Shared/Domain/Application.Contracts/Application/ EntityFrameworkCore/HttpApi/…) ist für dieses Repo explizit N/A (conventions-decisions.md ABP-11). Domain, Application und Persistence bleiben logische Schichten, aber materialisiert in einer kompakten Runtime-Assembly je Modul statt in sieben eigenen Projekten. Eine weitere Assembly-Grenze wird erst gezogen, wenn sie unabhängig konsumiert, versioniert oder ausgetauscht werden muss (ADR-01). Das reduziert Projekt- und Verkabelungsaufwand, ohne die fachliche Kapselung aufzugeben — die Kapselung sitzt in Feature-Slices, nicht in Assembly-Zahl.
4.3 Feature-Slices: Contracts / Runtime / Blazor
Jedes Fachmodul zerfällt in bis zu drei Projekte mit einseitiger Abhängigkeitsrichtung:
<Modul>.Contracts DTOs, AppService-Interfaces, Permissions, Localization, öffentliche IDs
<Modul> Runtime: Domain, Application Services, EF-Mapping
<Modul>.Blazor optionale Feature-Seiten/Komponenten (konsumiert nur Contracts)
- Contracts kennt keine EF-Entities und keine Implementierungsdetails; sie ist die einzige Fläche, die andere Module referenzieren dürfen.
- Runtime implementiert die Contracts, besitzt die eigenen Tabellen und darf nie fremde Runtime, fremde Entities oder fremde DbSets referenzieren.
- Blazor referenziert die eigene und ggf. fremde Contracts sowie Shell-Contracts, niemals eine Runtime.
Diese Grenzen sind eine Compile-Time-Eigenschaft, durchgesetzt über Architekturtests, nicht
nur eine Ordnerkonvention (Abhängigkeitstabelle in
Bausteinsicht §5.2.6).
Cross-Modul-Referenzen erfolgen ausschließlich über IDs (z. B. InstitutionId, DocumentId), nie
über relationale Foreign Keys oder Navigation über Modulgrenzen hinweg
(Querschnittliche Konzepte §2).
4.4 Zwei Bausteinklassen: wiederverwendbare CAF-Module vs. GZ-Fachmodule
Der Quellcode trennt zwei fachlich unterschiedliche Verantwortungsebenen strikt:
| Klasse | Beispiele | Kennzeichen |
|---|---|---|
CAF.Modules.* |
CAF.Modules.Authentication, CAF.Modules.UI.Blazor, CAF.Modules.Documents(.Contracts) |
anwendungsneutral, keine Abhängigkeit auf CAF.Applications.RAL.QualityMarks.HearingPortal.*, Quellcode-Baustein (nicht packbar) mit verbindlicher VERTRAG.md |
| GZ-Fachmodule | Authorization, Institutions, Hearings (je mit .Contracts/.Blazor) |
RAL-Gütezeichen-spezifisch, referenzieren Framework-Contracts, tragen die fachlichen Regeln |
CAF.Modules.* darf laut ADR-06
keinen GZ-Namespace und keinen GZ-Fachbegriff referenzieren; die Regel gilt nie umgekehrt
(CAF.Modules.* → CAF.Applications.RAL.QualityMarks.HearingPortal.* ist verboten). Konkret sichtbar wird das an den Modul-READMEs:
modules/Authentication/README.mdbeschreibt einen OIDC-/PKCE-Client ohne Produktrouten oder Berechtigungen der Anwendung.modules/Documents/README.mdbeschreibt einen mandantenfähigen Dokument-Adapter über ABP File Management, ebenfalls ohne Abhängigkeit auf das Portal.
Beide Bausteine behalten dabei bewusst das Präfix CAF in ihren persistierten Bezeichnern
(CAFDocumentShareGrants), unabhängig vom RALQM-Präfix der Anwendung (siehe 4.5). Diese Trennung
macht die Framework-Module potenziell in einem anderen ABP-Host wiederverwendbar, ohne dass GZ-
Fachlogik mitgezogen wird.
4.5 RALQM-Präfixstrategie für persistierte Kennungen
Anwendungsspezifische Kennungen tragen konsequent das Präfix RALQM: Tabellen
(RALQMHearings, RALQMInstitutions), Fehlercode-Namespaces (RALQM.<Feature>:), die
Permission-Gruppe RALQM und die Rollen RALQMAdministrator/RALQMCaseOfficer/
RALQMManagement. Technische Slugs bleiben demgegenüber lowercase (ral-qualitymarks).
Wiederverwendbare CAF-Module behalten ihr eigenes CAF-Präfix (CAFDocuments*) und werden von der
Umbenennung nicht erfasst — der Präfix markiert Ownership, nicht Technologie. Renames sind
grundsätzlich datenerhaltend: Migrationen, die einen Rename umsetzen (z. B.
20260825174437_RenamePersistedIdentifiersToRALQM), erzeugen keinen Datenverlust, und historische
EF-Migrationen behalten ihre alten Identifiers, statt rückwirkend umgeschrieben zu werden
(conventions-decisions.md EF-03). Diese Strategie hält die Grenze zwischen „Framework" und
„Anwendung" auch im Datenbankschema sichtbar, ohne die Migrationshistorie zu verfälschen.
4.6 Cohesion als verbindliche Fach-UI
Eigene CAF-/GZ-Oberflächen rendern ausschließlich über Cohesion (Syncfusion); MudBlazor,
rohes Syncfusion oder Blazorise dürfen von Fachcode nicht direkt aufgerufen werden
(conventions-decisions.md BL-01,
Querschnittliche Konzepte §5).
Ausgenommen sind allein die MVC-Razor-Pages unter /Account/**, die auf dem LeptonX-MVC-Theme
bleiben. Blazor-seitig gibt es seit der Ablösung der ABP-Modulansichten keine Ausnahme mehr: kein
MudBlazor- und kein Blazor-LeptonX-Paket ist noch referenziert, und keine Vendor-Komponente wird
gerendert. Blazorise kommt transitiv ueber ABPs Blazor-Theming-Paket mit; seine Stylesheets werden
im globalen Bundle wieder entfernt.
Träger dieser Entscheidung ist CAF.Modules.UI.Blazor: zentrale Cohesion-Registrierung,
Lizenzprüfung, Assets/Bundles und die Interactive-Server-Policy an einer Stelle. Das
Cohesion-Paket kommt aus dem GitLab-Gruppen-Feed; Quelle, Versionsbereich und Auth-Wege stehen in
Getting Started, Cohesion-Paketquelle. Feature-Seiten liegen im jeweils owning
.Blazor-Projekt, bleiben render-mode-neutral (kein @rendermode in Feature-Code) und erfüllen
WCAG 2.1 AA als Pflichtkriterium — fachlich relevant für ein Behördenportal.
4.7 Konsequenzen für Cross-Cutting-Themen
- Auth: Keycloak bleibt alleiniger Identity Provider;
CAF.Modules.Authenticationkapselt den OIDC-Client, GZ Authorization komponiert Rollen/Grants aus featureeigenen Permissions (Querschnittliche Konzepte §1). - Dokumente: ABP File Management/BLOB Storing bleibt Descriptor- und Inhalts-Owner;
CAF.Modules.Documentsliefert nur den neutralen Vertrag plus Share-Grants, Hearings trägt die fachliche Bedeutung einer Datei (Laufzeitsicht §6.4). - Persistenz: ein gemeinsamer
HearingPortalDbContext, aber jedes Modul liefert seine eigene Model-Konfiguration; Migrationen entstehen ausschließlich im Host. - Tests: die Modulgrenzen werden nicht nur dokumentiert, sondern durch Architekturtests erzwungen und sind damit Teil des Qualitätsnetzes (Querschnittliche Konzepte §7).
Siehe auch
- Randbedingungen — die gesetzten Vorgaben, die diese Strategie motivieren.
- Kontextabgrenzung — Systemgrenze und externe Nachbarn.
- Bausteinsicht — Detailschnitt der hier benannten Module.
- Querschnittliche Konzepte — Vertiefung von Auth, Dokumenten und Konfiguration.
- Architekturentscheidungen — ADR-Langform je Grundsatzentscheidung.
- docs/conventions-decisions.md — Konventions-Entscheidungsregister mit Status je Regel.
- DEVELOPMENT-GUIDE.md — verbindliche Arbeitsweise bei Änderungen.
05. Bausteinsicht
Dieses Kapitel zerlegt die statische Struktur des Systems in Bausteine: zuerst auf Ebene 1 (Module/Projekte), dann auf Ebene 2 (Feature-Slices der Anwendung). Motivation und Zielsetzung der No-Layer-Architektur stehen im Kontextabgrenzung und in der Lösungsstrategie; dieses Kapitel beschreibt nur, was existiert und **wer wen abhängen darf. Details zu Laufzeitabläufen liefert die Laufzeitsicht.
Quelle der Wahrheit für alle hier genannten Grenzen sind die Architekturtests (siehe ADR-06); dieses Kapitel fasst sie arc42-konform zusammen und verlinkt auf die READMEs der Bausteine.
5.1 Ebene 1: Gesamtsystem in Module und Anwendung
Das System ist ein modularer Monolith: ein Deployable
(CAF.Applications.RAL.QualityMarks.HearingPortal), eine gemeinsame SQL-Server-Datenbank,
aber strikt getrennte Bausteine im Quellcode und im Abhängigkeitsgraphen. Dafür gibt es drei
Solution-Einstiege: CAF.Framework.slnx enthält
die CAF-Projekte und deren Tests. CAF.slnx im Wurzelverzeichnis
umfasst das Monorepo und gliedert in /modules/<Modul>/src/,
/Applications/RAL/QualityMarks/HearingPortal/ mit je einem Unterordner pro Feature,
/modules/<Modul>/tests/, /Tests/Architecture/ und
/Tests/Applications/RAL/QualityMarks/HearingPortal/;
HearingPortal.slnx
umfasst die Anwendung samt CAF-Quellabhängigkeiten und gliedert in
/Host & Shell/, /Features/<Name>/, /modules/<Modul>/src/
und /Tests/.
flowchart TB
subgraph App["Anwendung: RAL Gütezeichen Anhörungsportal"]
direction TB
Host["Host\n…RAL.QualityMarks.HearingPortal"]
Shell["Shell"]
AppContracts["Contracts"]
AppUI["UI.Blazor\n(produktweiter UI-Baustein)"]
Auth["Features/Authorization"]
Inst["Features/Institutions"]
Hear["Features/Hearings"]
VL["Features/ValueLists"]
Filing["Features/Filing"]
AbpRepl["ABP-Ersatz-Features\nIdentity, Languages, TextTemplates,\nAuditLogs, Gdpr, Settings\n(Contracts + Blazor; TextTemplates mit Adapter-Runtime,\nSettings mit Absender-Runtime seit RAL-QM-HP-27)"]
end
subgraph Modules["Wiederverwendbare CAF-Module\n(anwendungsneutral)"]
direction TB
ModAuthn["CAF.Modules.Authentication"]
ModUI["CAF.Modules.UI.Blazor"]
ModDocC["CAF.Modules.Documents.Contracts"]
ModDoc["CAF.Modules.Documents"]
end
Host --> Shell
Host --> Auth
Host --> Inst
Host --> Hear
Host --> VL
Host --> Filing
Filing --> ModDocC
Filing -->|Runtime| Hear
Hear -->|Blazor| Filing
Filing --> AppUI
Host --> AbpRepl
AbpRepl --> AppUI
Auth --> Inst
Auth --> Hear
Auth --> VL
Hear --> Inst
Hear --> VL
Inst --> VL
Shell --> AppUI
Auth --> AppUI
Inst --> AppUI
Hear --> AppUI
VL --> AppUI
AppUI --> ModUI
Host --> ModAuthn
Host --> ModUI
Auth --> ModDocC
Hear --> ModDocC
ModDoc --> ModDocC
Pfeile bedeuten „referenziert/verwendet“ und meinen dabei stets die Contracts des Ziels. Die
beiden beschrifteten Pfeile zwischen Filing und Hearings sind deshalb kein Projektzyklus, sondern
zwei verschiedene Projekthälften: Filing.Runtime → Hearings.Contracts (Übernahme, Papierkorb) und
Hearings.Blazor → Filing.Contracts (Bedien-Einstieg, RAL-QM-HP-16) — Einzelheiten in
5.2.5. Die zentrale, architekturtestlich abgesicherte Regel:
die Anwendung hängt von den Modulen ab, nie umgekehrt. Kein CAF.Modules.*-Projekt darf ein
CAF.Applications.RAL.QualityMarks.HearingPortal.*-Projekt, einen GZ-Namespace oder einen
GZ-Fachbegriff referenzieren.
5.1.1 Anwendungs-Bausteine
| Baustein | Projekt | Verantwortung | Grenze |
|---|---|---|---|
| Host | CAF.Applications.RAL.QualityMarks.HearingPortal |
Start, Modulkomposition, Middleware, Routing, konkrete Konfiguration, gemeinsamer HearingPortalDbContext, SQL-Provider, Migration und Seed |
keine neuen Fachentities, Fachregeln oder Feature-Application-Services |
| Contracts | …HearingPortal.Contracts |
produktweite Shell-Localization (Ressource RALQM), globale Menünamen, von der Shell benötigte ABP-Contracts |
keine Feature-Entities, kein EF, keine Runtime-Abhängigkeiten |
| Shell | …HearingPortal.Shell |
serverorientierte Razor-Class-Library: Startseite (Arbeitsbereich: Einstiegskarten, jede unter dem Recht ihrer Zielseite aus den Feature-Contracts — seit RAL-QM-HP-1 auch „Mitarbeitendenkonten“ unter RALQM.Accounts —, darunter die registrierten Panels über HearingPortalWorkspaceOptions), Anmeldeeinstieg, Pflichtseiten, Produktmenü-Komposition (kein WebAssembly-Client — Render Mode wählt der Host) |
keine Fachpersistenz, keine Fachregeln, keine browserseitige WASM-Runtime; keine Referenz auf eine Feature-Runtime oder ein Feature-*.Blazor (Regel ClientToFeatureRuntime) — Feature-Inhalt erreicht die Startseite nur über den Erweiterungspunkt in Contracts |
| UI.Blazor | …HearingPortal.UI.Blazor |
produktweiter Shared UI Building Block (Stufe 6, Designdurchgang): Seitengerüst HearingPortalPage, Filterleiste HearingPortalFilterBar, Statusbadges mit der Ton-Zuordnung HearingPortalStatusTone, Verfahrens-Stepper HearingWorkflowStepper — Produktwerte, die Shell und alle Feature-*.Blazor gleich brauchen |
keine Route, keine Application-Service-Aufrufe, keine Feature-Runtime; referenziert nur Contracts, Hearings-Contracts (Statusenums) und CAF.Modules.UI.Blazor; Texte kommen aus den Ressourcen der aufrufenden Seite |
| Features (fachlich) | Features/{Authorization,Hearings,Institutions,ValueLists,Filing,Consents} |
die sechs fachlichen Slices der Anwendung, siehe 5.2 | siehe Abhängigkeitstabelle unten |
| Features (ABP-Ersatz) | Features/{Identity,Languages,TextTemplates,AuditLogs,Gdpr,Settings} |
Cohesion-Produktseiten, die die mitgelieferten ABP-Modulseiten ablösen; je Feature Contracts + Blazor; TextTemplates ergänzt eine schmale Runtime für verwaltete native Inhalte und Schreibschutz; Settings ergänzt seit RAL-QM-HP-27 eine Runtime für die Absenderangaben der Organisation (sieben ABP-Settings der Gruppe RALQM.Organisation, Recht RALQM.Settings.Organisation, Dienst OrganisationSenderAppService, Lese-Port IOrganisationSenderReader für Nachrichten und Anschreiben, Protokoll-Allowlist ProtocolledSettingsOptions). Fachliche Vorlagenregeln bleiben in Hearings, Inhaltsspeicherung in ABP |
keine eigenen Entities, kein EF-Mapping; referenzieren Produkt-Shell-Contracts und Produkt UI.Blazor (siehe Abhängigkeitstabelle unten) |
Details zur Anwendungsstruktur: ../../applications/RAL/QualityMarks/HearingPortal/README.md.
5.1.2 Wiederverwendbare CAF-Module
Alle vier Bausteine liegen unter modules/ und sind Quellcode-Bausteine, keine
NuGet-Pakete (IsPackable=false, keine PackageId/Version). Der Host konsumiert sie
ausschließlich über ProjectReference. Je Baustein gilt trotzdem die Vertragsdatei VERTRAG.md
als Quelltext-Vertrag — arch-getestet, siehe
ADR-03.
Die folgende Tabelle fasst zusammen, wie dieses Produkt die Bausteine nutzt. Maßgeblich für
Zweck, Abgrenzung und zugesicherte Fläche der Bausteine selbst ist
docs/ bzw. die VERTRAG.md am jeweiligen Baustein — diese
Tabelle ersetzt beides nicht.
| Modul | Projekt(e) | Verantwortung | Grenze |
|---|---|---|---|
| Authentication | CAF.Modules.Authentication |
OIDC-Client (Authorization Code + PKCE), Claim-Mapping, Cookie-/Session-Policy, lokale/remote Abmeldung samt idempotentem Entzug der ABP-Sitzung (RAL-QM-HP-92), Security-Stamp-Revalidierung | keine Produktrouten, keine Berechtigungen der Anwendung, keine Realm-/GZ-Rollen-Policy |
| UI.Blazor | CAF.Modules.UI.Blazor |
zentrale Cohesion-Registrierung (AddCohesion), Lizenzprüfung, Bundle-Contributors für CSS/JS, CAFCohesionSmokePanel |
keine Produktroute, keine Fachkomponente, kein Render-Mode-Entscheid des Hosts; keine Cohesion-Fassade für Razor-UI-Assemblies (siehe 5.1.3) |
| Documents.Contracts | CAF.Modules.Documents.Contracts |
DocumentId, vendor-neutrale DTOs, Dokument-/Content-/Share-Interfaces (seit RAL-QM-HP-21 auch IDocumentContentPort.DescribeManyAsync und IDocumentUploadPolicyReader), Permissions, Localization |
exportiert keine Volo.FileManagement-Typen |
| Documents | CAF.Modules.Documents (Runtime) |
dünner Adapter über ABP File Management: validierter Dateiinhalt (seit RAL-QM-HP-21 inhaltsbasiert per Dateisignatur, Dateiarten-Liste als Teilmenge der unterstützten Tabelle konfigurierbar), Metadatenzugriff, sichere direkte Freigaben; besitzt nur CAFDocumentShareGrants; Optionsbaum Storage (Datenbank oder Dateisystem außerhalb des Auslieferungsverzeichnisses), den der Host für den Blob-Container liest |
ABP besitzt Descriptor und BLOB-Inhalt |
RAL-QM-HP-19: Features/Filing besitzt die verfahrensunabhängige
persönliche/gemeinsame Ablage. Seine Contracts und Runtime konsumieren den neutralen
IDocumentFilingPort; ABP besitzt weiterhin sämtliche aktuellen Datei-/Ordnermetadaten und
Inhalte. Filing speichert nur Bereichseigentum, Elementzuordnung, Papierkorbzustand und
Fachhistorie in RALQMFilingAreas, RALQMFilingEntries und RALQMFilingHistory.
Aktive interne Referenten und Produktadministratoren erhalten Read/Manage/Purge für
gemeinsame und eigene persönliche Bereiche; fremde persönliche Bereiche bleiben privat.
Der Authorization-Port prüft die aktuelle Kontoeignung zusätzlich zu den ABP-Grants.
Filing.Blazor bindet den separat paketierten CohesionDataBrowser unter /filing
an die Filing-Contracts an. /filing/trash verwendet eine semantische Tabelle mit Cohesion-Aktionen für getrennte
Herkunfts-/Löschspalten. Die administrative Bereichsübertragung unter
/administration/ablage-uebertragen konsumiert nur Konten- und Bereichsprojektionen,
niemals Datei-Metadaten oder Inhalte. Die RCL hat keine Runtime-/EF-Abhängigkeit;
CAF-Documents-Contracts liefern lediglich Fehlercodes und deren Localization.
Der schmale IHearingDocumentTrashPort ergänzt entfernte Verfahrensdateien aus RAL-QM-HP-21.
Hearings besitzt deren Wiederherstellung, Löschauftrag und erhaltene Historie; die
Filing-Projektion legt keine zusätzlichen Fachdateien oder Bereiche an. Die gemeinsame
Liste sortiert und paginiert erst nach der Zusammenführung der autorisierten Quellen.
Ist das ursprüngliche Zweckfenster geschlossen, autorisiert derselbe Hearings-Port die
zurückgezogene Quelle für eine unabhängige Kopie in die Ablage. Filing besitzt Zielordner,
Namenskonflikte, Operation-ID und Kopierhistorie; CAF erzeugt eine neue Descriptor-/Blob-Identität.
Die Quellprüfung hält ihre Sperre in der von Filing begonnenen Serializable-Unit-of-Work bis
zum Kopierabschluss. Verfahrensreferenz, Originalinhalt, Status und Grants werden dabei nicht
reaktiviert oder verändert. Die Gegenrichtung — eine Ablagedatei als eigenständige
Verfahrensfassung übernehmen — ist mit RAL-QM-HP-16 hinzugekommen und in
5.2.5 beschrieben. Siehe die
abgestimmte Spec.
Persistierte Kennungen der Module behalten das Präfix CAF (CAFDocuments*), unabhängig vom
RALQM-Präfix der Anwendung. Details je Modul:
Authentication,
Documents,
UI.Blazor.
5.1.3 Cohesion-Referenz-Ausnahme für Razor-UI-Assemblies
Die Razor-UI-Assemblies dieser Anwendung — die Produkt-Shell, der produktweite UI-Baustein
…HearingPortal.UI.Blazor und jedes Features/*/Blazor — referenzieren das Cohesion-Paket
direkt per PackageReference und gerade nicht über CAF.Modules.UI.Blazor. Sie erzwingen
dazu RZ10012 als Fehler (WarningsAsErrors), damit ein unaufgelöstes Cohesion-Tag den Build
bricht statt still als leeres HTML-Element zu rendern. CAF.Modules.UI.Blazor selbst binden sie
für etwas anderes ein: die Grid-Naht (CAFGridDataAdaptor, CAFGridToolbar) und den
Fristbaustein (CAFDeadlineChip) — CAF-Konventionen, keine Cohesion-Fassade. Der Host bindet
es zusätzlich für Registrierung, Lizenzierung und Bundles ein.
Das ist eine bewusste, Razor-bedingte Ausnahme und keine aufzuräumende Redundanz — Regel,
Begründung (Compile-Time-Razor-Assets) und Rollenteilung stehen in
docs/ §02 Bausteine.
Verbindliche Arbeitsfassung:
modules/AGENTS.md und
Shell/AGENTS.md.
5.2 Ebene 2: Feature-Slices der Anwendung
Dieser Abschnitt beschreibt die fachlichen Features; die sechs ABP-Ersatz-Features aus 5.1.1 haben keine eigene Runtime und deshalb keine Ebene-2-Struktur.
Jedes fachliche Feature gliedert sich intern in bis zu drei Teilprojekte —
Contracts, Runtime und optional Blazor. Diese Dreiteilung besteht nur dort, wo die
Grenze echten Nutzen stiftet: Abhängigkeitsrichtung, serverseitige Interception und spätere
Auskopplung. Weitere Layerprojekte (z. B. separates Domain/Application) werden nicht
vorsorglich angelegt — Domain, Application und EF-Persistenz bleiben logische Schichten
innerhalb der Runtime-Assembly.
Features/<Feature>/
Contracts/ DTOs, AppService-Interfaces, Permissions, Localization, öffentliche IDs
Runtime/ Aggregate, Application Services, EF-Mapping (Domain/Application/EF in einer Assembly)
Blazor/ optionale Razor-Class-Library: Seiten, Komponenten, Navigation (nur bei eigener UI)
5.2.1 Authorization
| Teilprojekt | Verantwortung |
|---|---|
Authorization.Contracts |
globale GZ-Permissiongruppe RALQM, Rollenbezeichnungen (RALQMAdministrator, RALQMCaseOfficer, RALQMManagement, seit RAL-QM-HP-18 RALQMInstitution), die drei Kontenrechte RALQM.Accounts/.Invite/.InviteInstitution, Konten-Contracts (Übersicht mit Facetten, Institutionskonto aus Ansprechpartner, Kennungswechsel, Wiedereinladung, Papierkorb/Wiederherstellen, Verlauf — kein Delete); seit RAL-QM-HP-8 der schmale, permissionfreie In-Process-Lesevertrag IStaffAccountReferenceReader (aktive Referenten als Übertragungsziele, Anzeigenamen zu Benutzer-Ids) — dasselbe Muster wie IInstitutionReferenceReader, nie über HTTP |
Authorization (Runtime) |
Rollen-/Grant-Komposition für die vier Rollen mit exaktem Seed-Abgleich, lokale ABP-Benutzerprojektion, kontrollierter Keycloak-Admin-Adapter (anlegen, Einladung, Sperren, Logout, Kennung ändern, Zustände lesen), Mitarbeitenden-Onboarding über bestätigtes Keycloak-Subject (sub), Institutionsbindung (RALQMInstitutionAccountBindings), Kontoverlauf (RALQMStaffAccountHistory), Sitzungswiderruf über den Host-Port IAccountSessionRevoker, zweiter Faktor (RAL-QM-HP-11: Faktorstatus, Selbstbedienung über Keycloak-Aktionen, Rücksetzaufträge RALQMSecondFactorResetOrders) |
Authorization.Blazor |
eigener Kontenpfad: Übersicht mit Facetten (Status, Rolle, Institution), Anlage interner Konten, Wiedereinladung, Produktrollenwechsel, Sperren/Entsperren, Kennungswechsel, Verlauf, Papierkorb mit Wiederherstellen — je Recht des Aufrufers; Institutionskonten entstehen auf der Kontaktseite von Institutions |
Die Authorization-Runtime referenziert Feature-Contracts von Institutions und Hearings, um Rollen
zu komponieren, besitzt aber keine Feature-Permissions und keine Hearing-Daten.
Der Worker-Rechtecheck konsumiert Filing- und Hearings-Permissions; deren Contracts-Module
sind deshalb auch im ABP-Modulgraph über DependsOn geladen, ohne die Hearings-Runtime zu laden.
Für RAL-QM-HP-43 prüft IStaffResponsibilityReservation.IsActiveHolderAsync neben Aktivstatus
und genau einer internen Produktrolle die eindeutige lokale Keycloak-Subject-Bindung.
Auch Papierkorbprojektionen zählen beim Subject-Abgleich; mehrdeutige Importdaten machen
das Konto als Erinnerungs-/Eskalationsempfänger ungeeignet. Hearings liest nur den Contract.
5.2.2 Institutions
| Teilprojekt | Verantwortung |
|---|---|
Institutions.Contracts |
Institution-/Kontakt-DTOs, AppService-Interfaces, Permissions, Localization, Menünamen; die schmalen, permissionfreien In-Process-Leseverträge IInstitutionReferenceReader (Institutionsreferenzen) und seit RAL-QM-HP-9 IInstitutionContactDeputyReader (wirksame Vertretung eines Kontakts zu einem Zeitpunkt, für die Vertretungskopie im Postausgang; permissionfrei, weil Erinnerungen und Fristabläufe ohne angemeldeten Benutzer entstehen) und seit RAL-QM-HP-101 IInstitutionContactLanguageReader (gespeicherte Kommunikationssprache eines Kontakts, für die Sprache je Postausgangszeile und Eingangsbestätigung; permissionfrei aus demselben Grund) — alle drei [RemoteService(false)], nie über HTTP |
Institutions (Runtime) |
Institution-/Kontakt-Aggregat, Aktivität, Kreis (Fach-/Verkehrskreis) und Pflichtpartner-Kennzeichen als eigenes Merkmal (RAL-QM-HP-10 O4), Anschrift, interne Notiz (nur für interne Benutzer, Export nur mit ausdruecklichem Opt-in nach RAL-QM-HP-49; RAL-QM-HP-10), CSV-Import/-Export, Nutzungsprüfung, Dublettenregel für Namen (InstitutionNameDuplicateRule, eine Stelle; RAL-QM-HP-10), Standardansprechpartner (höchstens einer je Institution, immer aktiv, der erste aktive selbsttätig, weder deaktivier- noch entfernbar) und Vertretung am Kontakt mit ihren Zuweisungsregeln und ihrem Leser ohne Authorize (InstitutionContactDeputyReader, Zeitfenster und Aktivität aus Institution.FindEffectiveDeputy, „nicht gefunden“ ergibt keine Vertretung) sowie der Pflichtpartner-Guard beim Setzen des Kennzeichens (RAL-QM-HP-9), Institutionsgruppe mit ihren Mitgliedschaften (RAL-QM-HP-3), EF-Mapping; besitzt RALQMInstitutions, RALQMInstitutionContacts, RALQMInstitutionGroups, RALQMInstitutionGroupMembers |
Institutions.Blazor |
Institutionenliste mit Pflichtpartner-Filter und -Badge (RAL-QM-HP-10), Bearbeitung mit Pflichtpartner-Schalter neben dem Kreis und Dublettenwarnung vor dem Speichern, Bestätigungsdialog vor der Deaktivierung mit der Zahl laufender Verfahren in Liste und Maske (RAL-QM-HP-10), Kontakte mit Telefon, Standard-Kennzeichen und „Als Standard festlegen“, Nutzungshinweis je Kontakt, Bestätigungsdialog mit Kontakten und Verfahren und Vertretung mit Zeitraum (RAL-QM-HP-9), Kontaktsuche mit Standard-Kennzeichen, berechtigte Kontoeinladung; Gruppenübersicht, Gruppenmaske mit Mitgliederliste und Zuordnungsmaske mit Mehrfachauswahl (RAL-QM-HP-3) |
Institutionsgruppen (RAL-QM-HP-3): Eine
Institutionsgruppe ist ein verfahrensübergreifend wiederverwendbarer, benannter Beteiligtenkreis,
gemeinsames Stammdatum aller internen Konten. Gelesen und gepflegt wird sie über
IInstitutionGroupAppService (Übersicht mit Freitextsuche über Name und Beschreibung, Gruppe und
Mitgliederliste lesen, anlegen, umbenennen, beschreiben, auflösen, Institutionen zuordnen und
entfernen); der Name ist eindeutig, Änderungen tragen den Concurrency-Stamp. Die Oberfläche in
Institutions.Blazor besteht aus der Gruppenübersicht /institutions/gruppen, der Gruppenmaske
/institutions/gruppen/{id} mit Mitgliederliste und Bestätigungsdialog vor dem Auflösen, der
Zuordnungsmaske /institutions/gruppen/{id}/zuordnen und dem Menüeintrag „Gruppen“ im
Modul Institutionen (neben „Übersicht“ und „Kontaktsuche“; die Seite selbst heißt weiter
„Institutionsgruppen“).
Ein Mitgliederrefresh übernimmt einen neuen Gruppenstempel nur bei unveränderten
Metadaten des Formular-Ausgangsstands. Andernfalls bleiben lokale Eingaben und alter
Stempel erhalten und die Maske meldet den Konflikt.
Die Zuordnungsmaske ist die erste Mehrfachauswahl des Portals: sie zeigt die Institutionsliste
mit deren Suche und Filtern, hält die Auswahl aber selbst — Id und Name, über Seiten und
Filterwechsel hinweg, mit sichtbarem Zähler, aufklappbarer Namensliste und einmaligem Speichern.
Nach erfolgreichem Speichern entfernt sie nur die übermittelten IDs aus dem Korb;
Auswahlen während des laufenden Aufrufs bleiben für den nächsten Vorgang erhalten.
Die Sammelauswahl im Tabellenkopf greift höchstens auf die sichtbare Seite. Das Muster steht in
grid-muster.md §11, weil es für die nächste Mehrfachauswahl
gilt.
Das Datenmodell liegt im Slice: das Aggregat
InstitutionGroup mit Name, gespeichertem Vergleichsschlüssel, optionaler Beschreibung und
Revisionszähler sowie die Mitgliedschaft InstitutionGroupMember als reine Kindentität; Tabellen
RALQMInstitutionGroups und RALQMInstitutionGroupMembers. Die Persistenzregeln stehen in
Kapitel 8 §2,
die Rechte in §1.
Das Einbinden einer Gruppe in ein Verfahren (US-13) leistet seit RAL-QM-HP-5 (AC-8) der Baustein
Hearings über den Lesevertrag IInstitutionGroupAppService – Gruppe und alle Mitgliederseiten, mit
dem Leserecht RALQM.InstitutionGroups (siehe §5.2.3). Für diesen Aufrufer
erhielt der Listenvertrag IInstitutionAppService.GetListAsync einen Id-Filter
(GetInstitutionsInput.Ids, höchstens MaxIds = 1000): null schränkt nicht ein, eine leere
Liste trifft nichts – ein Aufrufer, dessen Id-Menge leer läuft, darf nicht stattdessen alle
Institutionen erhalten –, eine unbekannte Id fehlt in der Antwort. So löst Hearings die
Institutionen einer Mitgliederseite mit einer Lesung auf statt mit einer je Mitglied; der Filter
greift in InstitutionListSearchQuery und ist dort gegen echten SQL Server geprüft
(InstitutionSqlServerTests). Sonst bleibt Institutions unberührt. Rundnachrichten an eine Gruppe
(RAL-QM-HP-77, ADR-18) liegen in Hearings und lesen Gruppen und Kontakte nur über diese Verträge. Siehe auch
Glossar.
Institutions kennt Hearings nur über einen von außen implementierten Nutzungsport (keine
Rückabhängigkeit). IInstitutionUsageProvider beantwortet zwei Fragen: ob eine Institution
irgendwo referenziert ist (Löschschutz, zählt jede jemals vorhandene Teilnehmer-Referenz) und in wie vielen
laufenden Verfahren sie beteiligt ist (Deaktivierungswarnung, RAL-QM-HP-10 A4: weder abgeschlossen
noch abgebrochen, als Antragsteller oder nicht zurückgezogener Teilnehmer, je Verfahren einmal).
Beide Antworten gibt der Slice Hearings; ohne ihn antwortet die Institutions-Runtime „nicht
referenziert“ und „null“. Für Kontakte beantwortet IInstitutionContactUsageProvider zwei Fragen
mit bewusst verschiedenen Zählregeln (RAL-QM-HP-9 A4, N3): Der Löschschutz zählt jede jemals
vorhandene Beteiligung des Kontakts, auch zurückgezogene und solche in abgeschlossenen Verfahren,
samt aktiver Portalkontobindungen, und die erste gemeldete Nutzung blockt; die Nennung laufender
Verfahren je Kontakt (Kennung, Referenznummer, Titel; serverseitig die Leseoperation für den
Nutzungshinweis und die Abweisung ohne Deaktivierungsbestätigung, RAL-QM-HP-9 AC-4/AC-5; die Anzeige
in der Institutionsmaske folgt) zählt nur Verfahren, die weder abgeschlossen noch
abgebrochen sind (Entwürfe eingeschlossen), mit nicht zurückgezogener Beteiligung, und führt die
Antworten aller registrierten Anbieter zusammen.
RAL-QM-HP-49 erweitert den vorhandenen
CSV-Vertrag um alle aktiven Kontakte, den Institutionsstatus und ausdrücklich gewählte interne
Notizen. Listen- und Exportabfrage teilen Suche, Filter und Sortierung; der Export hat keine
Seitengrenze. Der Import validiert eine Institution samt Kontakten vor dem Schreiben und legt
nur neue Namen an. Bekannte Namen werden übersprungen. Länder und Kontaktfunktionen werden
über ValueLists.Contracts aufgelöst. Die optionale Institutionsnotiz bleibt intern und nutzt
die vorhandenen Pflege-Permissions und den Concurrency-Stamp des Aggregats; ihre Persistenz-
und Auditgrenze beschreibt Kapitel 8.
Der Kontaktblock trägt seit Teil 2 auch Anredeform, Titel, Telefonnummer und das
Standardkennzeichen aus RAL-QM-HP-9. Jede dort ergänzte Spalte trägt das Präfix Kontakt, weil
der Blockerkenner jeden gleichlautenden Kopfnamen als Kontaktspalte liest und ein bloßes
Telefon eine Altdatei mit gleichnamiger Institutionsspalte abweisen würde. Das
Standardkennzeichen steht je Block; nennt die Zeile keines, bleibt die Automatik aus RAL-QM-HP-9
zuständig. Der Import legt die Kontakte an, bevor der Pflichtpartner-Guard greift; die
Kennzeichnung aus der Datei folgt danach und überschreibt die Automatik. Vertretung und
inaktive Kontakte sind nicht Teil des Dateivertrags.
RAL-QM-HP-41 ergänzt
den Vertrag IInstitutionAppService um „einen Kontakt hinzufügen“ (AddContactAsync mit
AddInstitutionContactDto). Der Aufrufer reicht eine Person und den gelesenen Stand der
Institution; die Institution legt genau einen aktiven Kontakt hinter den vorhandenen an und
antwortet mit ihm. Es gelten die Regeln einer Kontaktzeile der Kontaktpflege (Funktion aus der
aktiven Werteliste, zustellbare Adresse, Längen) und ihr Recht RALQM.Institutions.Update. Der
Standardkontakt bleibt; hat die Institution keinen, greift die Automatik aus RAL-QM-HP-9. Zwei
Kontakte derselben Institution dürfen dieselbe Adresse tragen. Ob eine deaktivierte Institution
einen Kontakt erhalten darf, entscheidet der Aufrufer. Einziger Aufrufer ist die Übernahme einer
Kontaktmeldung in Hearings (siehe §5.2.3); die Institutionsmaske speichert weiter
die ganze Institution.
5.2.3 Hearings
| Teilprojekt | Verantwortung |
|---|---|
Hearings.Contracts |
DTOs/Interfaces für Anhörungen, Teilnehmer, Dokumente, Freigabe, Versand, Portal, Rückmeldungen (seit RAL-QM-HP-38 die Kategorieregeln HearingResponseRules – fünf Kategorien, Einwand-Menge, 15 Zeichen –, damit Aggregat, beide Erfassungswege und die Masken dieselbe Regel lesen, und der Portalvertrag mit Dateien in einem Aufruf; seit RAL-QM-HP-40 ergänzt eine Auftragskennung die unveränderliche Erstabgabe und neue Beiträge), Fristen, Historie (seit RAL-QM-HP-45 auch die verfahrensübergreifende Recherche IHearingHistorySearchAppService und die Höchstzahl der Ausleitung IHearingHistoryExportSettingsAppService), Einstellungen (seit RAL-QM-HP-38 die Anlagen-Höchstzahl IHearingResponseAttachmentSettingsAppService); Feature-Permissions/Localization |
Hearings (Runtime) |
Anhörungs-Aggregat und Lebenszyklus (siehe Laufzeitsicht), Referenznummern, Teilnehmer mit Beteiligungsgrund (seit RAL-QM-HP-5: Pflichtpartner oder manuell, im Moment der Zuordnung aus dem Kennzeichen der Institution abgeleitet, danach unveränderlich; die Regel HearingParticipationReasonRule liegt im Contract, damit jeder Zuordnungsweg dieselbe anwendet), Gruppenzuordnung (seit RAL-QM-HP-5 AC-8: HearingParticipantAppService.PreviewGroupAssignmentAsync und AssignGroupAsync lesen Gruppe und alle Mitgliederseiten über IInstitutionGroupAppService – der Vertrag von Institutions, kein zweiter Port –, lösen die Institutionen einer Mitgliederseite mit einer Lesung über den Id-Filter von IInstitutionAppService.GetListAsync auf (nie eine Lesung je Mitglied; der Plan läuft für Vorschau, Bestätigung und jede Wiederholung), weisen beide außerhalb des Entwurfs vor dem ersten Gruppenzugriff ab und legen im Entwurf in einem Speichervorgang je zuordenbarem Mitglied eine Beteiligung mit Standardansprechpartner, Grund nach E2 und Pflichtunterlagen an; bereits aktiv beteiligte, deaktivierte oder gelöschte Institutionen und solche ohne aktiven Standardansprechpartner werden mit Grund übersprungen, die Bestätigung rechnet neu; nötig sind Participants.Manage und RALQM.InstitutionGroups), Zugangsentzug je Beteiligung (seit RAL-QM-HP-5 AC-10, E6: Hearing.RevokeParticipantAccess und RestoreParticipantAccess setzen und löschen AccessRevokedAtUtc nur in Dispatched und Adjudication, nur für aktive Beteiligungen, ohne Begründung und ohne Nachricht; die Beteiligung mit Empfänger, Grants und Fristen bleibt, nach dem Ende ist der Zustand eingefroren; je Wechsel ein Verlaufseintrag AccessRevoked/AccessRestored; Participants.Manage), Bestätigung von Antragsteller- und Teilnehmer-Institutionen über den Institutions-Vertrag (Existenz und Aktivität; seit RAL-QM-HP-10 auch der Antragsteller beim Anlegen), Kontaktwahl bei automatischer Einbindung von Pflichtpartnern und beim Kopieren eines Verfahrens über das Standard-Kennzeichen des Kontakts (seit RAL-QM-HP-9; beim Kopieren bleibt der zuvor gewählte aktive Kontakt vorn, E10), Antwort auf den Institutions-Nutzungsport (Löschschutz, Zählung laufender Verfahren, Nennung laufender Verfahren je Kontakt), Dokumentzuordnung/-versionen/-grants (seit RAL-QM-HP-20 auch die Sammelzuordnung: Hearing.GrantDocumentToAllActiveParticipants erteilt in einem Speichervorgang je beim bestätigten Speichern aktiver Beteiligung ohne aktiven Grant einen neuen, lässt bestehende Grants unverändert und merkt sich den Zeitpunkt in HearingDocument.GrantedToAllParticipantsAtUtc; später hinzugefügte Beteiligte erhalten nichts automatisch und werden über ParticipantsMissingBulkGrant benannt; Recht Participants.ManageGrants, Stempelprüfung vor jeder Änderung, ein DocumentGranted-Verlaufseintrag je neu erzeugtem Grant), Vier-Augen-Freigabe (seit RAL-QM-HP-25 mit dem dauerhaften Benachrichtigungsauftrag je Entscheidung an den zuständigen Referenten: HearingApprovalDecisionNotification, Zustellung durch HearingApprovalDecisionNotificationProcessor, Fehler als Störung Notification:ApprovalDecision; seit RAL-QM-HP-22 mit der Zielgruppe Geschäftsführung für Einreichung und Rückzug, der Empfängerprüfung HearingRecipientValidator beim Einreichen und vor dem Erstversand sowie der Lesung GetSubmissionReadinessAsync für die Einreichen-Seite; seit RAL-QM-HP-6 bescheinigt die Prüfung die operative Adresse der Beteiligung), Empfängerstand je Beteiligung (seit RAL-QM-HP-6: die Snapshot-Spalten der Beteiligung – Institution mit Anschrift, Kontakt mit Anrede, Titel, Name, Funktion und E-Mail – sind der operative Stand jeder neuen Aussendung; eine Stammdatenänderung ist eine feldweise Abweichung, die HearingParticipantAppService.GetRecipientStandAsync über den Institutions-Vertrag ausweist, und erreicht den Stand nur über die drei Befehle UpdateRecipientStandAsync (Übernahme, gebunden an den ComparisonStamp der Vorschau), ChangeRecipientContactAsync (anderer aktiver Kontakt derselben Institution) und CorrectRecipientEmailAsync (nur die Adresse) – Recht Participants.Manage, nur in Draft, Dispatched, Adjudication, je ein Verlaufseintrag mit Feldnamen bzw. Kontaktpaar; jede Postausgangszeile friert den Stand ihres Moments ein, siehe Querschnitt), Kommunikationsschritt je Zweck (seit RAL-QM-HP-24: HearingCommunicationStep als Kind des Aggregats – einmalige Kopie des gebundenen Vorlagentexts mit Institutionsabweichungen, gesperrt nach Status und ab der ersten Postausgangszeile; seit RAL-QM-HP-101 je Verfahren, Zweck und Sprache – Editor nach dem Muster Bezugssprache lesend/Zielsprache bearbeitbar, nur die Sprachen der Empfänger, ohne eigenen Text Spiegel des aktuellen Standardtexts (E13), Rückfall am Schritt gekennzeichnet, OutputStamp über alle Sprachstände; IHearingCommunicationStepAppService mit Lesen (Default), Initialisieren/Text/Abweichung (Update), Endfassung je Empfänger als reine Lesung mit OutputStamp, Begleitdokument und ZIP-Zusammenstellung (Documents.Download); Begleitdokument je Teilnehmerzeile als PDF über IDocumentContentPort, Versand mit Anhang, versendeter Wortlaut auf der Zeile, Bounce-Ingest RecordBounceAsync (Outbox.Manage) ohne realen Eingangsweg), Vorlagen, Postausgang (seit RAL-QM-HP-9 mit der Vertretungskopie: HearingOutboxManager liest beim Einstellen jeder Aussendung die wirksame Vertretung über IInstitutionContactDeputyReader und schreibt eine zweite Zeile an ihre Adresse; seit RAL-QM-HP-101 friert jede Zeile die wirksame Sprache ihres Empfängers (Kontaktsprache über IInstitutionContactLanguageReader, sonst Standardsprache; der Renderer löst sie auf) und die Sprache des gesendeten Textes ein, siehe Kommunikationsvorlagen und Verfahrensstände), Einladungen, Portalzugang über den frischen IInstitutionAccountAccessReader aus Authorization.Contracts (RAL-QM-HP-31; ohne Gast- oder Claim-Fallback; seit RAL-QM-HP-30 lesend auch nach dem Ende eines versandten Verfahrens mit Freigaben, die aktiv oder allein durch das Ende widerrufen sind, Schreiben nur in Dispatched, eigener Code PortalAccessMissing ohne Bindung, und die Hearings-eigene HearingPortalParticipationRouteMiddleware für die neutrale 404 der Seitenadresse – siehe Laufzeitsicht 6.4), Stellungnahmen (seit RAL-QM-HP-38: vier Kategorien plus Verzicht mit umgeschriebenen Altwerten, Einwand-Menge an Rückfrage, Abschluss und Bescheidung; Erstabgabe und seit RAL-QM-HP-40 eigenständige Ergänzung als ein Aufruf in zwei Phasen – Vorprüfung, Dateien lesen, Speicherphase in HearingPortalWriteTransaction mit Wiederholung HearingResponseStorageRetry bei einem Deadlock-Opfer –, zweite Erstabgabe über den eindeutigen Index HearingResponseUniqueIndex, festgeschriebene Inhalte und Anlagenzuordnungen unveränderlich, Grenzen aus IDocumentUploadPolicyReader und der Einstellung ResponseAttachmentMaxCount; siehe Laufzeitsicht 6.4 und Querschnitt), fällige Aktionen, Dashboard, Historie — seit RAL-QM-HP-45 mit der verfahrensübergreifenden Recherche (Filter, Zählung, Sortierung und Seitenwahl in SQL, Namen und Feld-Diffs je Seite über das geteilte Lesemodell HearingHistoryReadModel) und deren CSV-Ausleitung (Exportrecht des Moduls, Höchstzahl als protokolliertes Setting, Zeilenzahl im Audit-Log des Aufrufs; siehe Querschnitt), persönlicher Arbeitsvorrat (RAL-QM-HP-1: IHearingAppService.GetWorkQueueAsync liefert Zeilen der Verfahrensübersicht; wessen Sicht es ist, folgt allein aus dem angemeldeten Konto und seinen Rechten — Freigaberecht: genau die eingereichten Verfahren, sonst genau die eigenen laufenden; feste Reihenfolge mit den überfälligen vorn, dahinter maßgebliche Frist und Aktenzeichen, Verfahren ohne Frist am Ende; „überfällig“ dafür als Datenbankabfrage HearingOverdueQuery neben der maßgeblichen Regel HearingOverdueRule; keine Schemaänderung); besitzt RALQMHearings und die RALQMHearing*-Tabellen |
Hearings.Blazor |
interne Prozessseiten, Dashboard, Protokollrecherche /anhoerungen/protokoll (RAL-QM-HP-45), Vorlagen/Postausgang, externe Portaloberflächen; die Kontaktauswahl beim Hinzufügen eines Teilnehmers und in der Nachbeteiligung kennzeichnet den Standardansprechpartner, wählt ihn vor und filtert nach Funktion aus der Werteliste (RAL-QM-HP-9); die Institutionsauswahl beim Hinzufügen bietet nur zuordenbare Institutionen an – aktiv, mit mindestens einem aktiven Ansprechpartner, nicht bereits aktiv beteiligt (RAL-QM-HP-5 AC-2; der Server entscheidet unabhängig davon), die Nachbeteiligung behält ihre Auswahl; im laufenden Verfahren bietet jede aktive Beteiligungszeile „Zugang entziehen“ oder „Zugang wieder freigeben“ mit Bestätigung ohne Begründungsfeld und Fokusrückgabe zum Auslöser über ElementFocus, der Zustand „Zugang entzogen“ steht mit Zeitpunkt als Text in der Zeile (RAL-QM-HP-5 AC-10); die Kachel „Meine offenen Aufgaben“ der Startseite (über HearingPortalWorkspaceOptions registriert) zeigt seit RAL-QM-HP-1 den Arbeitsvorrat des angemeldeten Kontos: acht Zeilen je Seite mit dem CohesionPager (dessen Seitengrößen-Auswahl bewusst aus ist), die Zeile mit den Bausteinen der Verfahrensübersicht (Status- und Überfällig-Abzeichen, Fristchip mit der maßgeblichen Frist, Zuständiger); die Kachel sortiert und siebt nichts selbst; die Teilnahmeansicht des Portals sammelt seit RAL-QM-HP-38 mehrere Dateiauswahlen mit je einem eigenen Feld und sendet sie mit der Stellungnahme, nennt die Frist als Datum nach der UTC-Tagesregel und behält Eingaben nach jeder Abweisung außer der neutralen (siehe Querschnitt 8.5); die Seite Fristvorgaben führt die Anlagen-Höchstzahl in einer eigenen Fläche |
RAL-QM-HP-70, RAL-QM-HP-71 ergänzen innerhalb dieses Slices HearingAdditionalRecipient
als ausgewählte Kontaktstände der bestehenden Beteiligung und HearingReminderRun
als unveränderliche Zielauswahl mit festem internem Berichtsempfänger. Der Postausgangsmanager
verzweigt sämtliche sieben Nachrichtenarten auf Primärkontakt, gewählte Zusatzkontakte und
deren wirksame Vertretung; die Beteiligung und der operative Portalstand bleiben gemeinsam.
IHearingReminderReportAppService liefert den geschützten Bericht, dessen Prozessor/Worker
aktuelle Postausgangszustände auswertet und die Zwischen-/Endmeldung versendet.
Hearings.Blazor besitzt Mehrfachauswahl und /anhoerungen/{id}/erinnerungen[/{runId}].
Die Tabellen, Snapshots, Claims und ReminderRunId gehören ausschließlich Hearings.
RAL-QM-HP-40 ergänzt am bestehenden HearingResponse die Sequenz, Festschreibung und
Auftragsidentität. Der bestehende Kontoportal-Vertrag besitzt Erstabgabe und explizite
Ergänzung; beide nutzen die atomare Dateiverarbeitung aus RAL-QM-HP-38. HearingResponseSequence
hält die Sortierung und den aktuellen Gesamtstand für Portal, Rücklauf und Abschluss zusammen.
Es entsteht kein weiteres Feature. Der alte Änderungsweg wird abgewiesen; der eigene
Zustimmungsumfang aus RAL-QM-HP-39 ist über Consents integriert und wird atomar je Abgabe nachgewiesen. ADR-10
dokumentiert den Übergang von der Vorbereitung zum technischen Schreibwechsel.
Die Eingangsbestätigung RAL-QM-HP-35 bleibt im Hearings-Slice:
HearingAccountPortalAppService legt beim Speichern einer Abgabe je Empfängerart einen
HearingResponseNotification-Auftrag an und hält je Anlage den SHA-256 fest;
HearingResponseNotificationProcessor (Worker HearingResponseNotificationWorker) stellt zu und meldet
Fehler über den Störungsweg aus RAL-QM-HP-37, dessen Detektor und Wiederholung die Aufträge kennen. Authorization
liefert nur die Adressen interner Konten über IStaffNotificationRecipientReader.
Die öffentliche Anzeige RAL-QM-HP-47 bleibt im
Hearings-Slice: das Aggregat trägt Kennzeichen und öffentliche Kennung (Hearing.Publication.cs),
HearingAppService.PublishAsync/UnpublishAsync schalten sie, IPublicHearingAppService liefert
die öffentliche Projektion PublicHearingDto anonym als Liste und dem Integrationsclient als Bestand
(PublicHearingFeedDto, voll oder als Delta mit Entfernungen). Der Controller
HearingPublicationFeedController und die Bearer-Registrierung HearingPublicationFeedAuthentication
gehören dem Hearings-Runtime; der Host komponiert nur. Seit RAL-QM-HP-78 kommen
HearingPublicationReceiptController und PublicHearingReceiptAppService (Quittung), der Leser
HearingPublicationSyncReader und der Monitor HearingPublicationSyncMonitor mit Worker dazu,
alle im Ordner Services/Publication des Hearings-Runtime. Hearings.Blazor besitzt die anonyme Seite
/anhoerungen/oeffentlich im Portal-Layout und die Karte „Öffentliche Anzeige“ der Detailseite.
Der Kopierpfad RAL-QM-HP-12 bleibt im
Hearings-Slice: IHearingCloneAppService liefert eine lesende Vorschau und erzeugt einen
eigenständigen Entwurf aus bestätigten Institutionen und Arbeitsunterlagen. Institutions liefert
aktuelle Kontakte über seinen vorhandenen Vertrag; CAF Documents kopiert Descriptor und Bytes
über IDocumentFilingPort. Die Herkunft samt akteurgebundener Vorgangskennung liegt am
Hearing-Aggregat, der Auftragsfingerabdruck bleibt vom Audit ausgeschlossen. Vorbereitete
Kommunikationsschritte aus RAL-QM-HP-24 werden als neue bearbeitbare Kindobjekte übernommen, globale
Vorlagen dagegen bei Anlage neu gebunden. Keine neue Projekt- oder Modulkante.
RAL-QM-HP-36 ergänzt die
Auswertung der Rückmeldungen ohne weiteres Feature und ohne neues Recht. Hearings.Contracts
trägt den Beteiligungsstand (HearingParticipationState: die acht Stände der Rangliste und
„Zurückgezogen“), die Hinweise (HearingParticipationHint), die von Ansicht und Export geteilten
Filter (GetHearingResponseOverviewInput) und die Herkunft einer Abgabe (HearingResponseOrigin).
In der Runtime leitet HearingParticipationStateRule Stand, Hinweise, „offen“ und Filtertreffer
aus den gespeicherten Sachverhalten ab; HearingParticipationMails liest Einladung und
Zustellergebnis aus den Postausgangszeilen. HearingResponseAppService liefert daraus Übersicht
und CSV-Export aus derselben Lesung, eine Zeile je Institution. Hearings.Blazor zeigt die Zeilen
über HearingParticipationTable im Reiter „Rücklauf“ der Detailseite und im Block
„Beteiligungsstand“ der Rückmeldungsseite /anhoerungen/{id}/rueckmeldungen; Filter und Export
gibt es nur dort. Ableitung: Laufzeitsicht 6.2,
Rechte: Querschnitt §1,
Spalte Origin: Querschnitt §2.
Der formelle Abschluss RAL-QM-HP-51
bleibt ebenfalls im Hearings-Slice. HearingClosureManager bietet eine Zweiphasen-API, die der
direkte Abschluss (HearingAppService.CompleteAsync) und der kombinierte einstufige Abschluss
(HearingAdjudicationAppService.DispatchSingleStageClosureAsync) gemeinsam nutzen (RAL-QM-HP-34-Lehre: eine Regel,
zwei Routen): PrepareClosureAsync vor der Transition (Endfassungsprüfungen, Empfänger mit wirksamem
Endfassungs-Grant, Vorprüfung Vorlage 70, Namensvorprüfung, Berichtsmodell, Bericht über den Port),
unmittelbar danach im try-Block des Anwendungsdienstes AttachClosureReportAndGrantFinalVersion
(Hearing.AttachClosureReport, Endfassungs-Grants) und nach der Transition CompleteClosureAsync
(Abschlussmitteilung, Endfassungsbenachrichtigung 70, Verlauf 810/820, Widerruf laufender Artefakte).
Der Konstruktor des Managers ist unverändert; IDocumentContentPort,
Antworten, Bescheidungen und die Id-Fabrik reichen die Anwendungsdienste als Methodenparameter durch.
Die reinen Vorabprüfungen liegen am Aggregat (Hearing.EnsureCompletable,
EnsureCompletableSingleStage); die Transitionen rufen sie selbst auf. Die Empfängermenge nach
Regel 4 bestimmt HearingFinalVersionRecipients (aktiv, maßgebliche Antwort ist eine Stellungnahme,
Zugang nicht entzogen; maßgeblich ist seit RAL-QM-HP-40 der letzte Stand je Teilnahme nach
HearingResponseSequence.Order), die wirksame Bescheidung
HearingEffectiveReply, die auch die RAL-QM-HP-46-Welle nutzt. Welche Bescheidung eine Beteiligung
erhalten hat, steht an der Beteiligung (AdjudicationDispatchedAtUtc, AdjudicationReplyId);
HearingPortalRules.DispatchedReplies leitet daraus den übermittelten Stand für Portal und
Rückmeldungsübersicht ab. Die Welle (HearingAdjudicationAppService) plant erst (Empfänger nach
Regel 4, bei einer Auswahl genau die gewählten, Pflichtprüfungen) und schreibt dann; das Aggregat
hält fest, wer bedient wurde, und setzt den Zeitpunkt der vollständigen Übermittlung, sobald keine
erforderliche Beteiligung mehr offen ist.
Den Bericht erzeugt HearingClosureReportGenerator hinter IHearingClosureReportGenerator: Modell nach
Regel 4, PDF über HearingClosureReportPdfWriter (Fließtext je Beteiligung, keine Tabelle, /Title und
/Lang de-DE), Ablage über IDocumentContentPort.CreateAsync nach dem RAL-QM-HP-24-Muster. Begleitbrief (RAL-QM-HP-24)
und Bericht teilen den Text-PDF-Kern HearingTextPdfWriter (PDF 1.4, Helvetica/WinAnsi, Umbruch nach
gemessener Glyphenbreite, „Seite n von m“, deterministisch, ohne Paket); HearingCoverLetterPdfWriter
ist darauf zurückgeführt und erzeugt dieselben Bytes wie vorher. Keine neue Projekt- oder Modulkante:
Documents wird nur über die vorhandenen Ports genutzt (CreateAsync, DescribeManyAsync, die
Löschreservierung von IDocumentFilingPort für die Kompensation), Authorization nur über Grants und
Rollen-Seed, Messaging über Ergänzungsbindung, Begleitbrief-Regel, Vorlage und Seed; keine Migration.
Ablauf und Guard-Reihenfolge: Laufzeitsicht.
RAL-QM-HP-41 ergänzt
die Kontaktmeldung ohne weiteres Feature und ohne neues Recht. Eine Institution meldet im
laufenden Verfahren eine andere Kontaktperson; der Referent übernimmt sie, ersetzt sie durch eine
andere Person oder verwirft die Meldung. HearingContactReport ist ein eigenes Aggregat neben dem
Verfahren (Tabelle RALQMHearingContactReports), je Beteiligung höchstens eine offene Meldung. Der
Kontoportal-Vertrag IHearingAccountPortalAppService trägt Melden und Zurückziehen und liefert mit
der Teilnahmeansicht die eigenen Meldungen samt Zustand und die aktive Funktionsliste. Intern liest
und entscheidet IHearingContactReportAppService: Liste, Hinweis (nur Institutionsnamen),
Entscheidungsgrundlage, Übernehmen, Ersetzen, Verwerfen. Die Übernahme in die Stammdaten ruft den
Institutions-Vertrag „einen Kontakt hinzufügen“ (§5.2.2) und den vorhandenen
Empfängerwechsel; „nur dieses Verfahren“ schreibt den Empfängerstand ohne Stammdatenkontakt
(ADR-14).
Die Auswahl zusätzlicher Empfänger verlangt deshalb keinen Kontaktbezug des Hauptempfängers mehr.
Hearings.Blazor zeigt im Portal die Karte „Kontaktperson melden“ der Teilnahmeansicht
(PortalContactReportPanel), in der Verfahrensakte die Kennzeichnung „Kontaktmeldung offen“ an
der Beteiligung mit dem Panel HearingContactReportPanel (Gegenüberstellung, Entscheidungen,
interne Notiz) und den Hinweis HearingOpenContactReportNotice vor Bescheidübermittlung,
kombiniertem Abschluss, Abschließen und Abbrechen. Ablauf:
Laufzeitsicht 6.2, Rechte:
Querschnitt §1,
Persistenz: Querschnitt §2.
5.2.4 ValueLists
| Teilprojekt | Verantwortung |
|---|---|
ValueLists.Contracts |
ValueListKind, Eintrags-/Options-DTOs, IValueListLookup (In-Process-Lesemodell für fremde Feature-Runtimes), die beiden AppService-Interfaces, die drei Permissions, Fehlercodes, die Seed-Ids, Localization, Menüname |
ValueLists (Runtime) |
vier Aggregate über der gemeinsamen Basisklasse ValueListEntry, Standardfristen als Owned Value Object der Verfahrensart, Pflegedienst ohne Löschoperation, cachefreier Lookup, EF-Mapping und Seed-Katalog (seit RAL-QM-HP-119 auch der Kontaktfunktionen-Katalog); besitzt RALQMMarkTypes, RALQMProcedureTypes, RALQMCountries, RALQMContactFunctions |
ValueLists.Blazor |
Pflegeseite /administration/wertelisten (Reiter je Liste links, Formular rechts), Menüeintrag „Wertelisten“ in der Gruppe Administration |
Der Slice ersetzt seit RAL-QM-HP-4 vier zuvor fest verdrahtete Ausprägungsmengen — Kennzeichnungsart und Verfahrensart waren C#-Enums, Land und Funktion eines Ansprechpartners Freitextfelder — durch Katalogtabellen, die ein Systemadministrator über die Oberfläche pflegt. Begründung und Preis stehen in ADR-07.
Eine Tabelle je Liste, ein Aggregat je Tabelle. MarkType, ProcedureType, Country und
ContactFunction erben Code, Namen, Aktivkennzeichen und Sortierung von ValueListEntry; die
Basisklasse selbst ist im Modell ausdrücklich Ignored und damit keine Tabelle. Das ist bewusst
keine gemeinsame Tabelle mit Diskriminatorspalte: Nur die Verfahrensart trägt zusätzliche Spalten
(die drei Standardfristen), die in einer Sammeltabelle für drei Viertel der Zeilen leer stünden,
und die Eindeutigkeit des Code bleibt so ein schlichter Unique-Index je Tabelle — gefiltert auf
[IsDeleted] = 0, damit eine soft-gelöschte Zeile ihren Code nicht dauerhaft belegt.
ValueListKind ist ein reiner Contract-Enum, der eine Liste adressiert, nie einen Wert in
ihr, und wird nirgends persistiert: Ein Enum, der wieder Ausprägungen aufzählte, wäre der Rückweg
in genau das, was diese Story abgeschafft hat.
Die Abhängigkeit läuft nur in eine Richtung. ValueLists.Contracts referenziert
ausschließlich Authorization.Contracts — für den Namen der Permission-Gruppe RALQM — und kennt
weder Hearings noch Institutions. Das ist keine Sparsamkeit, sondern Voraussetzung: Die
konsumierenden Slices (Hearings, Institutions und, für die Rollen-Grants, Authorization) hängen
ihrerseits an ValueLists.Contracts, jede Gegenrichtung wäre ein Projektzyklus. Deshalb
gibt es für das Lesen der Auswahloptionen auch kein hearings- oder institutionseigenes Recht,
sondern das eigenständige RALQM.ValueLists.Read (siehe
Querschnittliche Konzepte §1).
Fremde Slices sehen nur Ids und Anzeigenamen. Hearings speichert MarkTypeId und
ProcedureTypeId (beide Pflicht), Institutions CountryId und je Kontakt FunctionId (beide
optional) — Guid-Spalten ohne Foreign Key, wie es die Modulgrenze für jede
modulübergreifende Referenz verlangt. Aufgelöst wird über IValueListLookup — in den
*.Blazor-Projekten über den permissiongeschützten IValueListLookupAppService daneben. Die
Auflösung ist nach Richtung verschieden streng, und diese Unterscheidung liegt je Slice an genau
einer Stelle (HearingValueListNameMap, InstitutionValueListNameMap):
| Richtung | Verhalten bei unbekannter oder deaktivierter Id |
|---|---|
| Schreiben (Anlegen/Bearbeiten) | Fachfehler im Anwendungsdienst, nichts wird gespeichert |
| Lesen (Liste, Detail, CSV) | Platzhalter — und strukturierte Warnung; eine kaputte Zeile darf keine ganze Seite fällen |
| Ausgehender Versand (Hearings) | Fachfehler InvalidProcedureTypeReference statt Platzhalter — ein Anschreiben mit einem Gedankenstrich an der Stelle der Verfahrensart verlässt das Haus nicht |
Beide Karten lösen eine ganze Seite mit einem Aufruf je Liste auf, nicht mit einem je Zeile.
Kein Cache. Der Lookup liest bei jedem Aufruf über die Repositories; eine neu angelegte, umbenannte oder reaktivierte Ausprägung ist ohne Neustart und ohne Invalidierungspfad sichtbar. Fällt das später messbar ins Gewicht, ist ein Cache mit Invalidierung beim Schreibzugriff eine lokale Optimierung dieses Slices und ändert an keiner hier beschriebenen Grenze etwas.
ValueLists.Blazor referenziert CAF.Modules.UI.Blazor — anders als die drei anderen fachlichen
Feature-*.Blazor, aber wie Settings.Blazor — nicht direkt: Die Pflegeseite lädt je Reiter
eine vollständige Liste und braucht deshalb weder Grid-Datenadapter noch Toolbar-Preset aus der
Grid-Naht. Über den produktweiten UI-Baustein kommt das Modul ohnehin transitiv; eine direkte
Referenz würde eine Abhängigkeit behaupten, die es nicht gibt.
Der Kontaktfunktionen-Katalog wird seit RAL-QM-HP-119 gesät.
RAL-QM-HP-4 hatte diese Liste bewusst leer ausgeliefert, weil Kontaktfunktionen Kundendaten sind und
ein Seeder keine Fachbegriffe erfinden darf. Der Katalog aus 15 Rollen in neutraler, männlicher und
weiblicher Form (44 Codes, deutsche und englische Namen) ist aus dem Altexport des Anhörungsportals
abgeleitet und vom PO bestätigt, und der Institutionsimport weist Kontakte mit unbekannter Funktion ab —
der Katalog muss also auf jeder Umgebung vor dem ersten Import stehen. ValueListsDataSeedContributor
trägt ihn wie die drei anderen Listen idempotent je Code nach und überschreibt nie, was ein
Administrator gepflegt hat; zusätzlich legt er keinen Eintrag an, dessen deutscher Name schon unter
einem anderen Code existiert (kein Namenszwilling für Import und Auswahlfelder). Die Ids sind je
Katalogordinal fest (a4000000-…); ein Code darf nie wie der Name eines anderen Eintrags lauten, weil
der Lookup Codes und Namen in einem Durchgang vergleicht. Der Demo-Seed behält seine eigenen
DEMO-FUNKTION--Codes daneben. Eine Migration gibt es nicht; der Seeder läuft mit dem Migrator.
5.2.5 Filing
Der Slice besitzt die verfahrensunabhängige Ablage aus
RAL-QM-HP-19: einen gemeinsamen Bereich und je
berechtigtem internem Konto einen persönlichen Bereich (FilingAreaKind), darin Ordner und
Dateien (FilingEntryKind) bis zu 16 Ebenen tief, dahinter den zweistufigen Papierkorb
(FilingEntryState: Active, Trashed, Purging, Purged).
| Teilprojekt | Verantwortung |
|---|---|
Filing.Contracts |
Bereichs-, Ordner-, Element-, Upload- und Papierkorb-DTOs, seit RAL-QM-HP-16 Übernahme- und Verwendungs-DTOs, IFilingAppService und IFilingAdministrationAppService, die Permissions RALQM.Filing mit den Kindern .Read, .Manage, .Purge sowie das eigenständig vergebbare RALQM.Filing.Transfer, Fehlercodes RALQM.Filing:…, Localization, Menüname |
Filing (Runtime) |
Aggregate FilingArea, FilingEntry und (RAL-QM-HP-16) FilingHearingUsage samt Fachhistorie FilingHistoryEntry; Namens-, Hierarchie- und Tiefenpolitik, Bereichsrevision als Sperre jeder Mutation, Papierkorb mit FilingPurgeProcessor/FilingPurgeWorker, administrative Bereichsübertragung, Übernahme ins Verfahren und Verwendungsnachweis; EF-Mapping; besitzt RALQMFilingAreas, RALQMFilingEntries, RALQMFilingHistory, RALQMFilingHearingUsages |
Filing.Blazor |
Explorer /filing über den separat paketierten CohesionDataBrowser, gemeinsame Papierkorbansicht /filing/trash (Ablage- und Verfahrenszeilen), administrative Bereichsübertragung /administration/ablage-uebertragen, seit RAL-QM-HP-16 die Verwendungsansicht je Datei und die Löschbestätigungen mit Verfahrensliste |
Der Slice besitzt keine Dateiinhalte. Metadaten und Bytes liegen wie überall sonst bei ABP
File Management hinter dem neutralen IDocumentFilingPort von CAF.Modules.Documents.Contracts;
Filing speichert Bereichseigentum, Elementzuordnung, Papierkorbzustand, Fachhistorie und — seit
RAL-QM-HP-16 — den Verwendungsnachweis. Die persönlichen Bereiche fremder Konten bleiben bei jeder
Operation verborgen, auch für Administratoren (siehe
Laufzeitsicht §6.5).
Filing.Contracts referenziert ausschließlich Authorization.Contracts — auch dort, wo der
Slice mit Hearings zusammenarbeitet: Der Vertrag bleibt schmal, die Verzahnung liegt in der
Runtime. Verfahrensfakten führt er wie schon FilingTrashItemDto als blanke Guid/string;
HearingDocumentPurpose, HearingDocumentRole und HearingStatus liegen als zahlengleiche
Filing-Enums gespiegelt daneben (FilingHearingDocumentPurpose, FilingHearingDocumentRole,
FilingHearingStatus). Die Zahlenwerte sind Draht- und Persistenzvertrag und dürfen zwischen
Original und Spiegel nicht auseinanderlaufen.
Die fachliche Ablage-Verfahrensintegration wird durch Filing orchestriert. Filing (Runtime) referenziert
Hearings.Contracts. Seit RAL-QM-HP-65 konsumiert Hearings (Runtime) zusätzlich ausschließlich die
prozesslokalen Bestands-/Recovery- und Ausführungspolicyverträge aus Filing.Contracts
(ADR-21).
Diese Gegenkante erlaubt weder Filing-Entities noch Repositories, Dateizugriff oder Filing-Anwendungsfälle.
Beide verzahnten
Abläufe orchestriert deshalb Filing und holt sich die Verfahrenshälfte über einen prozesslokalen
Hearings-Port mit [RemoteService(false)]: IHearingDocumentTrashPort für entfernte
Verfahrensdateien und die Kopie in die Ablage, IHearingDocumentAdoptionPort (RAL-QM-HP-16) für die
Übernahme in der Gegenrichtung. Für den Verwendungsnachweis gibt es weiterhin keinen Usage-Provider
nach dem Muster von IInstitutionUsageProvider: Die neue Gegenkante ist ausschließlich für den
produktweiten Schreib-/Löschschutz und die zentrale Fristpolicy bestimmt. Verwendungszeilen sind Filing-Daten; von
Hearings kommen nur die autorisierten Fakten zu bekannten Verfahrensdokumenten.
Umgekehrt gibt es genau eine UI-Kante. Der Bedien-Einstieg „Aus der Ablage übernehmen“ liegt
in der Verfahrensakte, deshalb referenziert Hearings.Blazor seit RAL-QM-HP-16 Filing.Contracts
und konsumiert IFilingAppService. Das ist eine Feature-Blazor-→-fremde-Contracts-Kante, dieselbe,
die jede andere Feature-UI bereits trägt; die enge Hälfte Hearings.Blazor → Filing (Runtime)
bleibt verboten und ist in RepositoryArchitectureTests als roter Gegenfall neben der erlaubten
Kante mitgeführt. Es wurde dafür keine Regel gelockert.
5.2.6 Abhängigkeitsrichtung der Feature-Slices
| Consumer | Erlaubte eigene Projektabhängigkeiten |
|---|---|
| ValueLists Contracts | Authorization Contracts |
| Institutions Contracts | Authorization Contracts |
| Hearings Contracts | Authorization Contracts, Documents Contracts |
| Filing Contracts | Authorization Contracts |
| Consents Contracts | Authorization Contracts |
| ValueLists Runtime | ValueLists Contracts |
| Consents Runtime | Consents-, Authorization-Contracts (IInstitutionAccountAccessReader.GetActivationCandidateAsync für die Aktivierungszustimmung, 5.2.7) |
| Institutions Runtime | Institutions-, ValueLists-Contracts |
| Authorization Runtime | Authorization-, Institutions-, Hearings-, Filing-, ValueLists-, Consents- (Aktivierungsnachweis als Zugangsbedingung, RAL-QM-HP-39) und Documents-Contracts |
| Hearings Runtime | Hearings-, Institutions-, ValueLists-, TextTemplates-, Consents- (Zustimmungsnachweis im Abgabeabschluss, RAL-QM-HP-39), Filing- (nur Bestands-/Recovery-Schutz und zentrale Fristpolicy, ADR-21) und Documents-Contracts; ABP AuditLogging Domain (IAuditLogRepository — der Verfahrensverlauf liest die Entity History des Verfahrens als Store-Lesung hinter der Hearings-Berechtigung, nicht über den berechtigungsgeschützten IAuditLogsAppService; RAL-QM-HP-7, Review zu !79) |
| TextTemplates Runtime | eigene Contracts; nativer ABP-TextTemplateManagement-Application-Pfad |
| Filing Runtime | Filing-, Authorization-, Hearings- und Documents-Contracts (die Verzahnung mit Hearings liegt in der Runtime, nicht im Vertrag; siehe 5.2.5) |
| Produkt UI.Blazor | Produkt-Contracts, Hearings-Contracts (Statusenums), CAF.Modules.UI.Blazor |
| Produkt-Shell | Produkt-Contracts, Authorization-/Institutions-/Gdpr-/Hearings-Contracts, Produkt UI.Blazor |
| ValueLists Blazor | ValueLists-, Authorization-Contracts, Produkt-Shell-Contracts, Produkt UI.Blazor (CAF.Modules.UI.Blazor nur transitiv, siehe 5.2.4) |
| Institutions Blazor | Institutions-, Authorization-, ValueLists-Contracts, Produkt-Shell-Contracts, Produkt UI.Blazor, CAF.Modules.UI.Blazor |
| Authorization Blazor | Authorization-Contracts, Produkt-Shell-Contracts, Produkt UI.Blazor, CAF.Modules.UI.Blazor |
| Hearings Blazor | Hearings-, Institutions-, ValueLists-, Filing-Contracts (RAL-QM-HP-16, Einstieg „Aus der Ablage übernehmen“), Consents-Contracts (RAL-QM-HP-39: Zustimmungsseite im Portal, Bestätigung im Abgabeformular, Nachweisspalte), Produkt-Shell-Contracts, Produkt UI.Blazor, CAF.Modules.UI.Blazor |
| Filing Blazor | Filing-, Authorization-, Documents-Contracts, Produkt-Shell-Contracts, Produkt UI.Blazor, CAF.Modules.UI.Blazor |
| Consents Blazor | Consents-, Authorization-Contracts, Produkt-Shell-Contracts, Produkt UI.Blazor |
| ABP-Ersatz-Features Blazor (Identity, Languages, TextTemplates, AuditLogs, Gdpr, Settings) | eigene Contracts, Produkt-Shell-Contracts, Produkt UI.Blazor, CAF.Modules.UI.Blazor (Settings nur transitiv) |
| Host | Client, Framework Authentication/Documents/UI, alle Feature Runtime+Blazor |
Die Tabelle nennt Projektabhängigkeiten. Jedes *.Blazor-Projekt referenziert zusätzlich das
Cohesion-Paket direkt — Begründung in
5.1.3. Die Kante Feature-Blazor →
Produkt UI.Blazor ist die einzige erlaubte Kante zwischen UI-Assemblies; Feature-Blazor →
Feature-Blazor und Shell → Feature-Blazor bleiben verboten (Regel ClientToFeatureRuntime).
Immer verboten: Contracts → Runtime/EF/Host, Feature-Blazor → Feature-Runtime oder eine
fremde Runtime, GZ-Runtime → fremde GZ-Runtime oder deren Entities/Repositories/Tabellen, sowie
jedes Modul → ausführbarer Host. Über Modulgrenzen (auch zwischen Features) werden nur IDs
gespeichert, keine Foreign Keys — siehe Datenmodell in der Verteilungssicht
und Persistenzregeln in Querschnittliche Konzepte §2.
Diese Trennung ist eine Compile-Time-Eigenschaft, durch Architekturtests abgesichert, keine
bloße Ordnerkonvention. Die beiden Regeln FeatureRuntimeToHostOrClient und
FeatureRuntimeToForeignRuntime leiten die Feature-Zugehörigkeit aus dem Projektnamen ab statt aus
einer gepflegten Liste; Every_feature_runtime_project_on_disk_is_guarded_in_both_directions
liest Features/*/Runtime vom Dateisystem und verlangt für jedes geordnete Paar einen Verstoß.
Die sechste fachliche Feature-Runtime, Consents (5.2.7, RAL-QM-HP-39), war damit ab dem
Anlegen ihrer Projektdatei abgesichert und nicht erst, wenn jemand eine Regel nachträgt.
5.2.7 Consents
Seit RAL-QM-HP-39 (ADR-11). Der Slice ist nach der Abhängigkeitstabelle nummeriert, damit deren verlinkter Anker stabil bleibt.
| Teilprojekt | Verantwortung |
|---|---|
Consents.Contracts |
ConsentDocumentKind (Nutzungsbedingungen, Datenschutzhinweise), Fassungs-, Bestätigungs- und Nachweis-DTOs, die AppService-Interfaces für Pflege, Lesen der geltenden Fassungen und Aktivierung, die In-Process-Ports IConsentProofRecorder (Hearings) und IConsentProofReader (Authorization, Hearings), die Rechte RALQM.Consents.Documents und .Publish, Fehlercodes, die gesamte Lokalisierung der Zustimmung (Ressource RALQMConsents) |
Consents (Runtime) |
Fassungskatalog RALQMConsentDocumentVersions (nur Einfügen; Auflösung: höchste laufende Nummer je Art mit „gültig ab ≤ T“), Zustimmungsnachweise RALQMConsentProofs (nur Einfügen, je Konto ein Aktivierungsnachweis, je Abgabe ein Nachweis), Schutz gegen Ändern und Löschen beider Tabellen, Veröffentlichung in serialisierbarer Transaktion, Aktivierungsdienst, Demo-Fassungen nur unter RALQM:SeedDemoData |
Consents.Blazor |
Pflegeseite /administration/rechtstexte für den Systemadministrator, Menüeintrag „Rechtstexte“ in der Gruppe Administration |
Die Zustimmungsseite /portal/zustimmung liegt im Portal (Hearings Blazor), weil das Portallayout
dort liegt und Feature-Blazor → Feature-Blazor verboten ist. Den Bestätigungsbaustein mit zwei
Kästchen und Lesedialog teilen sich Zustimmungsseite und Abgabeformular über Produkt UI.Blazor
(ConsentDocumentConfirmation); er erhält Texte als Parameter und ruft keinen Dienst.
Der Nachweis einer Abgabe entsteht im Abgabeabschluss von Hearings über IConsentProofRecorder in
der umgebenden Unit of Work und damit in derselben Datenbanktransaktion (gemeinsamer
HearingPortalDbContext). Über die Modulgrenze werden nur Kennungen gespeichert (UserId,
HearingResponseId), keine Foreign Keys.
5.3 Direkt verwendete ABP-Bausteine
Ergänzend zu den eigenen Modulen nutzt die Anwendung ABP-Vertikalen als Implementierungssubstrat,
ohne sie zu eigenen CAF-Modulen zu machen: Account Public/Admin und Identity Pro (Login,
lokale Benutzer/Rollen), Permission Management, Setting Management, Audit Logging, Text
Template Management, Language Management/GDPR, File Management (Domain/EF/Application; keine
generische UI/API) sowie BLOB Storing Database und Emailing/Background Workers. Von diesen
Vertikalen wird jeweils nur die Serverhälfte komponiert (Application/HttpApi/EF); ihre
Blazor-Oberflächen sind durch Produktseiten ersetzt und die zugehörigen Pakete entfernt. Vom
LeptonX-Theme bleibt allein die MVC-Hälfte, die die /Account/**-Razor-Pages trägt.
5.4 Zusammenspiel im Request
Wie ein Blazor-Seitenaufruf durch Contract, Application Service, Aggregate und Persistenz läuft, beschreibt die Laufzeitsicht. Betriebs- und Deployment-Aspekte (ein Deployable, eine Datenbank, lokale Infrastruktur) stehen in der Verteilungssicht.
Weiterführend: Entwicklungsleitfaden, Getting Started, Konventionen.
06. Laufzeitsicht
Dieses Kapitel zeigt das dynamische Verhalten der in der Bausteinsicht beschriebenen Module anhand der wichtigsten Laufzeitszenarien: Anmeldung, Anhörungs-Lebenszyklus, externe Kontoprovisionierung, Dokumentfreigabe, Arbeitsablage mit Papierkorb und die Übernahme einer Ablagedatei ins Verfahren. Alle Abläufe sind im aktuellen Stand implementiert — mit den in Risiken und technische Schulden benannten offenen Nachweisen und der durch RAL-QM-HP-31 umgestellten Institutionsbindung. Details zu Modulgrenzen und Ownership stehen in der Bausteinsicht und den Querschnittlichen Konzepten, verbindliche Bauregeln im Entwicklungsleitfaden.
6.1 Login und Authentifizierung
Die Produktshell baut Menüs allein über Routerparameter auf (RAL-QM-HP-73). Initialisierung
und Menüabfragen werden serialisiert. IAsyncDisposable beendet die eigene Lebensdauer
und wartet bereits laufende Arbeit ab, bevor der Circuit-Scope freigegeben wird; danach
startet keine weitere Abfrage. ICancellationTokenProvider.Use(CancellationToken.None)
entkoppelt diese renderer-eigene Arbeit vom kurzlebigen HTTP-RequestAborted. Der Abbau
wartet sie unter den bestehenden Provider-Timeouts ab. Cancellation-, Scope- und andere
unerwartete Fehler werden nicht abgefangen oder unterdrückt.
Keycloak ist Token-Issuer und Identitätsquelle; CAF.Modules.Authentication
(modules/Authentication/src) ist der anwendungsneutrale OIDC-Client. Er registriert Cookie- und
OIDC-Authentifizierung (CAFAuthenticationServiceCollectionExtensions), setzt eine Cookie-Session-
Policy (CAFApplicationCookieSessionPolicy, CAFApplicationCookieTokenPropagation) und hält die
Session über einen revalidierenden AuthenticationStateProvider
(CAFRevalidatingAuthenticationStateProvider, CAFSecurityStampRevalidationPolicy) periodisch
aktuell.
sequenceDiagram
actor U as Benutzer
box transparent RALQM-Host
participant App as Blazor Web App (Shell)
participant Auth as CAF.Modules.Authentication
participant Id as ABP Identity (lokal)
end
participant Kc as Keycloak
U->>App: Aufruf einer geschützten Seite
App->>Auth: Challenge auslösen
Auth->>Kc: Redirect Authorization Code
+ PKCE (code_challenge)
U->>Kc: Anmeldung (Credentials/2FA)
Kc-->>Auth: Redirect mit Code
Auth->>Kc: Code-Tausch inkl. code_verifier
Kc-->>Auth: ID-/Access-/Refresh-Token
Auth->>Auth: Pflicht-Claims prüfen (u. a. sub)
Auth->>Id: IdentityUser über sub
finden/verknüpfen
Id-->>Auth: GZ-Rolle(n) und Grants
Auth-->>App: Cookie-Session gesetzt
App-->>U: Zielseite mit gewährten Permissions
Wesentliche Punkte:
- Die Verknüpfung zwischen Keycloak-Identität und lokalem
IdentityUserverwendet ausschließlich den stabilen OIDC-Subject-Identifiersub, niemals die E-Mail-Adresse. - Rollen (
RALQMAdministrator,RALQMCaseOfficer,RALQMManagement) sind lokale ABP-Grants; sie werden aus den Feature-Contracts komponiert (siehe Authorization und Autorisierung). - Die Cookie-Session wird nicht nur beim Login geprüft:
CAFRevalidatingAuthenticationStateProviderund die Security-Stamp-Policy erzwingen eine periodische Neuprüfung, sodass eine serverseitig gesperrte oder geänderte Identität in laufenden Circuits zeitnah wirkt. - Abmeldung läuft über
CAFAuthenticationSignOutlokal und bei Keycloak; Multi-Tenancy ist deaktiviert, Keycloak-Gruppen ersetzen keine GZ-Rolle oder ABP-Permission. - Jeder nachfolgende Application-Service-Aufruf prüft serverseitig erneut seine Permission — die Anmeldung allein gewährt keinen Fachzugriff.
Organisationsanmeldung und Ausfallweg (RAL-QM-HP-63, ADR-15)
sequenceDiagram
actor M as Mitarbeitende
participant P as Portal (/login)
participant K as Keycloak (Realm ral)
participant O as Organisationsdienst
M->>P: Mit Organisationskonto anmelden
P->>K: /Account/Login?anmeldeweg=organisation → authorize mit kc_idp_hint=organisation
K->>O: Brokering (PKCE)
O-->>K: Code / ID-Token des Organisationskontos
K->>K: Federated Identity vorhanden? sonst First-Broker-Login „Deny Access“
K-->>P: Code (Subject des bestehenden Keycloak-Benutzers, Claim identity_provider)
P->>P: Sicherheitsprotokoll „LoginPath/SignedInViaOrganisation“, ABP-Anmeldung über sub
Hat das Konto einen zweiten Faktor eingerichtet (RAL-QM-HP-11, ADR-19), fragt Keycloak nach dem
Brokering im Post-Broker-Login-Ablauf ralqm-organisation-post-login-otp den Code ab, bevor es
den Code an das Portal ausgibt; auf dem Passwortweg tut das der Standard-Browserablauf.
Ist der Organisationsdienst dreimal in Folge nicht erreichbar oder der Ausfallweg erzwungen, blendet die Anmeldeseite den Organisationsknopf aus und verweist neutral auf die Portal-Zugangsdaten; der Ablauf ist dann die bekannte Anmeldung aus 6.1.
6.2 Anhörungs-Lebenszyklus
Die fachliche Prozesssicht KP-HP-01 ergänzt diese technische Laufzeitsicht um Verantwortung, Freigaben, Abschlussvarianten und den getrennten Versandablauf. Der lokale Prozessreport und die interne Dokumentationsvorschau öffnen daraus denselben bpmn-js-Viewer. Scope, Quellstand und fachliche Abnahme stehen auf der Begleitseite. Der Prozesskatalog führt zu den ergänzenden Sichten für Beteiligung, Rückmeldungen, Unterlagen, Kommunikation sowie Konten und Zuständigkeiten.
Der Hauptstatus einer Anhörung (RALQMHearings, Feature Hearings) ist:
stateDiagram-v2
direction TB
[*] --> Draft: anlegen
Draft --> PendingApproval: zur Freigabe einreichen
PendingApproval --> Approved: freigeben (andere Person)
Approved --> Dispatched: Versand über Outbox
Dispatched --> Adjudication: zweistufige Variante
Adjudication --> Completed: Verfahren abschließen
Dispatched --> Completed: einstufig (US-33)
Completed --> [*]
note right of PendingApproval
benannte Rücksprünge und Abbruch
nach Fachregel (nicht dargestellt)
end note
Die Wahl der Abschlussvariante (US-33) entscheidet, ob Adjudication als eigener Status
durchlaufen wird — siehe Punkt 7 unten und Einführung und Ziele.
sequenceDiagram
actor R as Referent (RALQMCaseOfficer)
actor M as Geschäftsführung (RALQMManagement)
box transparent RALQM-Host
participant H as Hearings AppService
participant Out as Hearing-Outbox
participant W as ABP Background Worker
end
R->>H: Anhörung anlegen (Draft)
R->>H: Teilnehmer zuordnen (InstitutionId
aus Institutions.Contracts)
R->>H: Dokumente zuordnen (DocumentId
aus Documents.Contracts)
R->>H: Zur Freigabe einreichen (PendingApproval)
M->>H: Freigeben (andere Person als Einreichung,
Composition Hash sperrt Stand)
H->>Out: Versand enqueuen
(RALQMHearingOutboxMessages)
Out->>Out: Sendeversuche mit Retry und
Idempotency Key (RALQMHearingSendAttempts)
Note over H: Status Dispatched —
Adjudication-Fenster: nur Endfassungen neu/ersetzt
W->>H: Fristen als Due Actions verarbeiten
(RALQMHearingDueActions)
H->>H: Rückmeldungen der Teilnehmer
(RALQMHearingResponses, ...Replies)
R->>H: Bescheidung versenden (Fenster
schließt, Komposition fixiert)
R->>H: Abschließen (Endfassung freigeben,
Rückmeldungsübersicht erzeugen)
Note over H: Status Completed
- Anlegen: Draft entsteht über den owning Application Service; jede Statustransition ist eine
benannte Aggregate-Operation (kein
SetStatus). Die Anlage als Kopie (RAL-QM-HP-12) liest die Quelle in jedem Hauptstatus ohne Mutation und zeigt aktuelle Kontakte, Pflichtpartner, frische Fristvorschläge und kopierbare Arbeitsunterlagen. Bestätigung bindet Quell- und Vorschauzustand; geänderte Stammdaten verlangen eine neue Vorschau. Ausgewählte Dateien erhalten eigene Bytes und Kennungen; Zuordnungen und Kommunikationsabweichungen zeigen nur auf neue ausgewählte Beteiligungen. Alle Schritte samt Herkunft und Zielhistorie bilden eine Serializable-Transaktion. Dieselbe Vorgangskennung mit demselben Akteur/Auftrag liefert nach erneuter Autorisierung das bestehende Ziel. Freigaben, Antworten, Zugangsdaten, alte Fristen und Versandgeschichte werden nicht kopiert. - Teilnehmer/Institution: Hearings referenziert Institutionen nur über die
InstitutionIdausInstitutions.Contracts— keine Cross-Module-Navigation oder -Foreign-Key. Zuordnen, Zurückziehen und Wiederaufnehmen einer Beteiligung gibt es seit RAL-QM-HP-5 nur im Entwurf, auch wieder nach Rückzug der Einreichung oder Ablehnung. Ab der Einreichung weist das Aggregat das Zurückziehen mitHearingNotEditableab, nach dem Versand – inDispatchedundAdjudication– mit dem eigenen CodeWithdrawalNotAllowedAfterDispatch, dessen Meldung den vorgesehenen Weg nennt: den Zugangsentzug je Beteiligung (siehe §6.4). Das frühere Zurückziehen nach dem Versand ist ersatzlos entfallen; „betrifft uns nicht“ ist eine Rückmeldung der Institution oder eine interne Erfassung, kein Zurückziehen. Früher nach dem Versand zurückgezogene Beteiligungen bleiben zurückgezogen. - Freigabe: Der Wechsel nach
Approvederzwingt eine andere handelnde Person als die Einreichung und sperrt die geprüfte Dokumentzusammensetzung über einen Composition Hash. Seit RAL-QM-HP-25 schreibt jede Freigabe und jede Ablehnung in derselben Unit of Work einen dauerhaften Benachrichtigungsauftrag (RALQMHearingApprovalDecisionNotifications, genau einer je Entscheidungsdatensatz) an den in diesem Moment zuständigen Referenten; ein späterer Zuständigkeitswechsel adressiert ihn nicht um. Ein periodischer Worker stellt ihn wie die Störungsbenachrichtigung zu (Claim je Versuch, Wiederholung nach Frist, Begründung aus dem Entscheidungsdatensatz); Zustellfehler und ein fehlender oder inaktiver Zuständiger werden als Störung sichtbar und nie an andere Konten verteilt. Die Prüfansicht der Geschäftsführung nennt die Zuständigkeit, kennzeichnet zugeordnete Unterlagen ohne abrufbaren Inhalt als Warnung und benennt die noch fehlende Bindung der Anschreiben-Endfassung (RAL-QM-HP-24); sie ändert keine Daten. Seit RAL-QM-HP-22 verlangt die Einreichung aktuelle Anhörungsunterlagen (ZweckHearingMaterial, keine überholte Version) mit Grant je Beteiligung, den gebundenen Einladungstext aus RAL-QM-HP-26 und zustellfähige Empfänger: die aktuelle Institution und der gewählte Kontakt jeder aktiven Beteiligung werden in einer Lesung überInstitutions.Contractsgeprüft (HearingRecipientValidator), ein anderer aktiver Kontakt heilt nichts, und jede Abweisung nennt die Institutionen, ohne etwas zu schreiben. Einreichung und Rückzug ordnen denselben Auftrag mit Zielgruppe Geschäftsführung: die aktiven Konten der RolleRALQMManagementwerden bei Zustellung überAuthorization.Contractsaufgelöst und je einmal beliefert; ohne solches Konto entsteht eine Störung, keine Ersatzverteilung. Dieselbe Empfängerprüfung läuft vor dem Erstversand auf dem freigegebenen Stand und weist die ganze Welle ab, bevor ein Zugangsdatum oder eine Postausgangszeile entsteht. Seit RAL-QM-HP-6 ist die bescheinigte Adresse die operative der Beteiligung: Prüfung, Erstversand, Erinnerungen, Bescheid, Abschluss- und Abbruchmitteilung lesen denselben Empfängerstand aus den Snapshot-Spalten; eine Stammdatenänderung wird als Abweichung gezeigt und nur auf ausdrücklichen Befehl des Referenten übernommen (Übernahme, Empfängerwechsel, Adresskorrektur; nur inDraft,Dispatched,Adjudication). Jede Postausgangszeile friert den verwendeten Stand ein, die Vertretungskopie denselben; die Verfahrensakte zeigt je Beteiligung Stand, Abweichung und die Stände der Aussendungen. Das Portal zeigt den operativen Stand der Beteiligung, einschließlich einer ausdrücklich bestätigten Übernahme; historische Aussendungen bleiben unverändert (ADR-08). Seit RAL-QM-HP-24 ist der Wortlaut jeder Aussendung der Kommunikationsschritt des Zwecks: eine einmalige Kopie des gebundenen Vorlagentexts (beim ersten Öffnen durch den Referenten oder automatisch vor der ersten Zeile), je Institution mit eigener Abweichung, gesperrt für das erste Anschreiben ab der Einreichung und für jeden Zweck ab der ersten Postausgangszeile. Referent und Geschäftsführung prüfen dieselbe Endfassung je gewähltem Empfänger (Briefkopf, Anschrift, Ansprechperson, Betreff, Datum, Wortlaut, Zeichnung, Anhang) als reine Lesung; der Erstversand verlangt den Stempel dieser Prüfung, wenn die Versandseite ihn mitgibt. Jede Teilnehmerzeile entsteht mit ihrem Begleitdokument (PDF über CAF Documents, Absender dieses Moments, Zeichnung nach Zweck) und geht als Nachricht mit Anhang hinaus; ohne vollständigen Absender entsteht weder Dokument noch Zeile. Jede Aussendung trägt genau einen tokenfreien Portal-Link. Die Zeile hält den versendeten Wortlaut fest; eine vertrauenswürdig zugeordnete Unzustellbarkeit setzt das aktuelle Ergebnis des Empfängers, ohne die Übergabe umzuschreiben. - Versand: Kein "Best effort" im Request — eine persistente Hearing-Outbox mit Sendeversuchen,
Retry und Idempotency Keys entkoppelt Versand von der HTTP-Antwort.
Seit RAL-QM-HP-23 meldet die
Versandseite den Erfolg des Erstversands als „Befragung eingeleitet“ und den Zeilenstatus als
„an Mailtransport übergeben“ - beides bedeutet nicht „zugestellt“:
Dispatched,DispatchedAtUtc, der Verlaufseintrag, die Hauptaufträge aller aktiven Beteiligungen (plus Vertretungskopie aus RAL-QM-HP-9) und die Fristaktionen werden in einer Transaktion festgeschrieben; scheitert ein Schritt vor dem Commit, bleibt nichts davon sichtbar, ein paralleler oder wiederholter Aufruf erzeugt keine zweite Welle.SentAtUtceiner Postausgangszeile dokumentiert die Übergabe an den Mailtransport, keinen Eingang im Postfach; die Statusansicht je Empfänger (GetDeliveryStatusAsync, Recht.Dispatch) benennt sie so und zeigt je Zeile die Sendeversuche in ihrer Reihenfolge mit Ergebnis und sicherem Fehlercode – ein Retry (.Outbox.Manage, nur für nicht übergebene Zeilen) fügt einen Versuch mit demselben Wortlaut hinzu und überschreibt keinen. Ein Transportfehler ändert weder Status noch Einleitungszeit. Eine korrigierte Neuzustellung ist ein eigener.Dispatch-Befehl mit Verfahrens- und Nachrichtenstempel sowie akteurgebundener Operation-ID. Sie friert die korrigierte Adresse in einem neuen Auftrag ein; der alte bleibt mit Wortlaut, Empfänger und Versuchen alsSupersedederhalten. Unique-Indizes verhindern zweite Nachfolger. Erst die erfolgreiche SMTP-Übergabe des Nachfolgers erledigt die alte Störung, ohne ihr einen erfundenenSentAtUtczu geben. Technischer Retry ändert weiterhin keine Auftragsdaten. Manuelles Ausstellen und Erneuern von Einladungen versendet ebenfalls eine Nachricht und ist nur inDispatchederlaubt. InApprovedwird eine solche Aktion vor jeder Änderung an Zugang, Postausgang oder Historie abgelehnt; die Oberfläche deaktiviert sie. Erst der reguläre Versand schaltet den Portalzugang frei und erzeugt die erste Einladungswelle. - Fristen/Antworten: Persistente Due Actions und ABP Background Workers lösen fällige Aktionen
aus; Teilnehmer legen ihre Stellungnahme über das Benutzerkonto ihrer Institution innerhalb
der wirksamen Frist an oder ergänzen sie um einen neuen unveränderlichen Beitrag. Einen
Gastpfad gibt es seit RAL-QM-HP-31 nicht mehr. Seit
RAL-QM-HP-38 ist die Stellungnahme eine von
vier Kategorien oder der Verzicht, und Änderungswünsche und Ablehnung – die Einwände –
brauchen eine Begründung von 15 Zeichen oder eine eigene Anlage (
HearingResponseRules). Erstabgabe und Ergänzung sind je ein Aufruf; Ablauf in §6.4. Das Fenster ist am UTC-Fristtag offen und ab dem Folgetag geschlossen; ein versandtes Verfahren ohne wirksame Frist hat kein Fenster (ResponseDeadlineMissing). RAL-QM-HP-40 liefert die vollständige geordnete Antwortfolge: Rücklauf, Bescheidung und Abschluss wählen zuerst den jüngsten Beitrag je Teilnahme. Historische Anlagen und Bescheidtexte bleiben am ursprünglichen Beitrag lesbar. Ein wiederholter identischer Auftrag liefert denselben Beitrag; neue Inhalte benötigen eine neue Auftragskennung. Der alte Änderungsweg ist gesperrt. Consents (RAL-QM-HP-39) prüft beide aktuellen Fassungsbestätigungen und speichert den Nachweis in derselben Abgabetransaktion. Die drei fristgesteuerten Nachrichten – erste Erinnerung, zweite Erinnerung, Fristablauf-Nachricht – gehen an die offenen Beteiligungen: nicht zurückgezogen, ohne Stellungnahme und seit RAL-QM-HP-5 (E6) ohne entzogenen Zugang. Die Auswahl liegt an einer Stelle (HearingDueActionProcessor.OpenTargets). Eine Aktion, die keine offene Beteiligung findet, schließt trotzdem als ausgeführt ab; nach der Wiederfreigabe wird deshalb nichts nachgeholt, später fällige Aktionen erreichen die Institution wieder. Entschieden wird beim Einreihen in den Postausgang; eine schon eingereihte Nachricht geht noch hinaus. Jede individuelle Verlängerung (RAL-QM-HP-40) wird an der Beteiligung mit UTC-Fristtag, Begründung und Revision gespeichert. Der wirksame Tag ist das Maximum aus Verfahrens- und Individualfrist und bleibt vollständig offen. Eigene revisionsgebundene Aktionen verhindern verfrühten Ablauf; veraltete Jobs erzeugen keine Nebenwirkung. Zugangsentzug und Lifecycle bleiben vorrangig. Eine Verlängerung löscht nur die abgeleitete Keine-Aussage-Markierung, nie Antworten oder bisherige Historie. Seit RAL-QM-HP-33 gehen Erinnerungen nur inDispatchedhinaus (ein inAdjudicationnoch beanspruchter Auftrag endet ohne Nachricht). Sie enthalten ausschließlich die aktuell freigegebenen Unterlagen als authentifizierte, tokenfreie Portalverweise der jeweiligen Beteiligung; jeder Download prüft den aktuellen Grant erneut. Jeder Erinnerungslauf hinterlässt einen System-VerlaufseintragReminderRunCompletedmit Anzahl und Namen der tatsächlich erinnerten Institutionen (Vertretungskopien zählen nicht), und der Referent kann ausgewählte offene Beteiligungen von Hand erinnern (HearingDispatchAppService.RemindParticipantsAsync, Recht.Dispatch, nur inDispatchedund im wirksamen Fenster; jedes Ziel wird vor dem ersten Zugangsdatum geprüft, eine nicht offene Beteiligung weist den ganzen Aufruf mit Namen ab; die Zeile trägt den Idempotenzschlüssel der Vorgangskennung, dieselbe Kennung reiht nie zweimal ein). Mit gesetzter zweiter Frist plant der Planer zusätzlich die verfahrensweite AktionNoStatementCheckauf den ersten Augenblick nach dem UTC-Fristtag der zweiten Frist; sie hält für jede dann noch offene, erreichbare Beteiligung (nicht zurückgezogen, ohne Stellungnahme, ohne Zugangsentzug, ohne offene Störung) einmaligHearingParticipant.NoStatementRecordedAtUtcfest, mit System-Verlaufseintrag je Beteiligung, und versendet nichts. Ohne zweite Frist entsteht die Aktion nicht, und die Akte nennt das als Hinweis. „Keine Aussage" ist ein eigener Beteiligungsstand der Rücklaufübersicht und des Exports, kein Statuswert und kein Bestandteil des offenen Bestands; eine spätere interne Nacherfassung (RecordInternallyAsync) ersetzt ihn im selben Speichervorgang durch die verspätete Rückmeldung. Bescheidung, Abschluss- und Abbruchnachricht laufen nicht über diese Auswahl und bleiben unverändert. Auch von Hand geht keine Einladung an eine Beteiligung mit entzogenem Zugang: Ausstellen und Erneuern weist der Dienst mitInvitationNotAllowedWhileAccessRevokedab (HearingInvitationAppService.EnsureIssuableAsync), die Einladungskarte lässt beide Aktionen ruhen und nennt den Grund – sonst erhielte die Institution ein amtliches Schreiben mit Portallink zu einem Verfahren, das ihre Konten nicht öffnen können. DerHearingDueActionProcessoröffnet seine ABP Units of Work selbst, sowohl beim periodischen Worker als auch beim manuellen Prüflauf. Lesen, Recovery und Claim verwenden kurze, eigene Scopes; ein Claim ist vor der Ausführung festgeschrieben. Einladung, Postausgang, Hearing-Änderung und erfolgreicher Aktionsabschluss bilden je Aktion eine Transaktion. Nach einem Fehler wird diese zurückgerollt und der Retry-Status mit erneut geprüftem Claim in einer frischen Unit of Work gespeichert. Ein konkurrierend verlorener Claim hinterlässt so keinen fehlerhaften EF-Zustand für die folgenden Aktionen. Die Ausführung hält den gelesenen Verfahrenszustand mitRepeatableReadbis zum Commit stabil, ohne Serializable-Bereichssperren für andere Verfahren. Ist das Verfahren bereitsCompletedoderCancelled, endet auch eine vorher beanspruchte Aktion ohne neue Einladung, Nachricht oder Verlauf. Ein später konkurrierender Abschluss wartet oder löst einen vollständigen Rollback mit Retry aus. Stellt der Prozessor eine Erinnerung für ein Verfahren mit gesetzter zweiter Frist in den Postausgang, deren wirksame Frist die zweite Verfahrensfrist ist, schreibt er diese fest (SecondResponseDeadlineFixedAtUtc, RAL-QM-HP-29 AC-7): die Nachricht nennt diese Frist, ab da verweigert das Aggregat jede Änderung (SecondDeadlineFixedByReminder), und die Detailseite bietet sie nicht mehr an. Abschlusserinnerung (RAL-QM-HP-43): Der vollständige Bescheidungsversand nach RAL-QM-HP-46 plant in derselben Transaktion genau eineClosureCheck-Aktion mitDueAtUtc = AdjudicationFullyDispatchedAtUtc + ClosureReminderDays. Eine Teilwelle plant nichts: sie setzt nur den Erstversand (AdjudicationDispatchedAtUtc), erst die Welle, die die letzte erforderliche Beteiligung bedient, setzt den Zeitpunkt der vollständigen Übermittlung. Die Dauer (auch eine fehlende Gruppe) wird einmalig festgeschrieben; spätere Standards gelten für neue Pläne. Der bestehende Worker plant vollständig beschiedene Altdaten ohne Auftrag einmalig nach, jeweils in eigener Transaktion. Fehlende Dauer hinterlässt eine stornierte Aktion; ungültige Importwerte eine fehlgeschlagene Aktion mit sichtbarer, ausdrücklich wiederholbarer Störung. Am UTC-Grenzzeitpunkt prüft die Ausführung den aktuellen Verfahrensstand und die aktuelle Zuständigkeit über Authorization.Contracts. Nicht erreichbare/inaktive Zuständige führen zur einmaligen Eskalation an alle aktiven, eindeutig gebundenen Geschäftsführungskonten mit genau einer Produktrolle und gültiger E-Mail; die Meldung verlangt Zuständigkeitswechsel, überträgt aber nichts. Ohne Empfänger entsteht eine wiederholbare Störung. Enqueue, Systemverlauf undExecutedwerden gemeinsam gespeichert. Interne Nachrichten (ClosureReminder) besitzen keinen Institutionszweck, kein Anschreiben und keine Teilnehmer-/Zugangsbindung; der DE/EN-Text enthält Nummer, Gütezeichen, Bezeichnung und den permissiongeschützten Bearbeitungslink. SMTP-Retries verwenden denselben Outboxauftrag; erst die erfolgreiche Transportübergabe setzt dessenSentAtUtc. - Adjudication-Fenster (nur zweistufige Abschlussvariante): Ab Eintritt in
Adjudicationdürfen bis zum ersten Bescheidungsversand nur als Endfassung markierte Dokumente additiv angelegt, ersetzt oder freigegeben werden; die ursprünglich freigegebene Komposition bleibt nachvollziehbar. - Abschluss: Bei zweistufiger Variante schließt der Bescheidungsversand das Fenster, fixiert
die versendete Komposition samt Prüfsumme; das Verfahren bleibt bis zum ausdrücklichen Abschluss
in
Adjudication. Bei einstufiger Abschlussvariante (US-33) gehen Bescheidung und Endfassung in einem Vorgang hinaus, ohne denAdjudication-Status gesondert zu durchlaufen. Seit RAL-QM-HP-51 schließt der Referent auf beiden Wegen ab; beide verlangen eine verfügbare Endfassung, erzeugen die interne Rückmeldungsübersicht und geben die Endfassung den Empfängern nach Regel 4 im Portal frei – Ablauf und Guard-Reihenfolge unter Abschluss und Endfassung. Abbruch (RAL-QM-HP-42): Die Geschäftsführung (HearingsPermissions.Abort, nurRALQMManagement) beendet ein laufendes Verfahren (Dispatched,Adjudication) mit einer Pflichtbegründung, die seit RAL-QM-HP-42 die amtliche ist (IsCancellationReasonOfficial): Sie geht in der Abbruchmitteilung an jede angeschriebene Beteiligung – die aktiven, Zugangsentzug eingeschlossen, und zurückgezogene mit früherer Postausgangszeile –, zusammen mit dem tokenfreien Link auf die lesende Teilnahmeansicht; einen gebundenen Alttext ohne{{Begruendung}}ergänzt der Renderer um den Begründungsblock. Transition, Widerruf von Einladungen, Kontobindungen, Grants und Due Actions, Aufträge und VerlaufseintragAbortedlaufen in einer Transaktion; Wiederholung und konkurrierender Abbruch erzeugen keinen zweiten Auftrag, ein Transportfehler bleibt am Auftrag.Cancelvor dem Versand (Draft,PendingApproval) sendet nichts und hält den Grund intern;Approvedist von beiden ausgeschlossen. Der Endzustand ist schreibgeschützt und bleibt in der Arbeitsliste, bis RAL-QM-HP-44 ein Archivkennzeichen bringt. Archivieren und Zurückholen (RAL-QM-HP-44): Ein beendetes Verfahren (Completed,Cancelled) erhält durch Referent oder Geschäftsführung (HearingsPermissions.Archive) das ArchivkennzeichenIsArchivedmit Actor und UTC-Zeit - kein Status, keine Wiedereröffnung, keine Löschung. Verfahrensübersicht, Arbeitsvorrat und Export schließen archivierte Verfahren aus, auch mit explizitem Statusfilter; die Archivseite zeigt ausschließlich archivierte. Zurückholen verlangt das Kennzeichen und eine Pflichtbegründung, die nur im ABP-Audit-Log des Aufrufs steht; Endzustand, Schreibschutz und entzogene Zugänge bleiben. Beide Befehle schreiben je genau einen Verlaufseintrag (Archived,RestoredFromArchive) in derselben Transaktion; Stempelkonflikt oder Doppelaktion lassen nichts zurück. Öffentliche Anzeige (RAL-QM-HP-47): Ein freigegebenes oder versendetes Verfahren (Approved,Dispatched) erhält durch Referent oder Geschäftsführung (HearingsPermissions.Publish) das KennzeichenIsPublishedund beim ersten Mal die unveränderliche öffentliche KennungPublicId. Sichtbar ist es, solange Kennzeichen UND einer der beiden Status gelten (HearingPublicationRule); jede öffentliche Lesung wertet beides in SQL aus. Der Wechsel in die Bescheidung, Abschluss oder Abbruch beenden die Anzeige ohne Job und ohne Änderung am Kennzeichen; die Rücknahme der Freigabe nimmt das Kennzeichen zusätzlich zurück (EintragUnpublished), sodass eine erneute Freigabe nicht automatisch wieder anzeigt. Zurücknehmen ist in jedem Status möglich. Kennzeichnen und Zurücknehmen schreiben je einen Verlaufseintrag (Published,Unpublished). Die Website gleicht über den Bestandsabruf ab (Pull, siehe 6.4); einen Push an die Website gibt es nicht. Seit RAL-QM-HP-78 liest sie seitenweise und quittiert danach, was sie übernommen hat (POST /api/gz/hearings/public/receipts). Bleibt eine Änderung länger als die Frist unbestätigt oder kommt so lange keine Quittung, meldet der Sync-Worker eine Störung (ADR-20). - Neben ABP Audit Logging führt Hearings eine PII-arme fachliche Historie
(
RALQMHearingHistoryEntries); Freitexte, Dokumentinhalte und Zugangstokens erscheinen dort nie.
Details zu Datenownership und Tabellen stehen in Querschnittliche Konzepte §2.
Beteiligungsstand der Auswertung (RAL-QM-HP-36)
Die Rückmeldungsseite und der Reiter „Rücklauf“ zeigen je Institution genau einen Stand. Er wird
bei jedem Laden aus den gespeicherten Sachverhalten abgeleitet und nicht gespeichert
(HearingParticipationStateRule); es entsteht kein weiterer Verfahrens- oder Teilnehmerstatus.
Treffen mehrere Sachverhalte zu, gewinnt der obere
(SPEC-RAL-QM-HP-36, Regel 5):
| Rang | Stand | Sachverhalt, gelesen aus |
|---|---|---|
| 1 | Rückmeldung vorliegend / Verzicht | jüngste Abgabe der Teilnahme (HearingResponseSequence): Stellungnahme oder Verzicht |
| 2 | Zugang entzogen | HearingParticipant.AccessRevokedAtUtc |
| 3 | Zustellung fehlgeschlagen | Postausgang: die zuletzt erzeugte Mail an den Ansprechpartner ist endgültig gescheitert, aufgegeben oder als unzustellbar gemeldet |
| 4 | Keine Aussage | HearingParticipant.NoStatementRecordedAtUtc |
| 5 | Erinnert | Teilnehmerstatus Reminded |
| 6 | Eingeladen | Postausgang: es gibt eine Einladung an den Ansprechpartner der Beteiligung |
| 7 | Hinzugefügt | nichts davon |
| – | Zurückgezogen | Teilnehmerstatus Withdrawn; am Ende der Liste und in keiner Zahl |
Ein zutreffender Sachverhalt, der nicht der Stand ist, steht als Hinweis in der Zeile (Zugang
entzogen, Zustellung fehlgeschlagen, Keine Aussage, Verspätet abgegeben; bei Zurückgezogenen die
frühere Abgabe). Für „Zustellung fehlgeschlagen“ zählen die Vertretungskopie (Schlüsselende
:dep), die Mail an zusätzliche Empfänger (Schlüsselanfang recipient:), ersetzte Zeilen und
laufende Wiederholungen nicht; ein korrigierter Folgeauftrag zählt, wenn seine Ursprungszeile eine
Mail an den Ansprechpartner war (HearingParticipationMails). „Eingeladen“ liest die Einladung
an den Ansprechpartner im Postausgang, weil kein Übergang den Teilnehmerstatus Invited setzt –
gleich mit welchem Transportergebnis; eine Vertretungskopie oder eine Mail an zusätzliche
Empfänger allein lädt niemanden ein.
„Offen“ hat zwei Bedeutungen. Für die Auswertung – Kennzahl „offen“ und Filter „Nur offene
Beteiligungen“ – ist eine Beteiligung offen, wenn sie keine Abgabe hat, nicht als „Keine Aussage“
vermerkt und nicht zurückgezogen ist, auch mit entzogenem Zugang. Für Erinnerungen und
Fristablauf (HearingDueActionProcessor.OpenTargets, Schritt 5) gilt zusätzlich: ohne entzogenen
Zugang. Die Auswertung entscheidet nicht, wer erinnert wird.
Der Rücklauf zählt die nicht zurückgezogenen Institutionen mit Abgabe – Stellungnahme oder Verzicht – gegen die Beteiligten ohne Zurückgezogene. Die Filter (offen, Stand, Kategorie der jüngsten Abgabe) wirken zusammen, werden auf dem Server ausgewertet und schmälern nur die Zeilen; die Zahlen beschreiben immer das ganze Verfahren. Der Export liefert dieselben Zeilen unter denselben Filtern. Laden, Filtern und Exportieren sind eine Momentaufnahme ohne Push, ändern keine Daten und versenden nichts.
Kontaktmeldung (RAL-QM-HP-41)
Eine Institution meldet im laufenden Verfahren eine andere Kontaktperson; der Referent entscheidet
darüber. Die Meldung ist ein eigener Datensatz neben dem Verfahren (HearingContactReport), kein
weiterer Verfahrens- oder Teilnehmerstatus. Sie ist offen und erreicht genau einen Endzustand; je
Beteiligung ist höchstens eine Meldung offen
(SPEC-RAL-QM-HP-41).
| Handlung | Wer | Verfahrensstatus | Wirkung |
|---|---|---|---|
| Melden | Institutionskonto | Dispatched |
Meldung „offen“; Empfänger, Stammdaten und Konten bleiben |
| Zurückziehen | jedes Konto der Institution | Dispatched |
„zurückgezogen“; eine neue Meldung ist möglich |
| In Stammdaten übernehmen | Referent mit Kontaktpflegerecht | Dispatched, Adjudication |
ein neuer aktiver Kontakt der Institution, er wird Empfänger dieser Beteiligung; „übernommen“ |
| Vorhandenen Kontakt verwenden | Referent | Dispatched, Adjudication |
ein aktiver Kontakt derselben Institution mit dieser E-Mail wird Empfänger, kein neuer Kontakt; „übernommen“ |
| Nur für dieses Verfahren übernehmen | Referent | Dispatched, Adjudication |
Empfängerstand ohne Stammdatenkontakt (ADR-14); „übernommen“. Nicht mit der E-Mail des Stammdatenkontakts, der schon Empfänger ist |
| Ersetzen | Referent | Dispatched, Adjudication |
eines der drei Ziele mit einer anderen, vollständig erfassten Person; „ersetzt“ mit Person, Ziel und optionaler Notiz |
| Verwerfen | Referent | jeder Status | „verworfen“ mit optionaler Notiz; sonst ändert sich nichts |
Die Rückmeldefrist spielt beim Melden keine Rolle. Nichts schließt sich von selbst: Eine beim
Verfahrensende offene Meldung bleibt offen, bis der Referent sie verwirft. Bescheidversand,
Abschluss und Abbruch werden nicht aufgehalten; an diesen vier Stellen nennt ein Hinweis die
Institutionen mit offener Meldung (IHearingContactReportAppService.GetOpenNoticeAsync, nur
Namen) für den Stand beim Öffnen der Seite. „Meine Verfahren“ öffnet bei einem versandten
Verfahren die Karte der Teilnahmeansicht direkt.
Vor einer Entscheidung liest die Verfahrensakte ihre Grundlage (PrepareDecisionAsync): die Stände
von Meldung, Verfahren und Institution, ob das Verfahren noch läuft, Kontakte derselben Institution
mit derselben E-Mail (aktiv oder inaktiv, ohne Beachtung der Groß-/Kleinschreibung), ob ein
gewählter zusätzlicher Empfänger dieses Postfach trägt, das Kontaktpflegerecht des Aufrufers und
die aktiven Funktionen. Übernehmen und Ersetzen laufen in einer serialisierbaren Transaktion mit
allen Prüfungen vor dem ersten Speicherschritt: Meldung offen und unverändert, Verfahrensstand,
Status und aktive Beteiligung, kein gleiches Postfach, Rechte, Institution aktiv und unverändert,
Funktion aktiv. Erst danach folgen der neue Kontakt (Institutions-Vertrag „einen Kontakt
hinzufügen“), der Empfängerwechsel der Beteiligung, der Endzustand der Meldung und ein
Verlaufseintrag. Scheitert ein Teil, bleibt alles unverändert. Zurückziehen und Entscheiden
senden den gelesenen Stand der Meldung; die zuerst gespeicherte Handlung gilt, die andere endet
als Konflikt, auch als Deadlock-Opfer. Ein wiederholter Aufruf trifft auf den Endzustand und legt
nichts doppelt an.
Die nächste Nachricht des Verfahrens geht an den neuen Empfänger; eingereihte Nachrichten und
frühere Versandstände bleiben. Ein Empfänger ohne Stammdatenkontakt erhält keine Vertretungskopie.
Der Verlauf trägt je Handlung einen Eintrag (ContactReportSubmitted, …Withdrawn, …Adopted,
…Discarded, …Replaced) mit Akteur, Zeitpunkt und Beteiligung, bei Übernahme und Ersetzen mit
Ziel und Kontaktbezügen, nie mit Angaben der Person oder der Notiz. Konten, Bindungen und
Sitzungen bleiben von allem unberührt.
Folgeregeln vom 30.09.2026 (ADR-09)
Vor dem Erstversand darf die Geschäftsführung eine Freigabe nach Draft zurücknehmen; Korrektur erfordert anschließend erneute Einreichung und Vier-Augen-Freigabe. Frühere Entscheidungen bleiben. Interne Entscheidungsbenachrichtigungen ohne erreichbaren Zuständigen pausieren 72 Stunden nach dem ersten Empfängerfehler. Die ausdrückliche Fortsetzung legt einen verknüpften Folgeauftrag an.
Ein verspäteter automatischer Reminder prüft den wirksamen individuellen UTC-Fristtag erneut und endet bei geschlossenem Fenster ohne Nachricht. Der Erinnerungsbericht ist sofort nach Einreihung im geschützten internen Portal verfügbar. Nach Transportabschluss, spätestens nach 24 Stunden als Zwischenbericht, erhält der bei Auftragserstellung festgelegte Referent einen Link. Offene Transportaufträge werden weiter versucht; spätere Berichtabrufe zeigen ihren aktuellen Stand. Zusätzliche gewählte Kontakte und Vertretungen erhöhen die Nachrichtenzahl, nicht die Zahl der Beteiligungen. Die manuelle Mehrfachauswahl wird vor dem Auftrag bestätigt und vollständig validiert.
Abschluss und Endfassung (RAL-QM-HP-51)
Beide Abschlusswege – zweistufig Complete (aus Adjudication bzw. als Ausnahmeweg ohne relevante
Stellungnahme aus Dispatched) und einstufig CompleteSingleStage im kombinierten Vorgang – laufen
durch denselben Zweiphasen-Ablauf (SPEC-RAL-QM-HP-51,
Bausteine in 5.2.3). Den Abschluss führt der Referent aus: direkt
mit Complete, kombiniert mit Adjudicate UND Complete.
sequenceDiagram
actor R as Referent (RALQMCaseOfficer)
box transparent RALQM-Host
participant A as HearingAppService /
HearingAdjudicationAppService
participant C as HearingClosureManager
participant G as HearingClosureReportGenerator
end
participant D as CAF Documents
R->>A: Abschließen (Stempel)
A->>A: Guards 1–7, ohne Nebenwirkung
A->>C: PrepareClosureAsync
C->>G: Rückmeldungsübersicht erzeugen
G->>D: CreateAsync (PDF)
A->>C: AttachClosureReportAndGrantFinalVersion (try-Block)
C->>C: AttachClosureReport, Endfassungs-Grants
A->>A: einstufig: Bescheidungswelle ausführen
A->>A: Transition Complete / CompleteSingleStage
A->>C: CompleteClosureAsync
C->>C: 40 und 70 in den Postausgang,
Verlauf 810/820, Widerruf
Note over A,D: Fehler nach CreateAsync: Bericht in derselben
Unit of Work löschen, dann Rollback
Guard-Reihenfolge. Auf beiden Wegen gleich und ohne jede Nebenwirkung; ältere Abweisungen behalten ihre Codes:
- Recht und Verfahrensstempel (
ConcurrencyStamp). - Aggregat-Vorabprüfung
Hearing.EnsureCompletablebzw.EnsureCompletableSingleStage: Variante, Status, Bescheidungserfordernis, Rückmeldephase, unbeantwortete Einwände – dieselben Prädikate, Codes und Reihenfolge wie die Transition, die sie selbst aufruft. - Nur einstufig: Bescheidungswelle planen (
PlanAdjudicationWaveAsync, rein;UnansweredObjections,AdjudicationReplyMissing, Reihenfolge „unbeantwortet vor entzogen“ unverändert). Ausgeführt wird sie erst nach der Vorbereitung. - Endfassung vorhanden: mindestens eine aktive, nicht ersetzte Abschlussanlage, sonst
ClosingAttachmentMissing– auch auf dem Ausnahmeweg und bei leerer Empfängermenge. - Endfassung lesbar: Jede aktive Abschlussanlage hat einen Deskriptor
(
IDocumentContentPort.DescribeManyAsync), und jeder unterschiedliche Endfassungsinhalt lässt sich überIDocumentContentPort.OpenAsyncöffnen (Datenstrom sofort freigegeben; der Datenbank-Blob-Provider lädt den Inhalt dabei vollständig in den Speicher, siehe SPEC-RAL-QM-HP-51 Offenlegung 20). Meldet das Öffnen „Inhalt fehlt“, folgt derselbe Code mitreason = contentUnavailableund eine Warnung mit der Dokument-Id (Owner-Review !175: Deskriptor ohne Blob). Andere Fehler laufen als Betriebsfehler durch. - Vorlage 70: Mit mindestens einem Endfassungsempfänger mit wirksamem Endfassungs-Grant (Regel 7) muss
die Endfassungsbenachrichtigung gebunden sein, sonst
TemplateNotResolvable(purpose 70); siehe Ergänzungsbindung. - Bericht anhängbar, als reine Aggregatprüfung: Fenster (
Dispatched/Adjudication), höchstens ein Bericht je Verfahren, Anzeigename frei. IstRueckmeldungsuebersicht_<Nummer>.pdfbelegt, wählt die Vorprüfung deterministisch den ersten freien NamenRueckmeldungsuebersicht_<Nummer>_2.pdf,_3… – keine Abweisung, die den Abschluss dauerhaft blockieren würde.
Nebenwirkungen, erst danach und in einer Unit of Work:
PrepareClosureAsync: Empfängermenge nach Regel 4, beschränkt auf Empfänger mit wirksamem Endfassungs-Grant (Regel 7, 9); Berichtsmodell (alle Beteiligungen mit Status, je Beteiligung Eingangszeit, Art, Verspätung, Text und wirksame Bescheidung in Eingangsreihenfolge); Bericht überCreateAsync.- Unmittelbar danach, schon im try-Block des Anwendungsdienstes:
AttachClosureReportAndGrantFinalVersion–Hearing.AttachClosureReportunter dem vorgeprüften Anzeigenamen (ZweckClosureReport, HerkunftGenerated, keine Grants, nie Pflichtdokument); Endfassungs-Grants je aktiver Abschlussanlage × Empfänger. Ein Paar mit bereits widerrufenem Grant wird übersprungen (Regel 9: keine Reaktivierung), aktive Grants bleiben idempotent, fremde Grants auf Abschlussanlagen bleiben bestehen (E3). - Nur einstufig: die geplante Bescheidungswelle ausführen.
- Transition
Completebzw.CompleteSingleStage; sie widerruft alle Grants mitHearingCompleted, die nach RAL-QM-HP-30 lesbar bleiben. CompleteClosureAsync: Abschlussmitteilung (40) an die aktiven Beteiligten. Die Endfassungsbenachrichtigung (70; credential-frei, Idempotenzschlüssel Sequenz 1, Vertretungskopie, ohne Begleitdokument) undFinalVersionDelivered(810, je Empfänger, Subjekt Beteiligung) erhalten nur Empfänger mit mindestens einem wirksamen Endfassungs-Grant – einem vor der Transition aktiven oder neu erteilten. Wurden alle Grants eines Empfängers nach Regel 9 übersprungen, entstehen für ihn weder 70 noch 810 (Regel 7 bleibt wahrheitsgemäß). DanachClosureReportCreated(820, einmal, Subjekt Bericht) und der Widerruf laufender Artefakte.
Einstufig erhält ein Empfänger damit drei Nachrichten: Bescheid, Abschlussmitteilung und
Endfassungsbenachrichtigung. Das folgt der Trennung in RAL-QM-HP-51 O1 und ist als Folgefrage beim PO offengelegt.
Im Portal gibt HearingPortalRules.IsDocumentReleased nach Completed alles frei außer ClosureReport;
dieselbe Regel gilt für Liste, Download und Erinnerung, ein verirrter Grant auf den Bericht öffnet nichts.
Fehler und Wiederholung. Eine Abweisung in den Schritten 1–7 hinterlässt nichts. Scheitert ein
Schritt nach CreateAsync – etwa eine Abweisung beim Rendern der einstufigen Welle oder der
Endfassungsbenachrichtigung –, löscht der Abschluss den gerade abgelegten Bericht noch in derselben
Unit of Work über IDocumentFilingPort (Löschreservierung und Abschluss der Löschung, Muster
HearingDocumentAppService.CompensateUploadAsync) und wirft weiter; die Transaktion rollt Verfahren,
Grants, Aufträge und Verlauf zurück. Mit dem Datenbank-BLOB-Provider ist der Bericht ohnehin Teil der
Transaktion. Mit dem Dateisystem-Provider räumt der Documents-Baustein selbst nach: Er merkt jede
über den Inhaltsport neu geschriebene Datei an der Unit of Work vor und entfernt nach deren Scheitern –
auch bei einem Fehler beim Speichern oder beim Commit selbst, an dem der Fehlerzweig selbst scheitert und nur eine Warnung protokolliert –
jede Datei ohne committeten Deskriptor, Bericht wie Begleitbriefe 30/40
(Documents-Vertrag). Was ein
Prozessabbruch zwischen Ablage und Bereinigung zurücklässt, entfernt seit RAL-QM-HP-81 der
wiederkehrende Abgleichslauf des Documents-Bausteins
(Risiken). Eine Wiederholung nach
dem Commit weist der Statusguard ab, die Outbox-Schlüssel sind eindeutig – es entsteht weder ein zweiter
Bericht noch ein zweiter Auftrag.
6.3 Externe Kontoprovisionierung
Zwei getrennte, beide fail-closed arbeitende Pfade nutzen denselben kontrollierten
Keycloak-Admin-Port (IKeycloakAdminClient/KeycloakAdminHttpClient im Feature Authorization)
über den dedizierten vertraulichen Client ral-qualitymarks-provisioning (nur Rolle
manage-users, kein Browser-/Direktzugriffs-Flow).
sequenceDiagram
actor U as Berechtigter Benutzer
box transparent RALQM-Host
participant UI as Institutions/Authorization.Blazor
participant Auth as Authorization AppService
end
participant Kc as Keycloak Admin API
alt Kontakteinladung (aus Kontaktsuche)
U->>UI: Kontakt in institutionsübergreifender
Suche wählen
UI->>Auth: stabile Kontakt-ID übergeben
Auth->>Kc: Konto per E-Mail suchen
alt kein/eindeutiges Match
Auth->>Kc: Konto anlegen bzw.
Subject bestätigen
Kc-->>Auth: sub
Auth-->>UI: Einladung versendet
(keine automatische Fachrolle)
else mehrdeutig
Auth-->>UI: Fehler AmbiguousEmail
(geschlossen abgelehnt)
end
else Mitarbeitendenkonto (/administration/…)
U->>UI: Name, E-Mail, genau eine
GZ-Produktrolle
UI->>Auth: Anlage-/Wiedereinladungsauftrag
Auth->>Kc: Subject strikt bestätigen
Kc-->>Auth: sub
Auth->>Auth: lokale ABP-Projektion
+ Rollen-Grant setzen
Auth-->>UI: Konto aktiv, Wiedereinladung nur
bei ausdrücklicher Wahl
end
- Kontaktbasierte Einladung: So entstehen die dedizierten Institutionskonten — stets
RAL-seitig ausgelöst (aus der institutionsübergreifenden Kontaktsuche), nie per
Selbstregistrierung; je Institution erhalten mehrere Kontakte je ein eigenes Benutzerkonto.
Die UI übergibt nur die stabile Kontakt-ID an den Provisionierungsport. E-Mail-Gleichheit
erteilt keine Fachberechtigung — Identitäten werden über
subkorreliert. Ein bereits vorhandenes eindeutiges Konto erhält eine erneute Einladung statt eines Dublettenkontos; es wird keine automatische Hearing-Teilnahme vergeben. Seit RAL-QM-HP-18 läuft der Pfad über den Kontodienst (ProvisionInstitutionAccountAsync, RechtRALQM.Accounts.InviteInstitution): der Ansprechpartner muss aktiv sein und eine E-Mail haben, das Konto erhält die Produktrolle Institution (nur Portalrecht) und eine Bindung an Institution und Ansprechpartner in derselben Unit of Work; ein internes Konto unter der Adresse wird abgewiesen (RoleKindMismatch), ein bereits gebundener Ansprechpartner ebenso (AlreadyBound). - Mitarbeitendenkonto: einziger Anlage-/Wiedereinladungseinstieg ist die GZ-Seite
/administration/mitarbeitendenkonten(RechtRALQM.Accounts.Invite, nur Systemadministrator). Sie verlangt Name, E-Mail und genau eine interne Produktrolle, bestätigt das Keycloak-Subject strikt und weist die Rolle erst der lokalen ABP-Projektion zu. Wiederholte Aufrufe versenden ohne ausdrücklich gewählte Wiedereinladung keine neue E-Mail. Rollenwechsel bleibt in der Kontoart (intern/Institution) und lässt dem letzten aktiven Systemadministrator bzw. der letzten Geschäftsführung die Rolle. Sperren setzt das Keycloak-Konto aufenabled=false, beendet dessen Provider-Sitzungen, erneuert den Security Stamp und widerruft alle CAF-Sitzungen des Subjects — die nächste Aktion des Kontos landet auf der Anmeldung; das eigene Konto und das letzte einer Führungsrolle sind nicht sperrbar. Kennungswechsel (Personalwechsel) setzt E-Mail und Name in Keycloak und lokal neu, entfernt das Passwort, beendet die Sitzungen und lädt die Nachfolgeperson ein; Subject, Anmeldename (Alias — die Admin-API ändert ihn untereditUsernameAllowed=falsenicht), Institution, Verfahrenssicht und Verlauf bleiben. Papierkorb statt Löschen: Soft Delete mit Provider-Sperre, wiederherstellbar aus/administration/mitarbeitendenkonten/papierkorb; einen endgültigen Löschpfad gibt es nicht. Jede Mutation schreibt einen Verlaufseintrag (RALQMStaffAccountHistory) mit Akteur. Der Einladungszustand der Übersicht (offen bis / angenommen / abgelaufen) kommt aus dem Sendezeitpunkt (ExtraProperty) und den Keycloak-Zuständen (requiredActions); ein nicht erreichbarer Provider lässt ihn „unbekannt“ statt die Übersicht scheitern. - Fehlerfälle scheitern geschlossen und sind stabil kodiert:
ExternalAccountProvisioningErrorCodes(RALQM.Authorization:Provisioning:Disabled| AmbiguousEmail|SubjectConfirmationFailed|InvalidSubject|EmailBoundToOtherAccount) für den Kontaktpfad,StaffAccountErrorCodes(RALQM.Authorization:StaffAccounts:InvalidInput| InvalidRole|LocalUserNotFound|ProductRoleNotFound|NotExternallyLinked|ConcurrencyConflict| CannotChangeOwnAccount|LastAdministrator|LastManagement|RoleKindMismatch|ContactNotFound| ContactInactive|ContactWithoutEmail|AlreadyBound|EmailAlreadyUsed|NotInTrash|InTrash| InvitationAlreadyAccepted) für Mitarbeitenden- und Institutionskonten. -
Die ABP-eigene Benutzerseite ist für keinen der beiden Pfade ein unterstützter GZ-Weg und wird von den GZ-Seiten nicht verlinkt.
-
Aktivierungszustimmung (RAL-QM-HP-39): Nach der angenommenen Keycloak-Einladung führt der erste Portalaufruf auf
/portal/zustimmung. Die Person akzeptiert die Nutzungsbedingungen und nimmt die Datenschutzhinweise der geltenden Fassungen zur Kenntnis; erst der dabei gespeicherte Aktivierungsnachweis gibt den Fachzugang frei. Ohne veröffentlichte Fassungen bleibt der Schritt gesperrt.
6.4 Dokumentfreigabe
ABP File Management besitzt Dateimetadaten und BLOB-Inhalt. IDocumentContentPort bleibt
permission-frei; der Hearings-Anwendungsfall autorisiert vollständig vor jedem Inhaltsaufruf.
Seit RAL-QM-HP-31 bestehen im Host zwei
Produktpfade: interne Berechtigungen und feste Institutionskonten.
sequenceDiagram
actor P as Institutionskonto
participant H as Hearings
participant A as Authorization-Contract
participant D as Documents-Contract
P->>H: Liste / Detail / Mutation / Download
H->>A: GetCurrentAsync (frische Prüfung)
A-->>H: Konto-, Bindungs-, Institutions- und Kontakt-ID
H->>H: aktive Teilnahme ohne Zugangsentzug + Lifecycle + Frist + Grant
H->>D: Inhalt erst nach Autorisierung
D-->>P: Inhalt über Hostadapter (no-store)
Authorization liest die lokale Konto-/Rollen-/Subject-Zuordnung, die aktive feste Bindung
und den aktuellen Providerzustand einschließlich angenommener Einladung. Unbekannter Zustand
schließt den Zugriff. Die Providerprüfung fragt gezielt users/{subject} ab; Transport- und
Providerfehler bleiben technische Fehler mit Wiederholen statt einer dauerhaften fachlichen
Zugriffsverweigerung. Hearings verwendet ausschließlich diesen prozessinternen Contract;
keine fremden Tabellen oder Repositories. Mehrere Konten derselben Institution greifen auf
dieselben zulässigen Teilnahmen zu. Übersicht und Detail laden ohne alte Trackingwerte.
Schreibvorgänge verwenden Serializable; die Bindungslesesperre bleibt bis zum Commit erhalten,
sodass ein konkurrierender Widerruf eine definierte Reihenfolge hat. Vor Verwendung bereits
getrackter Hearing-Aggregate wird ihr Stempel mit dem frisch autorisierten Stand verglichen.
Seit RAL-QM-HP-5 (AC-9,
AC-10) gehört der Zustand „Zugang entzogen“ der Beteiligung (AccessRevokedAtUtc) zur Prüfkette
jeder Portaloperation: Ein Verfahren mit entzogenem Zugang fehlt in „Meine Verfahren“, und
Übersicht, Abruf, Abgabe und Änderung werden für jedes Konto der Institution mit derselben
neutralen Meldung abgewiesen wie ein fremdes Verfahren – auch nach dem Ende des Verfahrens, sodass
die Institution davon nichts mehr erfährt; ein abgewiesener Abruf ruft den Content-Port nicht
auf, die gespeicherte Stellungnahme bleibt intern lesbar. Die Freigabe wirkt ab dem nächsten
Aufruf ohne neue Einladung. Ein gleichzeitiger Schreibvorgang des Portals wird durch seine
Serializable-Transaktion und den Aggregatstempel entweder vor dem Entzug festgeschrieben oder
danach abgewiesen; einen Teilzustand gibt es nicht (HearingAccessRevocationRaceSqlServerTests).
Stellungnahme-Anhänge prüfen intern Responses.Read und die vollständige ID-Kette, extern
Kontozugang und die eigene institutionsbezogene Rückmeldung. Abgelehnte Downloads rufen den
Content-Port nicht auf und liefern 404 mit no-store und nosniff. Fristen und gesonderte
Versandfreigaben bleiben bestehen.
Seit RAL-QM-HP-30 liest das
Portal auch nach dem Ende eines versandten Verfahrens (HearingPortalRules.IsReadable): lesbar
sind Dispatched, Adjudication, Completed und ein Cancelled mit Versandzeitpunkt; ein
Abbruch vor dem Versand antwortet wie ein unbekanntes Verfahren, und eine eigene Abbruchmeldung
gibt es nicht mehr. Geschrieben wird nur in Dispatched; ein Schreibversuch auf ein beendetes
Verfahren erhält dieselbe neutrale Abweisung wie einer in der Bescheidung. Eine Freigabe ist nach
dem Ende lesbar, wenn sie aktiv ist oder allein wegen des Endes widerrufen wurde
(IsGrantReadable); die Gründe „durch das Ende“ stehen genau einmal in
HearingPortalRules.EndRevocationReasons (HearingCompleted, HearingCancelled) und speisen
die C#-Regel wie die SQL-Abfrage des HearingPortalAuthorizer. Hand-, Dokument- und
Teilnahmewiderruf sowie der Versionsersatz (DocumentSuperseded) bleiben gesperrt, nichts wird
reaktiviert. Die Authorizer-Abfrage des Downloads bekommt den Endzustand aus dem bereits
autorisierten Aggregat mit, nie aus dem Request. Nach einem Abbruch bleiben die Unterlagenarten
der erreichten Abschnitte sichtbar (Anhörungsunterlagen; Bescheidungsanlagen nur bei begonnener
Bescheidung; Abschlussanlagen nie), nach dem Abschluss alle. Der Zugangsentzug ist nach dem Ende
eingefroren, das erste Öffnen wird auch dann noch als Zustand und Verlaufseintrag festgehalten.
Eine fehlende Bindung ergibt vor jeder Abfrage den eigenen Code
RALQM.Hearings:PortalAccessMissing, ein fehlendes Portalrecht die ABP-Abweisung des Proxys
(Code Volo.Authorization:010001); beide zeigen die Portalseiten als Hinweis „kein
Institutionszugang“, die Objektebene behält ihre eine neutrale Abweisung. Ein Schreibversuch,
der auf ein inzwischen beendetes Verfahren trifft, führt auf der Seite zu einem erneuten Lesen:
lesbar → Leseansicht mit dem Hinweis „Ihre Änderung wurde nicht gespeichert“, sonst die neutrale
Meldung.
Seit RAL-QM-HP-41
schreibt das Portal außerdem Kontaktmeldungen (SubmitContactReportAsync,
WithdrawContactReportAsync). Es gilt die Prüfkette jeder Portalschreibung – Portalrecht, frisch
geprüfte Bindung, eigene aktive Beteiligung ohne Zugangsentzug, Dispatched –, aber ohne die
Rückmeldefrist. Außerhalb davon und für eine fremde oder unbekannte Meldung gilt die neutrale
Abweisung, und zwar vor jeder Prüfung des Inhalts. Gespeichert wird in
HearingPortalWriteTransaction unter der Teilnehmerreservierung; „höchstens eine offene Meldung je
Beteiligung“ sichert zusätzlich ein gefilterter eindeutiger Index. Die Teilnahmeansicht liefert die
Meldungen der Beteiligung mit Datum und Zustand, ob gemeldet werden kann, und dann die aktive
Funktionsliste; gelesen wird wie die Teilnahmeansicht, auch nach dem Ende. Der Portalvertrag trägt
weder die interne Notiz noch das Ziel noch die Person, die der Referent stattdessen übernommen hat
(Ablauf: 6.2).
Zwei neutrale 404 mit derselben Aussage, aber verschiedener Form: Die Seitenadresse
/portal/teilnahme/{id} antwortet bei fremder, unbekannter oder entzogener Kennung mit 404 ohne
Inhalt (no-store, nosniff, noindex); die Downloadroute antwortet mit 404 samt JSON-Körper
des einen neutralen Codes. Beide sind unabhängig davon, ob die Kennung existiert.
HearingPortalParticipationRouteMiddleware (Hearings-Runtime) stellt dem Vertrag die Frage
IHearingAccountPortalAppService.IsParticipationReadableAsync – kein Remote-Service, derselbe
SQL-Filter wie die Teilnahmeliste – und läuft im Host hinter UseAuthorization und
UseRateLimiter; die Seite trägt dafür dieselbe Policy hearing-portal wie der
Download-Controller. Ohne Anmeldung greift die Autorisierung der Seite, ohne Portalzugang zeigt
die Seite ihren Hinweis, ein technischer Fehler der Prüfung wird als Warnung protokolliert und
zur Seite durchgereicht (wiederholbar), eine vom Client abgebrochene Anfrage endet ohne Eintrag.
Betriebshinweis zur Aufrufbremse hearing-portal (HearingPortalRateLimiterRegistration): ein
festes Fenster von 20 Aufrufen je Minute und Absenderadresse ohne Warteschlange, das die
Vollaufrufe der Teilnahmeseite und die Portal-Downloads gemeinsam zählt; die Navigation innerhalb
des Blazor-Circuits zählt nicht. Hinter einem gemeinsamen Ausgang (NAT, Reverse-Proxy mit dessen
Adresse) teilen sich alle Konten dieser Adresse das Fenster. Die Ablehnung ist eine nackte 429 ohne
Fehlerseite; eine Konfigurationsfläche gibt es bewusst erst auf Anforderung des Betriebs. Im vollen
Browserlauf vom 24.09.2026 trat keine 429 auf.
Kontenprojektion, Profil und Institutionsfilter zeigen nur aktive Bindungen. Widerrufshistorie gehört in die gesonderte Bindungsverwaltung. Eine ausdrücklich erneute Kontakteinladung kann mit Verwaltungsrecht dieselbe feste Bindung wiederherstellen; Rücknahmebefehl, Kontenänderung und Historie laufen gemeinsam in einer eigenen Serializable-Unit-of-Work nach dem Vorabcheck. Ein Providerfehler rollt sie zurück; Institution/Kontakt und deaktivierte Konten bleiben geschützt.
Portal-only-Grants leiten interne Komponenten-GETs bereits im Host vor Autorisierung und
Blazor-Render zum Portal um. Die Entscheidung verwendet Permissions und ersetzt keinen
Circuit-Inhalt während der Initialisierung. Öffentliche Rechtstexte tragen AllowAnonymous;
APIs und Nicht-Komponenten-Endpunkte behalten ihre eigene Autorisierung.
Endpoint-Inventar: Fach-APIs und Kontoportal verlangen Anmeldung und Produkt-/Objektprüfung.
Der Host setzt eine authentifizierte Fallback-Policy; Routen ohne Endpunkt antworten davor 404
(UnmatchedRouteNotFoundMiddleware), weil die Policy sonst auch unbekannte Pfade anfordern
würde. Login, OIDC-Callback, Abmeldung und
öffentliche Rechtstexte bleiben ohne Fachdaten erreichbar. RAL-QM-HP-79 ergänzt
/Barrierefreiheit als vierten anonymen Rechtstext; die Seite liest ausschließlich
Betreiber-/Erklärungskonfiguration und das versionierte Register bekannter Barrieren.
Der Rückmeldeweg ist ein E-Mail-Link ohne Anmeldung und ohne Speicherung in der Anwendung.
Seit RAL-QM-HP-80 gehören auch
/nicht-gefunden und /fehler/{statusCode:int} zum datenfreien anonymen Inventar; sie zeigen
ausschließlich die 403/404/500-Vorlage und keinen Inhalt der fehlgeschlagenen Fachroute.
Die ABP-Kontoseiten des
Anmeldewegs werden per Razor-Pages-Konvention aus PublicAccountPages geöffnet, Kontoverwaltung nicht; Framework-Ressourcen behalten ihre
expliziten Authentifizierungsmetadaten; die Circuit-Endpunkte /_blazor* sind öffentlich, autorisiert
wird je Komponente. /health/live, /health/ready und /health/status
sind explizit öffentlich; Status verlangt zusätzlich die konfigurierte Netzwerkfreigabe.
Statische Assets sind öffentlich (Static-Asset-Endpunkte tragen AllowAnonymous). Seit
RAL-QM-HP-47 ist die Komponentenseite /anhoerungen/oeffentlich ausdrücklich
öffentlich; sie zeigt nur die öffentliche Projektion (Titel, Gütezeichen, Verfahrensart, Frist) der
sichtbaren Verfahren. Der Bestandsabruf GET /api/gz/hearings/public[?changedSinceUtc=][&pageSize=][&continuation=] und die
Quittung POST /api/gz/hearings/public/receipts (RAL-QM-HP-78) sind nicht
öffentlich: er verlangt ein Keycloak-Client-Credentials-Token des eigenen Bearer-Schemas
HearingPublicationFeed mit Audience und einem zugelassenen azp (ADR-12); die Browsersitzung
erreicht ihn nicht, no-store verhindert Zwischenspeicher. Die aufgegebenen /portal/einladung, /portal/kontext,
/portal/anhoerung, /portal/zugang-uebernehmen und /portal/teilnahme-beanspruchen führen
queryfrei zum festen Loginziel; alte Download-Unterpfade antworten 404. Gastkontext,
Gastcookie und Claim werden nicht ausgewertet. /api/caf/documents/shares/* ist hier gesperrt;
der CAF-Vertrag anderer Consumer wird nicht verändert. Reverse-Proxy-Zugriffsprotokolle dürfen
historische Zugangsqueries nicht aufzeichnen; bestehende Versandhistorie bleibt unverändert.
Neue und noch nicht versandte Nachrichten setzen den tokenfreien Teilnehmer-Tiefenlink erst beim Versand ein. Alte verschlüsselte Outbox-Payloads werden hierfür nicht mehr entschlüsselt. Vertretungskopien vermitteln kein Zugriffsrecht; die Vertretung braucht ihr eigenes gebundenes Konto. Historische Einladungs- und Claim-Datensätze bleiben ausschließlich für Referenzen erhalten.
Seit RAL-QM-HP-20 gibt es neben
dem Einzelgrant die Sammelzuordnung: ein bestätigter Auftrag erteilt einer Unterlage je beim
Speichern aktiver Beteiligung ohne aktiven Grant einen neuen; zurückgezogene Beteiligte werden
übersprungen, bestehende Grants bleiben, ein wiederholter Aufruf erzeugt nichts. Dieselben
Wächter wie beim Einzelgrant gelten (Zweckfenster nach RAL-QM-HP-21, aktive aktuelle Version), und der
gelesene Aggregatstempel wird vor jeder Änderung geprüft, sodass ein Teilnehmerwechsel zwischen
Vorschau und Bestätigung den Auftrag abweist. Die Unterlage merkt sich den Zeitpunkt
(GrantedToAllParticipantsAtUtc); eine danach hinzugefügte Beteiligung erhält die Unterlage nicht
automatisch – das bleibt die Pflichtunterlage –, sondern wird in der Verfahrensakte benannt. Die
Freigabeseite zeigt der Geschäftsführung dieselben Grants je Institution mit Name, Dateityp, Rolle
und Zweck, warnt textlich vor einer Institution ohne Unterlage und bietet den Abruf nur über die
bestehende autorisierte Download-Route und nur mit Documents.Download; Approve erweitert
keine Dokumentberechtigung, Liste und Abruf ändern keine Daten.
Stellungnahme mit Anlagen (RAL-QM-HP-38)
Seit RAL-QM-HP-38 schreibt das Portal die
Stellungnahme samt Anlagen in einem Aufruf und in zwei Phasen
(HearingAccountPortalAppService.SubmitResponseAsync). Seit RAL-QM-HP-40 erzeugt
AppendResponseAsync im selben Ablauf einen neuen Beitrag; AmendResponseAsync weist
Änderungen zurück. Das folgende Diagramm zeigt den ursprünglichen atomaren Ablauf aus RAL-QM-HP-38;
die dortige Anlagenentfernung ist seit der Festschreibung durch RAL-QM-HP-40 nicht mehr zulässig.
sequenceDiagram
actor P as Institutionskonto
participant H as Hearings
participant T as HearingPortalWriteTransaction
participant D as Documents-Contract
P->>H: Abgabe (Kategorie, Text, Dateien, zu entfernende Anlagen)
H->>H: Vorprüfung ohne Transaktion: Bindung, Beteiligung,
Dispatched, Frist, Kategorie, Anzahl, Regel 2
H->>P: Dateien vollständig lesen (Grenze je Datei + 1 Byte)
H->>T: Speicherphase, Serializable, requiresNew
T->>H: frische Lesung mit Stempelvergleich
H->>D: je Datei CreateAsync (Name, Typ, Signatur, Größe)
H->>H: Antwort einfügen (Index), Verlauf, Beteiligungsstand
T-->>H: Commit — oder Deadlock-Opfer: bis zu zwei Wiederholungen
mit denselben gelesenen Dateien
Jede Abweisung in der Speicherphase rollt alles zurück, auf dem Datenbank-BLOB-Provider die
Dateien eingeschlossen. Wiederholt wird nur das Deadlock-Opfer (Regeln in
Querschnitt §2);
Stempelkonflikt, abgewiesene Datei und eindeutiger Index werden nicht wiederholt. Seit RAL-QM-HP-40
reserviert die Speicherphase vor der Sequenzvergabe die Teilnahme zum Schreiben. Erstabgabe
verlangt eine leere Folge, Ergänzung einen vorhandenen Vorgänger. Eine bereits bekannte
Auftragskennung liefert nach den aktuellen Zugangs- und Fensterprüfungen genau ihren Beitrag,
wenn Akteur und Inhalt übereinstimmen; sonst folgt ein Operationskonflikt. Die neuen Dateien
werden vor der Festschreibung diesem Beitrag zugeordnet. Danach schützen Domäne und
Persistenzpfad ihn vor Änderungen und Löschung. Frühere weich gelöschte Anlagenzuordnungen
bleiben erhalten und vermitteln keinen Downloadzugang. Nachweise:
HearingResponseSubmissionSqlServerTests.
Weiterführend: Sicherheitskonzepte, Bausteinsicht.
Eingangsbestätigung und Referentenhinweis (RAL-QM-HP-35): Jede im Portal
festgeschriebene Abgabe – Erstabgabe und jede Ergänzung – legt in derselben Serializable-Speicherphase
zwei Aufträge an: die Bestätigung an die operative Kontaktadresse der Beteiligung und den Hinweis an den
in diesem Moment zuständigen Referenten. Die Anlagen tragen den SHA-256 der übernommenen Bytes. Ein
Worker stellt die Aufträge mindestens einmal zu (Klartext, ohne Stellungnahmetext; tokenfreier
Portalverweis bzw. Prüflink), meldet Fehler als Störung, pausiert nach 72 Stunden ohne erreichbaren
Empfänger und lässt sich über „Wiederholen“ auf /stoerungen erneut anstoßen oder an den aktuellen
Empfänger fortsetzen. Eine zurückgerollte Abgabe hinterlässt keinen Auftrag, ein Replay keinen zweiten.
6.5 Arbeitsablage und Papierkorb (RAL-QM-HP-19)
Filing prüft pro Aufruf die ABP-Permission, die aktuelle aktive interne Kontoprojektion mit
genau einer Produktrolle Referent oder Administrator und eindeutiger Keycloak-Bindung sowie
Bereichseigentum. Beide Rollen dürfen gemeinsame und eigene persönliche Bereiche verwenden;
fremde persönliche Bereiche bleiben auch für Administratoren bei allen Operationen verborgen.
Die technische ABP-Rolle admin allein genügt nicht. Der Menüaufbau und der Purge-Worker
verwenden dieselbe aktuelle Kontoprüfung. Die administrative Übertragung bleibt auf ein
deaktiviertes internes Quellkonto und einen aktiven Referenten als Ziel beschränkt und
vermittelt keinen Inhaltszugriff auf den fremden Bereich.
Auch das ausführende Konto muss aktuell aktiver, eindeutig gebundener Produktadministrator
sein. Service, Menü und Seite verlangen Transfer und Accounts.Invite für die Kontenauswahl.
Clientziele sind Filing-Element-IDs; verborgene native Bereichs- und
Papierkorbwurzeln werden nicht als Navigationsziele ausgegeben. Die Liste lädt unmittelbare
Kinder; Breadcrumbs prüfen höchstens 16 sichtbare Vorfahren.
Die Namenssuche filtert nur aktive direkte Kinder des gewählten Ordners im gewählten
Bereich. Unterordnerinhalte, andere Bereiche und Papierkorb gehören nicht zu dieser Suche.
HasChildFolders in Bereichs-, Ordner- und Element-DTOs wird aus aktiven Unterordnern der
bereits autorisierten Bereiche abgeleitet, unabhängig von Namensfilter und Paging.
Jede Mutation schreibt zuerst die concurrency-geschützte Bereichsrevision in derselben
SQL-Transaktion. Bei Bereichswechseln erfolgt dies nach stabiler ID-Reihenfolge. Erst danach
werden Name, Ziel, Unterbaum und Tiefe geprüft. Die betroffenen Unterbaumeinträge werden vor
der Domänenänderung mit EF-Tracking geladen, sodass Bereich und Zustand aller Nachfahren
gemeinsam gespeichert werden. Reine Verzeichnislisten bleiben ohne Tracking.
Anlegen, Upload und beide Kopierpfade binden Wiederholungen an unveränderliche Auftragsdaten
in der bestehenden Filing-Historie: normalisierter Name, Zielordner, Bereich, Quelle und Actor.
Nach Umbenennen oder Verschieben wird dieselbe Operation-ID weder für einen geänderten Auftrag
akzeptiert noch zur Erzeugung eines Duplikats verwendet. Ältere Historienzeilen ohne Name und
Zielordner liefern bei einer Wiederholung einen Operationskonflikt; aktuelle ABP-Metadaten
können den ursprünglichen Auftrag nicht beweisen.
Papierkorbverschiebungen erhalten die Bytes
und legen die betroffene native Wurzel in ein eigenes technisches Verzeichnis; früher separat
entfernte Kinder bleiben in ihrem eigenen Löschvorgang. Wiederherstellen prüft aktive Ziele
und stellt nur den ausgewählten Unterbaum seines Löschvorgangs wieder her.
Die Sammelentfernung bindet jede Wurzel an den ausgewählten Löschvorgang. Vor dem
Einzelpurge werden Löschurheber, Löschwurzel und DeletionBatchId erneut geprüft;
Wiederherstellen und erneutes Löschen liegt außerhalb dieses Umfangs, auch beim selben
Akteur. Der dabei gelesene Eintragsstempel schützt vor Änderungen nach der Prüfung.
Endgültiges Entfernen reserviert zunächst alle Datei-Descriptoren und persistiert Purging
zusammen mit Actor und Operation-ID. Aktive CAF-Shares sowie auch historische Hearings-
Referenzen blockieren den gesamten Auftrag. Der bestehende ABP-Background-Worker-Mechanismus
liest die dauerhaften Aufträge erneut, revalidiert Actor, Rechte und Eigentum und entfernt
Dateien sowie anschließend ausschließlich leere Ordner. Erst der gemeinsame Commit von
Inhaltsentfernung, Purged und Historie bestätigt den Abschluss. Fehler bleiben als feste
Fehlerkategorie am Auftrag; ein später berechtigter Inhaber kann ihn ausdrücklich erneut
autorisieren. Reservierte Dateien lassen weder Download noch neue CAF-Shares zu.
Eine Share-Erzeugung reserviert den vorhandenen Descriptor als erste Descriptor-Operation
durch atomaren EF-Self-Update seines unveränderten ConcurrencyStamp. Erst danach werden
Descriptor und Löschreservierung gelesen. Die Schreibsperre bleibt bis zum Commit der
Serializable-Unit-of-Work bestehen; ein vorheriger Shared-Read mit späterem Lock-Upgrade
ist wegen der Konvertierungsdeadlocks bei parallelen Freigaben ausgeschlossen.
Ein eindeutiger gefilterter Index der PurgeStarted-Historie bindet die Operation-ID dauerhaft
an eine ausgewählte Wurzel und ihren Bereich. Filing übersetzt ausschließlich die entsprechende
SQL-Indexverletzung in den fachlichen Operationskonflikt; der Datenbanktreiber dafür bleibt im
Produktmodul, der CAF-Dokumentvertrag bleibt providerneutral.
RAL-QM-HP-65 ergänzt zwei getrennte Auftragsursachen: manuelle Anforderung mit
menschlichem Actor und automatisches Fristende mit System ohne erfundenen Benutzer.
Die zentrale revisionsgebundene Policy startet deaktiviert mit 90 Tagen. Änderungen
serialisieren auf derselben SQL-Zeile wie automatischer Vollzug; eine Erhöhung schützt
auch bestehende Systemreservierungen. Manuelles Vorziehen bindet dieselbe Operation
und hält ursprüngliche Ursache, gebuchten Termin und neue menschliche Anforderung fest.
Der Tick bucht jedes fällige ungeschützte Element einzeln; ein Ordner benötigt seine
eigene Fälligkeit und tatsächliche Leere. Geschwister behalten unabhängige Fristen.
Restore entfernt nur die Basis der wirklich wiederhergestellten Elemente; erneutes
Trash erhält einen neuen Batch. Aktive Freigaben und historische Verfahrensbezüge
schützen weiter. Vollständig zwischen Ticks durchlaufene CAF-Sharephasen sind durch
Schutzendzeit und eine stabile Revision der gesamten Freigabehistorie erkennbar.
Unbekannte historische Endzeiten beginnen frühestens mit einer bestätigten aktuellen
Beobachtung neu; Listenlesen datiert keinen Bestand um.
/filing/bevorstehende-entfernungen und /filing/loeschauftraege verwenden dieselbe
frisch autorisierte reine Projektion wie der Papierkorb. Filter und Sortierung gelten
vor Paging. Nur tatsächlich bestätigte Inhalte zählen dedupliziert zur Gesamtgröße;
Ordner-Rollups zählen nicht, Purging zählt bis zum tatsächlichen Vollzug weiter.
Unbekannte oder widersprüchliche Mengen ergeben einen unvollständigen Gesamtwert.
Tägliche und kumulierte Prognosen enthalten ausschließlich bestätigte ungeschützte
termingebundene Inhalte, keine offenen Aufträge und keine bereits erfolgte Freigabe.
Die administrative Kapazität unter /administration/speicher misst SQL-Dateien bzw.
den konfigurierten Dateisystemdatenträger getrennt von Dokumentbytes, mit Quelle und
UTC-Zeit; unbekannter physischer SQL-Datenträgerplatz wird nicht geschätzt.
Vor jeder Dokumentmutation hält die bestehende native ABP-UoW einen externen Generationslease bis nach Commit/Rollback und Dispose (ADR-21). Der aktive Modus koppelt auch die nativen CAF-Schreibports und Hearings-eigene Referenz-/Grantänderungen an diese Schranke. Vor Auftrag und Vollzug prüft ein frischer Inhaltsabgleich unter selber Lease erneut. Lokale Befunde sperren betroffene Löschungen; unbekannter Umfang sperrt den Kontext. Der regelmäßige und manuelle begrenzte Vollabgleich und die exakte Wiederanlauffreigabe sind in Kapitel 8 beschrieben. Der kanonische Betriebsweg rotiert die externe Generation vor Restore: Getting Started §6a.
Entfernte Verfahrensdateien werden durch IHearingDocumentTrashPort zugeliefert. Vor
Metadatenzugriff gelten die aktuellen Hearings-Leserechte; fehlende Verfahrensrechte liefern
keine Verfahrenszeilen und verhindern nicht den berechtigten Ablagezugriff. Die gemeinsame
Liste benennt das Verfahren und bietet einen eigenen Bereichsfilter. Restore sperrt zuerst
das Hearing-Aggregate, prüft dessen ConcurrencyStamp, Zweckfenster und Namenskonflikte und
reaktiviert keine Teilnehmergrants. Freigabe- und Abschlussstände werden nicht umgangen.
Bei geschlossenem ursprünglichem Zweckfenster wählt der Benutzer ausdrücklich „Kopie in
Ablage wiederherstellen“ und einen aktiven Ordner seiner persönlichen oder der gemeinsamen
Ablage. Filing prüft Read/Manage, Kontoeignung, Zielstempel, freien Namen und Ordnertiefe und
sperrt zuerst den Zielbereich. PrepareCopyToFilingAsync prüft die Hearings-Lese- und
Downloadrechte, den Verfahrensstempel und die zurückgezogene, noch verfügbare Quelle ohne
Löschreservierung. Die Hearing-Schreibsperre und der frische Descriptor-Lesezugriff bleiben
in derselben Serializable-Transaktion bis zum Abschluss der CAF-Kopie erhalten.
Die Kopie erhält eigene Bytes, Descriptor-ID, Filing-Zuordnung und Historie; Verfahrensreferenz,
Originalinhalt, Verfahrensstatus und Grants bleiben unverändert. Die Sperre erneuert lediglich
den ConcurrencyStamp des Hearings. Die Operation-ID bindet Quelle, Ziel, Name und Actor.
Ein identischer Wiederholungsaufruf prüft aktuelle Rechte und die vorhandene aktive Zielkopie;
er benötigt keine erneute Quellkopie und bleibt auch nach späterem Quell-Purge wiederholbar.
Die Oberfläche bestätigt ausdrücklich die Kopie, nicht eine Reaktivierung im Verfahren.
Ein expliziter Verfahrens-Purge benötigt Completed, eine entfernte ungeschützte Upload-/Archive- Datei und keine weitere Datei-/Antwortreferenz oder aktive Freigabe. Er nimmt nur die genau betroffene entfernte Hearing-Referenz aus der konservativen Schutzprüfung aus. Dateien mit nativer Ordnerzuordnung bleiben geschützt, damit ältere gemeinsame Verweise auf Ablagebytes nicht gelöscht werden. Cancelled ist keine Freigabe zum endgültigen Entfernen. Hearings persistiert Auftrag, Actor und Retryzustand am eigenen Dokument; der Worker verwendet die CAF-Reservierung und prüft Kontoeignung sowie Filing-/Hearings-Permissions erneut. Der erhaltene Dokumentdatensatz unterscheidet beabsichtigtes Purged von beschädigtem Inhalt.
Der aktuelle Filing-Upload-/Kopierpfad einschließlich dieser Wiederherstellungskopie verlangt den Datenbank-BLOB-Provider, weil dessen Inhalt
mit SQL zurückgerollt werden kann. Seit RAL-QM-HP-81 entfernt zwar ein Abgleichslauf die Reste
gescheiterter Erstellungen auf dem Dateisystem, die Sperre bleibt aber: Eine Löschung ist dort sofort
endgültig, und ein Rollback ihrer Unit of Work ließe einen Deskriptor ohne Inhalt zurück
(Documents-Vertrag); ein Best-Effort-Catch ist keine Zusicherung.
Die Oberfläche konsumiert Cohesion über den gleitenden Bereich 3.*-* — eine Version steht hier
bewusst nicht mehr, sie wäre bei jedem Paketstand aufs Neue falsch (siehe Directory.Packages.props).
Zugesichert wird das Verhalten: Der Explorer bestätigt Navigation
erst nach der Serviceantwort und ignoriert veraltete Antworten.
Seit 3.6.3-alpha.0.6 sind Krümelpfad und Mehrfachauswahl des CohesionDataBrowser
Opt-in (EnableBreadcrumbs, EnableSelection, Vorgabe jeweils false); die drei
Aufrufstellen im Produkt setzen sie ausdrücklich, sonst verschwände der Standortpfad lautlos. Der Baum lädt direkte
Ordnerkinder beim Aufklappen unabhängig von der aktuell gefilterten Dateilistenseite.
Refresh veröffentlicht neue Wurzeln und Standortinhalt gemeinsam; Knotenupdates bewahren
die feste Bereichsreihenfolge. Ein letzter Blattknoten öffnet die Papierkorbroute und ist
kein auswählbares Schreibziel. Die Ordneranlage verwendet einen modalen Cohesion-Dialog;
Dateiaktionen einen zentrierten Icon-Button und bis zur integrierten Tastatur-/Fokusprüfung
des korrigierten RCL-Menüs einen Dialog.
Standardmäßig erscheinen 25 Einträge; die Oberfläche zeigt Anzahl und Auswahl 25/50/100
auch bei nur einer Seite. Die Suchbeschriftung benennt den Umfang, Navigation löscht den Filter.
Uploaddateien erhalten Einzelresultate und unabhängige Operation-IDs; Namenskonflikte
verlangen Überspringen oder einen bestätigten Namen. Änderungen senden die gelesenen
Bereichs-/Elementstempel. Papierkorb und Transfer verlangen eigene Bestätigungen,
Purge zusätzlich die separate Permission. Die flache Papierkorbliste verwendet eine
semantische Tabelle mit Cohesion-Aktionsbuttons. Der Clipboard-ARIA-Fix liegt in der RCL
vor; ein erneuter Grid-Einsatz verlangt den realen Clipboard-/axe-Nachweis
(CAF-Override-Register).
Der vollständige Portal-Browserlauf vor der Adminerweiterung ist in Gesamtgate 5 vom
2026-09-10 grün. Die Adminerweiterung wurde am 2026-09-11 in SQL und mehrfach in der gesamten
Filing-Browserstrecke einschließlich Transfer, Tastatur, Mobilansicht und axe geprüft.
Der aktuelle Reviewstand ist in ral-qm-hp-19-review-gate-5 am 2026-09-11 um 14:01:52 MESZ
vollständig grün: 3.204 Tests ohne Skips, kein EF-Modellunterschied und der ungefilterte
Portal-Browserlauf einschließlich Migration/Seed aus leerer Datenbank und Neustart.
Die Spec führt den aktuellen Nachweis getrennt von den historischen Fehlerbildern.
Der Verfahrenspapierkorb einschließlich Kopie bei geschlossenem Ursprungsfenster ist im
integrierten Stand von RAL-QM-HP-21 implementiert; die zugehörige aktuelle Ausführungsevidenz
wird in der Spec getrennt geführt. Die Snapshot-Übernahme in der Gegenrichtung ist mit
RAL-QM-HP-16 hinzugekommen und steht in 6.6.
Offener Abnahmeteil bleibt allein der externe RAL-Providernachweis.
6.6 Ablagedatei ins Verfahren übernehmen (RAL-QM-HP-16)
Die Gegenrichtung zu 6.5: Eine aktive Datei aus dem gemeinsamen oder dem eigenen persönlichen
Bereich wird als eigenständige Verfahrensfassung in ein Verfahren übernommen — eigene
DocumentId, eigener Descriptor, eigene Bytes. Orchestriert wird sie in Filing.Runtime
(FilingAppService.HearingAdoption.cs), weil die Laufzeitkante nur in dieser Richtung besteht;
die Verfahrenshälfte liegt hinter IHearingDocumentAdoptionPort. Ein Aufruf behandelt genau eine
Datei mit eigener Operation-ID; die Oberfläche ruft je ausgewählter Datei einmal auf. Ein
Serverbatch scheidet aus, weil jede Mutation des Dokumentports die Transaktion des Aufrufers
verlangt und ein Fehler bei der dritten Datei die ersten beiden mit zurückrollen würde.
sequenceDiagram
actor R as Referent (RALQMCaseOfficer)
box transparent Filing-Orchestrierung
participant F as FilingAppService
Serializable-UoW je Datei
participant Area as Bereich + Element
(RALQMFilingAreas/-Entries)
participant U as Verwendungsnachweis
(RALQMFilingHearingUsages)
end
box transparent Hearings
participant P as IHearingDocumentAdoptionPort
end
participant Doc as IDocumentFilingPort
+ ABP File Management
R->>F: AdoptToHearingAsync (eine Datei,
eigene OperationId)
F->>F: Rechte gestapelt + Kontoeignung
(EnsureFilingUserAsync)
F->>U: OperationId bereits vergeben?
alt Wiederholung derselben Bestellung
U-->>R: AlreadyApplied, nichts geschrieben
else abweichende Bestellung unter derselben Id
U-->>R: OperationConflict
else erster Lauf
F->>Area: Bereich sperren (Bereichsrevision),
Quelle prüfen: aktiv, Datei, Stempel
F->>P: PrepareAdoptionAsync — Ziel sperren und
prüfen: Lifecycle, Zweckfenster, Namenskollision
P-->>F: bestätigter Zweck, Name,
frischer Verfahrensstempel
F->>Doc: CopyDocumentAsync(folderId: null)
Doc-->>F: neue DocumentId + Descriptor + Blob
F->>P: CompleteAdoptionAsync — anhängen mit
origin = Archive, Verlaufseintrag
P-->>F: HearingDocumentId + Übernahmezeit
F->>U: Verwendungszeile einfügen
F->>Area: Filing-Historie HearingDocumentAdopted
F-->>R: Adopted (ein Commit) bzw. Rejected
mit Fehlercode je Datei
end
- Rechte und Kontoeignung. Es gibt keinen eigenen Permission-Knoten. Der Aufruf stapelt
RALQM.Filing.ReadmitRALQM.Hearings,RALQM.Hearings.DocumentsundRALQM.Hearings.Documents.Manage; dazu prüftRequireActorAsyncüberIStaffFilingAccessPort.EnsureFilingUserAsyncdie aktuelle Kontoeignung, bevor irgendein Metadatum gelesen wird. Der Port prüft dieselbe Eignung in seiner eigenen Hälfte erneut. - Eine Transaktion je Datei. Die Methode trägt
[UnitOfWork(false)]und öffnet eine eigene, transaktionaleSerializable-Unit-of-Work. Deadlocks (SQL 1205) werden alsAbpDbConcurrencyExceptiongemeldet; von den übrigen SQL-Fehlern wird ausschließlich die Verletzung des namentlich geprüften eindeutigen IndexUX_RALQMFilingHearingUsages_OperationIdin den fachlichen Operationskonflikt übersetzt — jeder andere Fehler bleibt, was er ist. - Replay-Erkennung. Die committete Verwendungszeile ist der Beleg der Operation. Dieselbe
Bestellung unter derselben Operation-ID schreibt nichts erneut und meldet
AlreadyApplied; eine abweichende Bestellung (anderes Element, anderes Verfahren, anderer Actor) ist ein Operationskonflikt. - Bereich sperren, dann Quelle prüfen. Die Bereichsrevision wird als erste Schreiboperation
gestempelt und arbitriert damit gegen einen gleichzeitigen Purge der Quelle, der denselben
Bereich sperrt. Erst danach werden Bereichseigentum,
FilingEntry.EnsureActive(Papierkorbzustände →AdoptionSourceMustBeActive), der Elementstempel undFilingHierarchyPolicy.EnsureCopy(nur Dateien, keine Ordner) geprüft. - Ziel sperren und prüfen — vor der Kopie.
PrepareAdoptionAsyncerzwingt die transaktionale Serializable-Unit-of-Work des Aufrufers und prüft in dieser Reihenfolge: Lebenszyklus zuerst (Completed/Cancelled→TargetClosed), dann das Zweckfenster über den einen vorhandenen WächterHearing.EnsureDocumentAttachable(purpose), dann Sperre und Stempelrotation des Verfahrens, dann die Namenskollision gegen aktive Unterlagen desselben Verfahrens. Die Lebenszyklusprüfung steht vor dem Zweckfenster, weilIsDocumentWindowOpenin einem abgeschlossenen oder abgebrochenen Verfahren für alle Zweckefalseliefert — ohne die Vorabprüfung wäre „nimmt überhaupt nichts mehr auf“ von „nicht in diesem Schritt“ nicht unterscheidbar. Geschrieben wird hier nichts außer der Sperre. - Warum die Zielprüfung vor der Byte-Kopie steht. Genau dafür sind Prepare und Complete
getrennt: Eine abgewiesene Übernahme darf keinen Inhalt hinterlassen, den jemand
kompensieren müsste. Erst wenn das Ziel unter seiner Sperre bewiesen ist, entsteht über
IDocumentFilingPort.CopyDocumentAsynceine neueDocumentIdmit eigenem Descriptor und eigenem Blob. Der Port verlangt dafür die Transaktion des Aufrufers (RequireTransaction/EnsureTransactionalContentMutation), also bleibt die Kopie bis zum gemeinsamen Commit rollback-fähig; ein Kompensationsaufruf wie im Upload-Weg von RAL-QM-HP-21 wird hier nicht gebraucht. Der Preis ist die bestehende Bindung an den Datenbank-BLOB-Provider aus RAL-QM-HP-19 — ein nichttransaktionaler Provider wird abgewiesen, nicht stillschweigend geduldet. folderId: nullist zwingend.HearingDocumentTrashRetentionschützt jeden Descriptor mit Ordnerzuordnung vor dem endgültigen Entfernen. Eine Kopie, die in einem Ablageordner läge, wäre vom Verfahren nie mehr purgefähig.- Anhängen und Verlauf.
CompleteAdoptionAsyncprüft den frischen Verfahrensstempel und hängt die bereits kopierte Fassung überHearing.AttachDocumentmitorigin: HearingDocumentOrigin.Archivean — der erste Erzeuger dieses seit RAL-QM-HP-21 vorhandenen Herkunftswerts. Der VerlaufseintragDocumentAdoptedFromFilingträgt flach und ohne Klartext nur{"sourceEntryId":"…"}; Ablagename und Pfad erscheinen dort nie (PII-Regel des Verlaufs). Der Übernahmezeitpunkt ist der Anlagezeitpunkt der Verfahrensfassung, derselbe Wert, denHearingDocumentDtoalsUploadedAtUtcveröffentlicht. - Verwendungsnachweis und Commit.
FilingHearingUsagebindet Quell-Element, gelesene Quellfassung, Verfahren, Verfahrensdokument, Übernahmezeit, Actor und Operation-ID; die Zeile wird nie gelöscht. Danach die Filing-HistorieHearingDocumentAdopted, dann der gemeinsame Commit von Kopie, Verfahrensfassung, Verlauf, Nachweis und Historie. - Eine fachliche Abweisung ist ein Ergebnis, keine Ausnahme. Sie kommt als
FilingAdoptToHearingResultDtomitStatus = Rejectedund Fehlercode zurück, damit die Schleife über mehrere Dateien weiterläuft; die Transaktion ist zu diesem Zeitpunkt bereits zurückgerollt. Als Ausnahme bleiben: fehlende Berechtigung, fehlende Kontoeignung,EntryNotFoundund Deadlock. Die Codes der Hearings- und der Uploadhälfte werden an der Modulgrenze in die sprechenden Filing-Codes übersetzt (AdoptionTargetClosed,AdoptionPurposeNotOpen,AdoptionNameInUse,AdoptionContentRejected) — Vorbild istHearingTrashCommandAsync. Die Kopie durchläuft die Uploadpipeline erneut: Eine vor RAL-QM-HP-21 abgelegte Datei mit unpassender Signatur wird deshalb sichtbar abgewiesen, nicht still übernommen. - Der Verwendungsnachweis legt nichts Fremdes offen.
GetHearingUsageAsyncist mengenbasiert (eine Abfrage für viele Elemente, damit der Warnhinweis vor dem Löschen eines Ordners und später das Leeren des Papierkorbs dieselbe Quelle nutzen). Er lässt zwei Arten von Zeilen weg, ohne zu scheitern: Elemente, deren Ablagebereich der Aufrufer nicht sehen darf — ein fremder persönlicher Bereich bleibt auch hier privat —, und Verfahren, die er nicht lesen darf. Kein Platzhalter verrät, dass dort etwas war. Die verbleibenden Zeilen sind nach Übernahmezeit absteigend sortiert und kennzeichnenCompletedundCancelledals beendet (IsClosed); das Archivkennzeichen des Verfahrens (RAL-QM-HP-44) erreicht die Ablage nicht, weil es weder Schreibschutz noch Retention der übernommenen Datei berührt. - Die Quelle bleibt frei. Umbenennen, Verschieben, Ersetzen, Papierkorb und endgültiges
Entfernen der Ablagedatei wirken nicht auf eine bereits übernommene Fassung und werden durch
eine Übernahme auch nicht gesperrt. Der Hinweis vor dem Löschen ist ein Hinweis, keine Sperre;
der bestehende
PurgeProtected-Pfad für echte Descriptor-Mitbenutzung bleibt unberührt.
Anmeldung und Sitzungsablauf (RAL-QM-HP-52 A)
- Eine geschützte lokale Adresse wird samt Query durch Shell und ABP-Account-Filter geprüft und über die unveränderte OIDC-State-Runde erhalten.
- Nach erfolgreichem Login legt CAF einen serverseitigen Sitzungszustand an. Ein Cookie verweist mit opaker ID darauf; das Refresh-Token bleibt im Prozessspeicher.
- HTTP-Navigation und antiforgerygeschützte Bedienmeldungen verschieben nur den Inaktivitätszeitpunkt. Provider-Refresh und Blazor-Keepalive verschieben ihn nicht.
- HTTP-Middleware und CircuitHandler prüfen vor Fachcode. Bei Ablauf wird eine neue Anmeldung verlangt; der verworfene Schreibvorgang wird nicht wiederholt.
- Abmelden widerruft zuerst lokal für alle Tabs und startet dann OIDC-Sign-out. Ein neues Login verlangt Credentials, auch wenn beim Provider noch SSO besteht. Löscht eine gleichzeitige Anfrage derselben Sitzung deren ABP-Sitzungszeile zuerst, endet die Abmeldung trotzdem mit dem Providerredirect statt mit HTTP 500 (RAL-QM-HP-92).
Die absoluten Grenzen, Konfiguration und Einschränkungen stehen in Kapitel 8.
07. Verteilungssicht
1. Überblick
CAF.Applications.RAL.QualityMarks.HearingPortal (RALQM, "RAL Gütezeichen Anhörungsportal") läuft lokal als Zweiknoten-Deployment: ein nativer .NET-Prozess (der Blazor-Server-Host) und eine Docker-Compose-Infrastruktur mit SQL Server, Keycloak und Mailpit. Es gibt keine separate Web-/API-/Worker-Trennung — Host, Application Services, Blazor-UI, EF-Migrationen und Hintergrundarbeiter laufen im selben Prozess (siehe Bausteinsicht für die fachliche Modulaufteilung, Kontextabgrenzung für die Nachbarsysteme).
Jede Entwicklungsmaschine benötigt Pester >= 5.5 für die versionierten PowerShell-Tests.
setup.cmd installiert das Modul im Benutzerprofil, ohne die Vertrauensstellung von PSGallery
zu ändern. Fehlt es weiterhin, schlagen Setup, Doctor und Anwendungs-Preflight fehl.
-SkipPester unterbindet nur die Installation. Die vollständigen Voraussetzungen und
Installationswege stehen im Schnelleinstieg.
┌─────────────────────────────── Windows-Workstation ───────────────────────────────┐
│ │
│ dotnet-Prozess (Kestrel, Blazor Interactive Server) │
│ CAF.Applications.RAL.QualityMarks.HearingPortal (Host) │
│ https://localhost:<APP_PORT> │
│ - Shell, Contracts, Features/* — drei Fachfeatures (Authorization, Hearings, │
│ Institutions) und sechs ABP-Ersatz-Features (Identity, Languages, │
│ TextTemplates, AuditLogs, Gdpr, Settings) │
│ - CAF.Modules.{Authentication, Documents, UI.Blazor} │
│ - EF Core (SQL Server Provider), ABP Background Worker │
│ │
│ │ SQLSERVER_PORT │ KEYCLOAK_PORT │ SMTP │
│ ▼ ▼ ▼ │
│ ┌───────────────────────── Docker Compose: backend-Netzwerk ──────────────────┐ │
│ │ │ │
│ │ sqlserver keycloak mailpit │ │
│ │ mssql/server:2022 keycloak:26.7.5 mailpit:v1.31.4 │ │
│ │ DBs: RALQM, keycloak Realm "ral", start-dev SMTP-Fänger, In-Memory │ │
│ │ Volume: sqlserver_data (extern, persistent) │ │
│ │ │ │
│ │ sqlserver-init (init-Container, läuft einmalig) │ │
│ │ keycloak-provisioner (init-Container, läuft einmalig) │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────┘
Alle Compose-Ports der Development- und local-Stacks sind ausschließlich an 127.0.0.1
gebunden. Produktionsbetrieb, Backupstrategie und Monitoring werden aus dieser lokalen
Development-Umgebung nicht abgeleitet
(siehe DEVELOPMENT-GUIDE.md, Abschnitt "Docker-Compose-Umgebung ist
ausschließlich für lokale Development-Daten"). Für den Serverbetrieb liegt unter
applications/RAL/etc/docker/deploy/ ein eigener, bisher unerprobter
Einknoten-Stack im Repository (Abschnitt 3); dessen Caddy bindet 80/443 standardmäßig an
0.0.0.0 (CADDY_HTTP_BIND) und ist damit aus dem Internet erreichbar.
2. Knoten und Erreichbarkeit
Die Anwendung besitzt ihren Betrieb unter
applications/RAL/QualityMarks/HearingPortal/etc; Entwicklungsskripte und Wrapper liegen
am selben App-Root in tools beziehungsweise direkt daneben. Die bisherigen Root-Wrapper
delegieren dorthin. Kundenweit geteilte Keycloak-Dateien und der Infrastruktur-Deploy-Stack
liegen unter applications/RAL/etc/docker; der Anwendungs-Deploy-Stack liegt im App-etc.
Die Compose-Konfigurationen binden ihre gemeinsamen Dateien über relative Pfade ein.
Gemeinsame lokale ABP-/Syncfusion-Lizenzen liegen am Repository-Root unter
secrets/appsettings.local.secrets.json; nur die leere .gitkeep ist versioniert.
Setup, Doctor und Lifecycle verwenden diesen Pfad. Der Development-/F5-Host liest
ausschliesslich die Lizenzfelder, waehrend Container diese als Prozessumgebung
erhalten. Stack-Zugangsdaten und Endpunkte bleiben im eigenen Runtime-Verzeichnis.
Jeder Entwickler besitzt einen eigenen Cohesion-Feed-Token in der ignorierten
secrets/cohesion-feed.json. Setup registriert ihn unter Windows verschluesselt in
der Benutzer-NuGet-Konfiguration; Gate/Lifecycle importieren ihn nur in den Prozess.
ABP verwaltet seinen Benutzerfeed ueber den eigenen abp login. ABP-Entwickler-
Passwoerter gehoeren nicht in die Landingzone. CI besitzt separate Feedzugaenge.
Die gemeinsame Datei wird weder in Images noch in Clean-Room-/Graph-Manifeste aufgenommen.
Neue lokale Stacks werden nach CAF-REPO-03 je App, Worktree, Branch und Betriebsart
isoliert. Bestehende Legacy-Ressourcen bleiben unangetastet. Der Descriptor unter
%LOCALAPPDATA%/CAF/stacks/<worktree-id>/<stack-id> besitzt Namen, reservierte Ports
und Docker-Daemon-Zuordnung; settings.env im selben Verzeichnis besitzt lokale Secrets.
Container, Netzwerk, Volume, PID-/Status-/Logdateien und Image-Tag sind kontextgebunden.
Der Host verwendet fuer F5 denselben lesenden Resolver wie die Lifecycle-Skripte.
Das Launch-Profil setzt externalUrlConfiguration: true, damit Visual Studio keine
eigenen Standard-URLs injiziert. Widersprechende Endpunkte bleiben ein Startfehler.
status.cmd zeigt die tatsaechlichen Endpunkte. Die Portnamen in der Uebersicht
beziehen sich auf die Zuteilung im Descriptor.
Das Hearing Portal verwendet weiterhin den bestehenden Realm ral. EnvironmentalLabel
ContractManager und LL ContractManager sollen dieselbe Keycloak-Instanz nutzen, erhalten aber
auf Kundenvorgabe je einen eigenen Realm und OIDC-Client. Für LogoLicense ist der Realm
ral-logolicense mit dem Client ral-logolicense-contractmanager im eigenen lokalen
Entwicklungsstack des ContractManagers eingerichtet; die Provisionierung bei RAL ist offen. Der
EnvironmentalLabel-Realm ist noch nicht eingerichtet; siehe
RAL-Anwendungen.
App-URL, SQL, OIDC/Callbacks, Portal-/Dokumentlinks und SMTP werden aus demselben Kontext abgeleitet. Widersprechende Prozess-/CLI-Endpunkte werden beim Development-Host abgewiesen. Build-/Testbefehle koordinieren die Ausgaben je Worktree. Fuer manuelle parallele Browser-Sitzungen getrennte Profile verwenden; BrowserGate erzeugt eigene Playwright-Kontexte und einen kompletten eigenen Run-Stack.
3. Docker-Compose-Dienste
Definiert in
applications/RAL/QualityMarks/HearingPortal/etc/docker/development/docker-compose.yml
(Compose-Projekt <stack-id>):
| Dienst | Image | Rolle | Lebenszyklus |
|---|---|---|---|
sqlserver |
mcr.microsoft.com/mssql/server:2022-CU27-ubuntu-22.04 (Digest-gepinnt) |
Persistenter SQL-Server-Provider für Anwendung und Keycloak | restart: unless-stopped, Healthcheck via sqlcmd |
sqlserver-init |
dasselbe SQL-Server-Image | Einmaliger Init-Container: legt RALQM-Login (RALQM-login.sql) und keycloak-DB (keycloak-database.sql) an |
restart: "no", läuft nach sqlserver healthy, terminiert nach Erfolg |
keycloak |
quay.io/keycloak/keycloak:26.7.5 (Digest-gepinnt) |
OIDC-Provider, start-dev --import-realm, persistiert im mssql-Backend (DB keycloak) |
restart: unless-stopped, Healthcheck gegen /health/ready |
keycloak-provisioner |
dasselbe Keycloak-Image | Einmaliger Init-Container: reconciliiert Realm/Client/Mapper/Gruppen/Development-Benutzer/SMTP idempotent (Entrypoint reconcile.sh, siehe „Keycloak-Reconciler“ unten) |
restart: "no", läuft nach keycloak healthy |
mailpit |
axllent/mailpit:v1.31.4 (Digest-gepinnt; ersetzt MailHog seit 08.10.2026) |
Development-SMTP-Fänger mit Web-UI und REST-API v1, Nachrichten nur im Container, keine Volumes/Credentials | restart: unless-stopped, Healthcheck mailpit readyz |
greenmail |
greenmail/standalone:2.1.14 (Digest-gepinnt), nur mit Compose-Profil delivery-reports (DELIVERY_REPORTS_ENABLED=true) |
Rückläuferpostfach (RAL-QM-HP-76, ADR-17): SMTP 3025 zum Einliefern von Testmeldungen, IMAP 3143 für den Abruf; Host-Ports GREENMAIL_SMTP_PORT/GREENMAIL_IMAP_PORT; nur Development/Local |
restart: unless-stopped, Healthcheck TCP auf 3143 |
clamav |
clamav/clamav:1.4 (Digest-gepinnt) |
Schadsoftwareprüfung hochgeladener Dateien (RAL-QM-HP-50, ADR-16), clamd INSTREAM auf 3310, Host-Port CLAMAV_PORT |
restart: unless-stopped, Healthcheck clamdcheck.sh, start_period 180 s für das Laden der Signaturen |
Alle Dienste hängen am Bridge-Netzwerk <stack-id>-backend und schreiben
begrenztes JSON-File-Logging (max-size: 10m, max-file: 3). Die kausal abhängige Kette
SQL → Principal → Keycloak → Reconcile → Migration läuft laut
HearingPortal-Leitfaden §4 nie parallel; lediglich Keycloak,
Mailpit und ClamAV starten beim Kaltstart gleichzeitig.
Keycloak-Reconciler: Realm-Scope und Client-Scope
Der Reconciler unter applications/RAL/etc/docker/shared/keycloak/init/ trennt den Realm-Scope des
Kundenbetriebs vom Client-Scope der Anwendung. Heute ist dieser Pfad für das Hearing Portal
im Realm ral eingerichtet. SMTP, Passwortrichtlinie, Brute-Force-Schutz und Lifespans gehören
zum jeweiligen Realm; ein Client-Update darf diese Einstellungen nicht überschreiben.
Die zusätzlichen, getrennten Realms für EnvironmentalLabel ContractManager und LL ContractManager benötigen später eigene
Provisionierung und passende Prüfungen; die vorhandene HearingPortal-Konfiguration wird dafür
nicht unverändert auf weitere Anwendungen übertragen.
| Datei | Besitzer | Inhalt |
|---|---|---|
reconcile.sh |
Entrypoint beider Compose-Stacks | Dünner Orchestrator: führt erst den Realm-, dann den Client-Scope aus |
reconcile-common.sh |
geteilte Bibliothek | kcadm-Wrapper, Login, Lookups, ensure_group, Pflichtvariablenprüfung, gemeinsame Konfiguration (Server-URL, Realm, kcadm-Konfigurationen) |
reconcile-realm.sh |
Kunde, genau einmal je Realm | Realm-Einstellungen, SMTP, Passwortrichtlinie, Brute-Force-Schutz, Lifespans, Basisgruppen caf-developers und caf-users |
reconcile-client.sh |
Anwendung, je Anwendung einmal | Client ral-qualitymarks samt Protocol-Mappern, dedizierter Provisioning-Client, Anwendungsgruppen gz-referenten/gz-geschaeftsfuehrung/gz-institutionen, Development-Benutzer sowie die reine Live-Verifikation (KEYCLOAK_RECONCILE_VERIFY_ONLY) |
Lokal ändert sich dadurch nichts: Der Container-Entrypoint bleibt
/opt/caf/keycloak-init/reconcile.sh, und ein Lauf konvergiert weiterhin vollständig. In
einer geteilten Umgebung gleicht der Kunde den Realm-Scope einmal ab; jede Anwendung führt
danach nur ihren eigenen Client-Scope aus und fasst den Realm nicht an.
Drei Schalter machen denselben Reconciler deploy-fähig. Jeder Default reproduziert exakt das bisherige Development-Verhalten:
| Variable | Default (Development/local) | Deploy |
|---|---|---|
KEYCLOAK_SSL_REQUIRED |
none |
external für einen aus dem Internet erreichbaren Realm |
KEYCLOAK_PROVISION_DEV_USERS |
true |
false: keine Development-Benutzer; die beiden Development-Passwörter sind dann auch keine Pflichtvariablen mehr |
KEYCLOAK_SMTP_SERVER_JSON |
Mailpit-Literal (mailpit:1025, ohne Zugangsdaten) |
Definition eines echten Relays |
Die normativen Literale (SMTP-Block, Passwortrichtlinie, Gruppen, Client-Konfiguration)
bleiben gegen ral-realm.json durch
KeycloakConfigurationConsistencyTests.cs
abgesichert; die Tests lesen jeweils die Datei, die das Literal nach der Trennung besitzt.
Persistentes Volume
Genau ein externes, benanntes Volume trägt den gesamten Datenbankzustand:
volumes:
sqlserver_data:
name: ral-qualitymarks-hearing-portal-sqlserver-data
external: true
external: true bedeutet: Compose legt es nicht implizit an — die Lifecycle-Skripte
(start.cmd/setup.cmd) erzeugen und besitzen es explizit. Es überlebt stop.cmd und
restart.cmd. Der einzige destruktive Standardpfad ist reset.cmd, strikt begrenzt auf
ENVIRONMENT_NAME=Development und exakt dieses Volume (siehe
GETTING-STARTED.md, Abschnitt 5).
.env-gesteuerte Konfiguration
Die einzige lokale, nicht versionierte Compose-Konfigurationsdatei ist
settings.env im isolierten Stack-Verzeichnis
(Vorlage: …/development/.env.example). Sie legt Image-Digests,
Ports, SQLSERVER_SA_PASSWORD, RALQM_DB_PASSWORD, KEYCLOAK_ADMIN_PASSWORD,
KEYCLOAK_DB_PASSWORD, KEYCLOAK_CLIENT_SECRET, KEYCLOAK_PROVISIONING_CLIENT_SECRET,
KEYCLOAK_DEV_ADMIN_PASSWORD, KEYCLOAK_DEV_USER_PASSWORD, APP_URL und TIME_ZONE fest.
setup.cmd erzeugt neue Dateien mit den Descriptor-Endpunkten und zufaelligen lokalen
Zugangsdaten. Vorhandene Dateien werden validiert; fehlende Werte werden nicht still ersetzt.
Secrets erscheinen nie im
Repository; Diagnosewege (doctor.cmd) melden nur SET/MISSING (siehe Abschnitt 13 im
DEVELOPMENT-GUIDE.md und Querschnittskonzepte
für die vollständige Secret-Regel).
Ablage unter etc/docker
Die Compose-Artefakte sind je Kunde, Produkt und Anwendung abgelegt; kundenweit
geteilte Bausteine liegen genau einmal unter shared:
applications/RAL/
├── etc/docker/
│ ├── shared/keycloak/ # kundenweite Realm-/Reconciler-Quellen
│ └── deploy/ # Kunden-Infrastruktur und Server-Skripte
└── QualityMarks/HearingPortal/etc/docker/
├── development/ # Compose und wertfreie Konfigurationsvorlage
├── local/ # containerisierter Local-Stack und Vorlage
├── sqlserver/ # app-eigene SQL-Provisionierung
└── deploy/ # Anwendungs-Tier fuer den Serverbetrieb
applications/RAL/etc/docker/shared/keycloak ist die einzige Quelle für Realm-Import und Reconciliation;
die Compose-Files der Anwendung binden Keycloak- und SQL-Server-Verzeichnisse relativ
ein. local ist der vollständig containerisierte Local-Stack: Er startet neben der
Infrastruktur auch Migration und Anwendung als Container aus dem lokal gebauten Image
caf/ral-qualitymarks-hearing-portal:<stack-id> (tools/build/build-images-locally.ps1) und
läuft mit ASPNETCORE_ENVIRONMENT=Development konfigurationsgleich zum nativen
Development-Weg. Eigener Compose-Projektname je App/Worktree/Branch/Local fuer Container,
Netzwerk und Volume sowie kollisionsfreie, an Loopback gebundene Host-Ports
erlauben den Parallelbetrieb neben dem Development-Stack; konfiguriert wird er über
eine eigene, nicht versionierte settings.env im Stack-Verzeichnis (Vorlage local/.env.example, siehe
GETTING-STARTED.md, Abschnitt „Containerisierter
local-Stack“). Die getrennten Deploy-Quellen tragen den Serverbetrieb (nächster Abschnitt).
Vorhandene Legacy-Ressourcen bleiben erhalten; neue lokale Kontexte erhalten eigene Namen.
Deploy-Stack: Kunden-Tier und Anwendungs-Tier
Noch nicht in Betrieb. Die Artefakte unter
applications/RAL/etc/docker/deploy/sind vollständig, aber bisher weder auf einem Kundenserver noch in einer Pipeline gelaufen. Die Development- undlocal-Stacks bleiben davon unberührt; sie sind weiterhin die einzigen erprobten Wege.
Anders als Development und local ist der Deploy-Stack nicht ein Stack je Anwendung,
sondern zwei Ebenen mit unterschiedlichem Besitzer:
| Ebene | Datei | Compose-Projekt | Dienste |
|---|---|---|---|
| Kunden-Tier | deploy/infra/docker-compose.yml |
ral-infra |
sqlserver, sqlserver-init, keycloak (Modus start), keycloak-realm-reconciler, caddy |
| Anwendungs-Tier | deploy/apps/hearingportal/docker-compose.yml |
ral-hearingportal |
keycloak-client-reconciler, hearingportal, dazu im Profil ops hearingportal-migrator und sqlserver-reconcile |
Der Schnitt folgt dem Besitz und spiegelt exakt die Trennung des Keycloak-Reconcilers
(Abschnitt „Keycloak-Reconciler“ oben): In Produktion bedienen ein Keycloak und ein
SQL Server die vorgesehenen RAL-Anwendungen des Kunden, während jede Anwendung ihrem
eigenen Release-Takt folgt. Die zusätzlichen Realms und Anwendungs-Tiers der beiden weiteren
Anwendungen (LogoLicense lokal ausführbar, EnvironmentalLabel Stub) sind im Deployment noch nicht
umgesetzt. Ein Anwendungs-Update darf die Identitäts- und Datenbankebene
nicht anfassen — deshalb reconciliiert der Kunden-Tier ausschließlich den Realm
(reconcile-realm.sh) und der Anwendungs-Tier ausschließlich seinen Client
(reconcile-client.sh).
Verbunden werden beide Ebenen über das Bridge-Netzwerk ral-backend: Der Kunden-Tier
deklariert es, der Anwendungs-Tier bindet es als external: true ein. Fehlt der
Kunden-Tier, bricht der Anwendungs-Tier sofort ab („network ral-backend declared as
external, but could not be found“). Beide Ebenen lassen sich unabhängig voneinander
starten, stoppen und aktualisieren.
┌──────────────── Server (ein Knoten) ────────────────────────────────────┐
│ │
│ Internet ──► caddy (nur 80/443, TLS-Terminierung, WebSocket-fähig) │
│ │ app.<DOMAIN> ─────────────┐ │
│ └─ auth.<DOMAIN> ──┐ │ │
│ ▼ ▼ │
│ ┌── ral-infra (Kunde) ──────┐ ┌── ral-hearingportal (Anwendung) ──┐ │
│ │ keycloak (start) │ │ hearingportal (Production) │ │
│ │ keycloak-realm-reconciler│ │ keycloak-client-reconciler │ │
│ │ sqlserver + init │ │ [ops] migrator, sqlserver-reconc.│ │
│ └───────────────────────────┘ └───────────────────────────────────┘ │
│ └────────── Netzwerk ral-backend ──────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
Vier Festlegungen unterscheiden den Deploy-Stack inhaltlich vom local-Stack:
- Kein Realm-Import.
keycloakstartet ohne--import-realmund ohne Mount vonshared/keycloak/realm/.ral-realm.jsonist ein Development-Bootstrap: sieben Development-Benutzer undsslRequired=nonegehören nicht auf einen aus dem Internet erreichbaren Server. Den Realm legt stattdessen der Realm-Reconciler an — er ist idempotent und setzt dieselben normativen Werte (abgesichert durchKeycloakConfigurationConsistencyTests.cs). ASPNETCORE_ENVIRONMENT=Production, kein~/.abp-Mount. Die ABP-Pro-Lizenz wird offline überAbpLicenseCodegeprüft statt über den abp.io-Login des Entwicklers. Production aktiviert zugleichUseHsts/UseHttpsRedirection; da im Quellcode keine Behandlung von Weiterleitungs-Headern existiert, setzt der StackASPNETCORE_FORWARDEDHEADERS_ENABLED=true— sonst entsteht hinter Caddy eine Endlosschleife aus Weiterleitungen.- Migration nur auf ausdrückliche Anweisung.
hearingportal-migrator(und der nachgelagertesqlserver-reconcile, der den[ralqm]-Datenbankbenutzer erst nach dem Anlegen der Datenbank erzeugen kann) liegen im Compose-Profilops. Ein einfachesdocker compose upkann damit keine Migration auslösen, auch nicht beim Neustart des Servers. - Persistente Data-Protection-Schlüssel. Der Anwendungs-Tier hängt dafür ein benanntes Volume ein; ohne dieses würde jeder Neustart sämtliche Anmelde-Cookies entwerten.
Dazu kommt die Serverebene selbst: deploy/server/
enthält bootstrap.sh (einmalige Vorbereitung der Maschine), deploy.sh (Routine-Deployment des
Anwendungs-Tiers) und die beiden systemd-Units, die die Tiers nach einem Serverneustart wieder
hochfahren. Betrieb, Reihenfolge der Inbetriebnahme, Datensicherung und die Liste der noch nicht
automatisierten Punkte stehen in
applications/RAL/etc/docker/deploy/README.md.
4. Der Host-Prozess
Der ausführbare Knoten ist ein einzelner .NET-Prozess: das Projekt
applications/RAL/QualityMarks/HearingPortal/src/Host/CAF.Applications.RAL.QualityMarks.HearingPortal.csproj,
im Development-Weg nativ auf Windows gestartet, im local- und im Deploy-Stack als Container aus
Host/Dockerfile (Dienst hearingportal). Er bündelt in einem Prozess:
- Kestrel-Endpunkt mit Blazor Interactive Server Rendering (kein WASM-Bootstrap),
- die Composition Root, die
Shell,Contractsund alleFeatures/*- sowieCAF.Modules.*-Bausteine referenziert (siehe Bausteinsicht), entsprechend der No-Layer-Architektur aus dem Root-AGENTS.md, - den EF-Core-DbContext samt Migrations-Host
(
applications/RAL/QualityMarks/HearingPortal/src/Host/Migrations), - ABP Background Worker für Postausgang/Fristenaktionen (Outbox, Due Actions).
Konfigurationsquellen werden in fester Priorität zusammengeführt (siehe Getting Started, Host-Konfigurationspriorität):
versionierte appsettings-Dateien
< stack-eigene settings.env (nur Development-Workstation)
< appsettings.local.secrets.json
< Umgebungsvariablen
< Kommandozeilenargumente
Host/Configuration/DevelopmentDockerEnvironmentConfiguration.cs liest dafür nur in
IsDevelopment() die Datei settings.env im durch den gemeinsamen Resolver gefundenen
Stack-Verzeichnis ausserhalb des Repositorys und leitet daraus App:SelfUrl, App:RedirectAllowedUrls,
ConnectionStrings:Default (Server 127.0.0.1,<SQLSERVER_PORT>, Datenbank RALQM, Login
ralqm), Authentication:Authority (<KEYCLOAK_PUBLIC_URL>/realms/ral) sowie die
Keycloak-Provisioning-Werte ab. Damit liest F5 aus Visual Studio dieselbe Laufzeitkonfiguration
wie start.cmd, ohne einen vorgeschalteten PowerShell-Prozess zu benötigen. Fehlt .env oder ist
ein Pflichtwert noch CHANGEME, bricht der Start fail-closed mit einer expliziten Meldung ab.
5. Migration und Seed (--migrate-database)
Schema und Demodaten werden nicht implizit beim normalen Start ausgeführt, sondern über denselben Host-Prozess mit einem expliziten Kommandozeilenschalter:
dotnet run --project applications/RAL/QualityMarks/HearingPortal/src/Host -- --migrate-database
Program.cs erkennt --migrate-database (IsMigrateDatabase), schaltet auf ein
Migrations-Logging-Profil um und ruft nach InitializeApplicationAsync() den
HearingPortalDbMigrationService auf. Dieser läuft in drei Schritten:
EnsureMigrationsExist()— derHearingPortalMigrationPathGuardsucht ab dem Startverzeichnis nach demCAF.slnx-Repository-Marker und verlangt, dassapplications/RAL/QualityMarks/HearingPortal/src/Host/Migrationsexistiert und mindestens eine echte Migrationsklasse enthält (kein.Designer.cs, keinModelSnapshot.cs) — ein Schutz gegen einen falsch aufgesetzten Arbeitsbaum. Findet sich kein Marker (Published-Lauf, z. B. der containerisiertelocal-Stack), prüft der Guard stattdessen fail-closed, dass mindestens eine kompilierte EF-Core-Migrationsklasse in der Host-Assembly vorhanden ist.MigrateDatabaseSchemaAsync()— führt die EF-Core-Migrationen über denHearingPortalDbSchemaMigratorgegen dieRALQM-Datenbank aus.SeedDataAsync()— ruft ABPsIDataSeedermit einem zufällig erzeugten, deaktivierten Bootstrap-Administratorpasswort auf (kein festes Secret im Code).
Praktisch läuft dieser Schritt in den Lifecycle-Skripten mit einem separaten, nur für den
Bootstrap privilegierten SQL-Zugang; danach reconciliiert start.cmd den dauerhaften,
eingeschränkten ralqm-Datenbankprincipal (siehe
GETTING-STARTED.md, Abschnitt 6, Schritt 9). Migration und Seed sind
idempotent: ein wiederholter Lauf legt keine Duplikate an und überschreibt keine vorhandenen
Demodaten (setup.cmd -WithDemoData erzwingt den Abgleich bewusst erneut).
6. Lokaler Start- und Betriebsweg
Der schlanke, skriptlose Pfad — vorausgesetzt
settings.env im isolierten Stack-Verzeichnis und
appsettings.local.secrets.json liegen bereits vor:
# 1. Infrastruktur (SQL Server, Keycloak, Mailpit)
docker compose -f applications/RAL/QualityMarks/HearingPortal/etc/docker/development/docker-compose.yml up -d
# 2. Schema/Seed (nur beim ersten Start bzw. nach neuen Migrationen)
dotnet run --project applications/RAL/QualityMarks/HearingPortal/src/Host -- --migrate-database
# 3. Anwendung starten
dotnet run --project applications/RAL/QualityMarks/HearingPortal/src/Host
Der komfortable, empfohlene Weg sind die Root-.cmd-Wrapper (setup.cmd, start.cmd,
status.cmd, stop.cmd, restart.cmd, reset.cmd, doctor.cmd, logs.cmd), dünne Aufrufer der
kanonischen PowerShell-Skripte unter tools/scripts. start.cmd führt deterministisch aus:
SDK-/Zertifikatsprüfung → Restore → Docker-/Volume-Prüfung → SQL Server + Init-Container →
Keycloak + Mailpit parallel → Keycloak-Reconciliation → Migration/Seed →
ralqm-Principal-Reconciliation → Start des Host-Prozesses als versteckter
Windows-Prozess (PID-Datei unter %LOCALAPPDATA%\CAF.Applications.RAL.QualityMarks.HearingPortal).
Details, Idempotenz-Garantien und alle Kommandovarianten stehen in
GETTING-STARTED.md, Abschnitte 4–6.
7. Zuordnung Bausteine → Infrastruktur
| Baustein | Läuft in | Persistiert/kommuniziert über |
|---|---|---|
Features/Authorization, Features/Hearings, Features/Institutions |
Host-Prozess (in-process) | EF Core → SQL Server (RALQM, Tabellenpräfix RALQM…) |
ABP-Ersatz-Features Features/{Identity,Languages,TextTemplates,AuditLogs,Gdpr,Settings} |
Host-Prozess (in-process) | ABP-Modulschemata über denselben HearingPortalDbContext → SQL Server (RALQM) |
CAF.Modules.Documents(.Contracts) |
Host-Prozess | ABP File Management → SQL Server (RALQM) |
CAF.Modules.Authentication |
Host-Prozess | OIDC-Client gegen die stack-eigene Keycloak-URL, Realm ral |
CAF.Modules.UI.Blazor |
Host-Prozess (Blazor Interactive Server) | Cohesion-Assets aus wwwroot, kein externer Dienst |
| Shell, Contracts | Host-Prozess | keine eigene Persistenz |
Hearing-Versand (IEmailSender) |
Host-Prozess (Background Worker) | SMTP → Mailpit (127.0.0.1:1025) |
Schadsoftwareprüfung (DocumentScanWorker, Upload) |
Host-Prozess | clamd INSTREAM → ClamAV (127.0.0.1:CLAMAV_PORT, im Local-/Deploy-Stack clamav:3310) |
| Keycloak-Provisioning (Mitarbeitenden-/Institutionskonten) | Host-Prozess | Keycloak Admin-REST via dediziertem Service-Client ral-qualitymarks-provisioning |
| EF-Migrationen | Host-Prozess (--migrate-database) |
SQL Server (RALQM) |
Es gibt keine eigenständig deploybaren Knoten je Feature-Modul: die No-Layer-Architektur
(Root-AGENTS.md) bündelt alle Fachmodule im selben Host-Prozess. Im
Development-Weg sind nur die Infrastrukturdienste (SQL Server, Keycloak, Mailpit) eigene Container;
im local- und im Deploy-Stack läuft derselbe Host-Prozess zusätzlich als eigener Container.
Mehrknotenbetrieb und Load Balancing sind nicht Bestandteil dieses Repositories — der Deploy-Stack
zielt auf genau einen Serverknoten.
8. Siehe auch
- Bausteinsicht — fachliche und technische Modulaufteilung innerhalb des Host-Prozesses.
- Laufzeitsicht — Ablauf einzelner Anwendungsfälle über diese Knoten hinweg.
- Querschnittskonzepte — Secret-Handling, Konfigurationspriorität, Auditierung.
- GETTING-STARTED.md — vollständiger Einstieg inkl. Lifecycle-Skripten, Diagnose und Kennzahlen.
- HearingPortal-Leitfaden §4 — konkrete Konfigurationsregeln.
- CAF-Leitfaden §15 — Nachweise und Qualitätsgate.
applications/RAL/QualityMarks/HearingPortal/etc/docker/development/docker-compose.yml— normative Dienstdefinition.
08. Querschnittliche Konzepte
Dieses Kapitel bündelt Konzepte, die mehrere Module gleichermaßen betreffen: Authentifizierung/ Autorisierung, Persistenz, persistierte Kennungen, Lokalisierung, UI-Grenzen, Fehlerbehandlung und Teststrategie. Die Modulgrenzen selbst stehen in Bausteinsicht, der konkrete Ablauf eines Requests in Laufzeitsicht.
Die lokale F5-Konfiguration ruft den gemeinsamen Stack-Resolver ausschließlich über
Windows PowerShell im OS-Systemverzeichnis auf. Der Host gibt das feste Repositoryskript
mit ArgumentList, UseShellExecute=false, deaktiviertem Profil und ohne interaktive
Eingabe weiter; CAF_STACK_ID wird vor dem Start validiert. Weder ausführbare Datei noch
Skript oder Command-Text sind Requestparameter. Der Checkout bleibt ausführbarer,
vertrauenswürdiger Entwicklercode. Die beiden eng begrenzten SCS0001-1-Ausnahmen und
der reale Prozessnachweis sind in CAF-REPO-02, Abschnitt 11
erläutert. Produktive Authentifizierung und ABP-Modulgrenzen ändern sich dadurch nicht.
1. Authentifizierung und Autorisierung
Keycloak (OIDC, Authorization Code + PKCE)
→ CAF.Modules.Authentication (Cookie-Session, Claim-Mapping, Revalidierung)
→ lokaler ABP IdentityUser, gebunden über den stabilen OIDC-Subject "sub"
→ RALQM-Rolle (Administrator/CaseOfficer/Management/Institution)
→ ABP Permission (RALQM.<Feature>…)
→ Application Service + Objektprüfung
- Keycloak ist alleiniger Token-Issuer und Identitätsquelle; die Anwendung betreibt keinen lokalen OpenIddict-Server.
- Kundendesign (RAL-QM-HP-102, ADR-23): Das gemeinsame RAL-Basistheme
ral-v1erbtkeycloak.v2; das app-eigeneralqm-legalerbtral-v1und behält Rechtsfooter sowie bestehende A11y-Korrekturen. Im bestehenden Realmralistral-v1der Standard, damit abgelaufene native Aktionslinks auch ohne Clientkontext das Kundendesign erhalten. Der HP-Clientoverride bleibtralqm-legal; andere Clients ohne Override erben nur die Kundenbasis. Andere Realms, Credentials, native Provideraktionen und OIDC-Grenzen werden nicht geändert. Vorhandene RAL-/HearingPortal-Assets werden lokal ausgeliefert; Hell/Dunkel folgt der OS-Präferenz ohne neue Speicherung oder Cross-Origin-Übernahme. Umsetzungsentscheidung und Rückfall: ADR-23. CAF.Modules.Authenticationist der wiederverwendbare, anwendungsneutrale OIDC-Client (Authorization Code mit PKCE, Cookie-Session-Policy, Token-Propagierung, revalidierenderAuthenticationStateProvider, Sign-out). Er kennt weder GZ-Rollen noch Permissions — siehemodules/Authentication/README.md.- ABP Identity speichert das lokale Benutzerabbild. Die Verknüpfung verwendet ausschließlich
den stabilen
sub, niemals die E-Mail-Adresse. HearingPortal.Authorizationdefiniert die produktweiten Rollen (HearingPortalRoles:RALQMAdministrator,RALQMCaseOfficer,RALQMManagement,RALQMInstitution) und komponiert deren Grants aus den Permissions der Feature-Contracts. Ein neues Feature-Recht wird nicht zentral in Authorization deklariert, sondern im owning{Feature}.Contracts-Projekt.- Rollenzuschnitt seit RAL-QM-HP-18: Der Systemadministrator ist eine Verwaltungsrolle ohne
Verfahrens- und Freigaberechte — Kontenverwaltung, Rollenvergabe, Institutionsstammdaten,
Wertelisten, Ablage, Vorlagen, Postausgang, Störungen und manuelle Fristläufe, aber kein
Anlegen, Einreichen, Freigeben, Versenden, Bescheiden oder Lesen von Stellungnahmen. Referent
(Fallarbeit inklusive Versand, Nachversand, Bescheidungsübermittlung
RALQM.Hearings.Adjudicateund AbschlussRALQM.Hearings.Complete) und Geschäftsführung (Vier-Augen-Entscheide: FreigabeRALQM.Hearings.Approveund Nachversand-Freigabe, dazu Abbruch) halten zusammen jedes Verfahrensrecht. Seit RAL-QM-HP-51 (SPEC-RAL-QM-HP-46 Regel 1/O1, SPEC-RAL-QM-HP-51 O2, RAL-QM-HP-34 AC-2/3) liegen Bescheidungsübermittlung und Abschluss beim Referenten; die Geschäftsführung bescheidet und schließt nicht ab, der Seed entzieht ihr beide Rechte in bestehenden Datenbanken. Direkter und kombinierter einstufiger Abschluss setzen dieselbe Rollenregel durch (Dienst:AdjudicateUNDComplete, Oberfläche zusätzlichAuthorizeViewaufComplete). Die Rolle Institution trägt nurRALQM.Hearings.Portal.Access. Kontenrechte:RALQM.Accounts(Übersicht),RALQM.Accounts.Invite(interne Konten, Systemadministrator),RALQM.Accounts.InviteInstitution(Institutionskonten, Systemadministrator und Referent). Der Seed gleicht die Grants der vier Produktrollen bei jedem Start exakt ab (HearingPortalDomainRolesDataSeedContributor); die technische ABP-Rolleadmindes Ersteinrichtungskontos bleibt außerhalb dieser Komposition. - Die Permission-Gruppe heißt
RALQM(HearingPortalPermissions.GroupName); Feature-Permissions hängen sich darunter an, zum BeispielRALQM.Hearings.ApproveoderRALQM.Accounts.Invite. - Jeder Application Service prüft seine Permission serverseitig; Objektzugriff, Status und Teilnehmerzuordnung werden zusätzlich im owning Feature geprüft. Ein versteckter Button ist keine Autorisierung.
Der gemeinsame Papierkorb kombiniert getrennte Autorisierungsbereiche. Filing prüft Read und aktuelle interne Kontoeignung; Hearings liefert Verfahrenszeilen erst nach seinen eigenen Leserechten. Weder bekannte IDs noch ein gemeinsamer Filter erweitern diese Sicht. Für die Wiederherstellung im ursprünglichen Verfahren gelten Filing.Read/Manage und die Hearings-Lese-/Dokumentpflegerechte sowie das offene Zweckfenster. Ist dieses geschlossen, erfordert die ausdrücklich gewählte unabhängige Ablagekopie Filing.Read/Manage, Hearings.Default/Documents.Default/Download und ein aktuell zulässiges eigenes oder gemeinsames Ziel. Die Quellautorisierung und -sperre bleibt bis zum Zielcommit in derselben Serializable- Transaktion erhalten; bekannte Dokument-IDs oder ein früher erteilter Grant ersetzen sie nicht. Verfahrensstatus, Quellreferenz und widerrufene Teilnehmergrants ändern sich durch die Kopie nicht. Auch ein idempotenter Wiederholungsaufruf prüft aktuelle Rechte und die gebundene aktive Zielkopie. Verfahrens-Purge benötigt zusätzlich Filing.Purge und die Hearings-Lese-/Dokumentpflegerechte. Der Hintergrundprozess baut für den protokollierten Actor einen aktuellen Principal und prüft diese Grants erneut. Kontenübertragung verlangt einen aktuellen Produktadministrator und Transfer sowie Accounts.Invite; die Berechtigung des Actors ist unabhängig von der Eignung des Quell- und Zielkontos. Weitere Abläufe beschreibt Kapitel 6.5.
Die Übernahme einer Ablagedatei ins Verfahren (RAL-QM-HP-16) bekommt keinen eigenen
Permission-Knoten, sondern stapelt vorhandene Rechte: RALQM.Filing.Read für die Quelle sowie
RALQM.Hearings, RALQM.Hearings.Documents und RALQM.Hearings.Documents.Manage für das Ziel.
Wer eine Unterlage anhängen und die Ablage lesen darf, darf fachlich auch übernehmen; ein neues
Recht hätte dieselbe Menge beschrieben und zusätzlich vergeben werden müssen. Zu den ABP-Grants
tritt wie bei jeder Filing-Operation die Kontoeignung — aktives internes Konto mit genau einer
Produktrolle Referent oder Administrator und eindeutiger Keycloak-Bindung
(IStaffFilingAccessPort.EnsureFilingUserAsync) —, geprüft vor jedem Metadatenzugriff und in
beiden Hälften: im Filing-Dienst und noch einmal im Hearings-Port, der seine eigene Fläche nicht
von der Vertrauenswürdigkeit des Aufrufers abhängig macht. Der Verwendungsnachweis verlangt
dieselben Leserechte ohne Manage. Er legt nichts Fremdes offen: Zeilen zu Verfahren, die der
Aufrufer nicht lesen darf, und Zeilen zu Elementen in einem fremden persönlichen Ablagebereich
fallen weg, ohne dass die Abfrage scheitert und ohne Platzhalter, der ihre Existenz verriete —
dieselbe Regel wie bei IHearingDocumentTrashPort.GetListAsync. Bezeichnung und Status eines
nicht lesbaren Verfahrens verlassen die Hearings-Hälfte gar nicht erst. Eine fachliche Abweisung
der Übernahme ist ein Ergebnis mit Fehlercode, keine Ausnahme, damit eine Mehrfachauswahl je Datei
weiterläuft; fehlende Berechtigung und fehlende Kontoeignung bleiben Ausnahmen und brechen ab.
Ablauf: Kapitel 6.6.
Die Teilnahme-Seitenroute prüft vor dem Rendern denselben aktuellen Lesefilter wie die
Portalübersicht. HearingPortalParticipationRouteMiddleware liegt hinter Autorisierung und
Rate-Limiter und fragt den prozessinternen Vertrag IsParticipationReadableAsync ab.
Fremde, unbekannte und entzogene Beteiligungen antworten neutral mit 404 ohne Fachinhalt.
Die gemeinsame Policy hearing-portal begrenzt Teilnahme-Seite und Dokumentdownload;
sie ersetzt weder die aktuelle Kontobindung noch den institutionsbezogenen Dokumentgrant.
Dieser Vertrag aus RAL-QM-HP-30 verwendet vorhandene Tabellen; seine SQL-Nachweise prüfen
Filter und konkurrierende Zugriffe, keine Schemaänderung.
Die Abschlussansicht (RAL-QM-HP-62)
zeigt bei einem beendeten Verfahren den Verlauf der eigenen Beteiligung als Projektion, nie den
internen Verlauf: HearingPortalTimelineRules nimmt nur die Stationen der Positivliste
(Einladung bzw. Nachversand, Erinnerung, eigene Abgabe, übermittelter Bescheid, Abschluss oder
Abbruch), Zeitpunkte aus Aggregat und eigenen Antworten und aus dem Verlauf allein die Einträge
220 und 390, zugeordnet über das Subjekt und nie über den Akteur. Der Portaldienst liest diese
Einträge erst nach der Autorisierung und nur bei beendetem Verfahren; ausgegeben werden Art,
Zeitpunkt und Folge, keine Kennungen, Namen oder DetailJson. Der Abbruchgrund erscheint nur mit
amtlicher Kennzeichnung (RAL-QM-HP-42), „Keine Aussage“ nur als Erklärung aus RAL-QM-HP-33.
Interne Verfahrensuploads, Versionsersatz und Downloads prüfen Hearings-Rechte, Fachobjekt,
Zustand und beim Schreiben den Stempel, bevor sie IDocumentContentPort aufrufen.
Referenten benötigen hierfür keine generischen CAF-Dokumentrechte. Bei einem Fehler nach
dem Upload darf die Kompensation über IDocumentFilingPort nur den gerade angelegten
Descriptor mit dessen Stempel und eigener Löschoperation entfernen. Allgemeine
Dokumentdienste behalten ihre eigenständigen Rechteprüfungen.
Rückmeldungen lesen und beantworten (RAL-QM-HP-36)
Wer Rückmeldungen lesen darf – RALQM.Hearings.Responses und .Read –, erreicht die
Rückmeldungsseite über den Prozessschritt „Rückmeldungen auswerten“ und den Verweis im Reiter
„Rücklauf“ und liest dort den Beteiligungsstand, alle Abgaben mit Text und Anlagen und die
Antworten auf Einwände. Schreiben bleibt bei eigenen Rechten: Antwort verfassen .Reply, intern
erfassen .RecordInternally, exportieren RALQM.Hearings.Export.
RAL-QM-HP-36 ändert keine
Rollenkomposition: Die Geschäftsführung liest und exportiert, verfasst und erfasst aber nicht; der
Referent hält alle vier Rechte; der Systemadministrator liest keine Stellungnahme;
RALQM.Hearings allein reicht nicht. Die Seite selbst verlangt neben dem Leserecht nur
RALQM.Hearings für die Rahmenlesung des Verfahrens; aus ihr stammen auch die Beteiligungen für
die Beschriftung und die Erfassungsauswahl, ein Teilnehmerrecht braucht die Seite nicht.
ABP verknüpft die [Authorize]-Attribute von Klasse und Methode mit UND.
HearingResponseAppService und HearingDialogAppService tragen deshalb an der Klasse das
schwächste Recht des Knotens (Responses) und an jeder Methode ihr eigenes. Bis RAL-QM-HP-36 stand
.Reply an der Klasse des Dialogdienstes; damit las die Antworten niemand, der nur lesen durfte.
Leser erfahren, dass eine Zustellung fehlgeschlagen ist – als Stand oder Hinweis, in Zeile und
Export. Adresse, Zahl der Versuche und Fehlergrund bleiben beim Zustellstatus hinter
RALQM.Hearings.Dispatch. Die Auswertung liest aus dem Postausgang je Zeile Art, Schlüssel,
Transportstatus und Erzeugungszeitpunkt und – nur um zu entscheiden – den Versuchszähler, den
gemeldeten Versuch und den Verweis auf die ersetzte Zeile (HearingMailFact). Ausgegeben wird
davon nichts: Der Vertrag der Übersicht hat kein Feld dafür. Adresse, Fehlercode und Meldegrund
liest die Auswertung gar nicht. Nachweise: HearingResponseReplyTests (Form der Rechte, Rollen), die Datei
HearingResponseEvaluationSqlServerTests.cs im Projekt Hearings.SqlServer (Teil der Klasse
HearingResponseSubmissionSqlServerTests; echter ABP-Proxy auf SQL Server: Geschäftsführung,
reines Leserecht, fünf Konten ohne Leserecht) und HearingResponseOverviewBoundaryTests (Vertrag).
Maschinenabruf der öffentlichen Anzeige (RAL-QM-HP-47, ADR-12)
Der Bestandsabruf für die Website ist der einzige eingehende Maschinenzugang. Er nutzt ein eigenes
JWT-Bearer-Schema HearingPublicationFeed neben dem interaktiven Cookie, nie als Standardschema:
die CAF-Sitzungsprüfung sieht deshalb keinen Bearer-Prinzipal, und die Policy
hearing-publication-feed nennt das Schema, sodass die Autorisierung den Aufruf ausschließlich mit
dem Token authentifiziert. Geprüft werden Aussteller und Signatur über die Realm-Metadaten,
Lebensdauer (eine Minute Toleranz), Audience und das azp gegen AllowedClientIds; die Identität
trägt das Schema als Typ, damit eine Browsersitzung mit zufällig gleichem azp nie zählt. Der Dienst
prüft dieselbe Policy noch einmal. Konfiguration Hearings:PublicationFeed (Enabled, Authority,
Audience, AllowedClientIds, RequireHttpsMetadata): ausgeschaltet hat das Schema keine
Signaturschlüssel und weist jedes Token ab; eingeschaltet ohne Aussteller, Audience oder Client
bricht der Start ab. Der Keycloak-Client (Service-Account, Client Credentials, Audience-Mapper) wird
im Kundenrealm angelegt, sobald der Websitebetreiber feststeht; der lokale Stack provisioniert ihn
nicht. Abruf und anonyme Übersicht laufen hinter der Aufrufbremse hearing-portal (je Adresse);
der Abruf schreibt keinen Audit-Eintrag je Poll, sondern eine strukturierte Logzeile.
Seit RAL-QM-HP-78 (ADR-20):
- Seiten: Der Abruf liefert Seiten von höchstens 500 Einträgen mit Fortsetzung (Keyset über
die öffentliche Kennung). IsComplete gilt nur für die letzte Seite eines vollständigen Abrufs.
- Quittung: Die Website quittiert unter derselben Policy mit
POST /api/gz/hearings/public/receipts. Das Portal speichert je Kennung nur den bestätigten
Änderungszeitpunkt und den Client, nichts über Personen. Je Quittung entsteht kein Audit-Eintrag.
Die Website quittiert mindestens alle 15 Minuten und gibt die Änderungszeit exakt zurück.
- Website-Client: reconcile-website-client.sh legt ihn an, wenn sein Secret gesetzt ist. Es
wird von reconcile-client.sh eingebunden und läuft damit auch im Deploy-Einstieg.
Konfiguration im Portal: Hearings:PublicationFeed mit Audience=ral-qualitymarks-publication-feed
und dem Client in AllowedClientIds.
- Störung: Der Worker HearingPublicationSyncWorker meldet einen überfälligen oder stummen
Abgleich nach Hearings:PublicationSync:StaleAfter (60 Minuten) als Störung PublicationSync
und löst sie mit dem nächsten gesunden Lauf auf.
Kontaktmeldungen lesen und entscheiden (RAL-QM-HP-41)
RAL-QM-HP-41 führt
kein Recht ein und ändert keine Rollenkomposition. Melden und Zurückziehen verlangen
RALQM.Hearings.Portal.Access und die Prüfkette des Portals; Institution, Akteur und Empfänger
stammen nie aus dem Aufruf. Intern liest Meldungen, wer Beteiligte liest
(RALQM.Hearings.Participants), also auch die Geschäftsführung. Jede Entscheidung verlangt
Participants.Manage. Eine Übernahme, die einen Stammdatenkontakt anlegt, verlangt zusätzlich
RALQM.Institutions und .Update: Hearings prüft beide vor dem ersten Speicherschritt, der
Institutions-Vertrag prüft sie beim Aufruf erneut. „Nur dieses Verfahren“ und Verwerfen brauchen
kein Institutionsrecht. Ohne Leserecht auf Institutionen zeigt die Entscheidungsgrundlage keinen
Treffer gleicher E-Mail und bietet die Stammdaten nicht an. HearingContactReportAppService trägt
an der Klasse RALQM.Hearings und an jeder Methode ihr eigenes Recht (UND-Verknüpfung, wie oben).
Datensparsamkeit: Der Portalvertrag hat kein Feld für die interne Notiz, das Ziel oder die
stattdessen übernommene Person; der Hinweis vor Bescheid, Abschluss und Abbruch trägt nur
Institutionsnamen. Entität, Personen-DTOs sowie Personen- und Notizfelder der Eingaben sind
[DisableAuditing]; der Portaldienst ist es als Ganzes. Der Verlauf nennt Akteur, Zeitpunkt,
Beteiligung, Ziel und Kontaktbezüge, nie Angaben der Person. Nachweise:
HearingContactReportContractTests (Vertragsform), HearingContactReportAppServiceTests und
HearingContactReportPortalTests (Rechte und Abweisungen), HearingContactReportSqlServerTests
(echter ABP-Proxy auf SQL Server je Rolle; mit eingeschaltetem Audit steht keine Angabe der Person
oder der Notiz in den Audit-Tabellen).
Sitzung und Rücksprung (RAL-QM-HP-52, Stufe A)
Der freigegebene Hoststandard ist 15 Minuten Inaktivität bei maximal acht Stunden
Gesamtdauer. Authentication:Session:IdleTimeout und CookieLifetime werden beim
Start validiert; UseSlidingExpiration bleibt false. Die prozesslokale CAF-Sitzung
bindet Tabs derselben Anmeldung, serverseitige UTC-Zeit und das Provider-Refresh-Token.
Ein Hostneustart verlangt neue Credentials. Hintergrundverkehr verlängert das
Inaktivitätsfenster nicht. Die Shell meldet echte Bedienereignisse höchstens einmal
pro Sekunde mit Antiforgery-Nachweis; die Fünf-Minuten-Prüfung von ABP-Status und
Security Stamp bleibt zusätzlich erhalten. HTTP-Middleware und CircuitHandler
verweigern abgelaufene oder widerrufene Sitzungen vor Weitergabe an Fachcode.
Nach einem bestätigten Session-401 wird der Browserübergang zur Anmeldung terminal. Bevor Ausblenden oder ein gleichzeitiger Reconnect den Fokus verschiebt, schützt der Host genau den nächsten Blur des zu diesem Zeitpunkt fokussierten Controls vor einem späten Circuit-Callback. Das ist der enge Produktbehelf UP-67, kein Fehlerfilter: gewöhnliche Blur-Ereignisse, temporäre Verbindungsverluste und sonstige JavaScript-Fehler bleiben unverändert sichtbar. Der kontrollierte Browserfall verwendet reale Kontosperre, Session-401 und den eigenen echten Blazor-WebSocket.
Shell und Account-Filter erlauben nur lokale Rücksprungziele einschließlich Query.
Kodierte Separatoren und Account-/Callback-Schleifen führen nach /. Der Zielzugriff
wird erneut autorisiert. Abmeldung widerruft die lokale Sitzung vor dem OIDC-Aufruf;
ein serverseitiger Providerfehler zeigt die neutrale Abmeldeseite mit HTTP 503, deren
einzige Handlung die erneute Anmeldung ist (RAL-QM-HP-91 E1): Wer sich beim Anbieter
abmelden will, meldet sich erneut an und danach ab, sobald der Anbieter erreichbar ist.
Eine eigene Wiederholung der Providerabmeldung gibt es nicht; ist die Providerkonfiguration
im Hostprozess zwischengespeichert, leitet der Host auch bei ausgefallenem Anbieter dorthin
weiter und der Browser zeigt seinen Netzwerkfehler.
Geschützte Antworten verwenden no-store; die Shell lädt Seiten aus dem Back/Forward
Cache neu. Ein neuer OIDC-Login verlangt ausdrücklich Credentials statt stiller SSO.
Jede Abmeldung des Anwendungs-Cookies löscht über ABP Account Pro zusätzlich die Zeile der
ABP-Sitzung (AbpSessions). Die Abmeldeseite stellt das DELETE nur in ihre Unit of Work, die
erst nach dem Handler geschrieben wird. Melden zwei Anfragen derselben Sitzung gleichzeitig ab,
etwa die Abmeldeseite und eine Anfrage eines zweiten Tabs, die CAFSessionMiddleware nach dem
CAF-Widerruf abweist, oder zwei Abmeldungen, dann entfernt eine von beiden die Zeile zuerst.
Eine bereits entfernte Zeile gilt als erledigter Entzug (RAL-QM-HP-92). Das sichert CAF
Authentication zu (CAFRevokedSessionWriteInterceptor, für jeden DbContext über
AbpDbContextOptions.PreConfigure): Unterdrückt wird genau die EF-Concurrency-Meldung, deren
Einträge ausschließlich gelöschte oder geänderte IdentitySessions sind; geändert heißt hier das
LastAccessed-UPDATE, das ABPs Sitzungsprüfung im selben Request vormerkt. IdentitySession hat
keinen Concurrency-Token, „keine Zeile betroffen“ heißt dort also „schon entfernt“, und das
Unterdrücken schreibt nichts. Jeder andere Konflikt bleibt ein Fehler.
Keycloak besitzt die neutralen DE/EN-Anmeldefehler und LOGIN_ERROR-Ereignisse.
Die freigegebene Aufbewahrung beträgt 14 Tage; der Reconciler verwendet
KEYCLOAK_LOGIN_EVENTS_EXPIRATION_SECONDS (Standard 1209600, positive ganze Sekunden).
Zugriff auf Ereignisgründe bleibt beim Keycloak-Betrieb, ohne neue App-Auditfläche.
Seit RAL-QM-HP-18 widerrufen Kontosperre, Kennungswechsel und Papierkorb die CAF-Sitzungen des
betroffenen Kontos sofort (CAFSessionStore.RevokeSubject, Host-Adapter
CAFSessionAccountRevoker), zusätzlich zur Keycloak-Sperre und dem Logout aller
Provider-Sitzungen; die nächste Aktion des Kontos landet auf der Anmeldung. Der Schlüssel des
Widerrufs ist der NameIdentifier des Anwendungs-Cookies, also die lokale Benutzer-Id (ABP
Claims-Factory) — nicht das Keycloak-Subject, das nur bei den Seed-Konten mit der Id
übereinstimmt.
Details und Abnahmestand: SPEC-RAL-QM-HP-52.
Organisationsanmeldung (RAL-QM-HP-63, ADR-15)
Beide Anmeldewege enden im selben Keycloak-Benutzer. Der Host prüft vor dem externen
Anmeldeticket über IPortalLoginAccountReader das validierte sub: genau ein aktives,
nicht gelöschtes Hostkonto und genau eine lokale Produktrolle. Authorization bezieht
Papierkorb- und Tenantzeilen in die Eindeutigkeitsprüfung ein, ohne sie zuzulassen oder
zu verändern. Institutionskonten dürfen nur den Passwortweg verwenden. Die bestehende
technische Bootstrap-Ausnahme (admin ohne Produktrolle) bleibt auf diesen Weg begrenzt;
sie vergibt keine Fachgrants. Ein abgewiesener Callback endet vor Kontoverknüpfung,
Passwortabschluss und Erfolgsaudit auf derselben anonymen, lokalisierten Fehlerseite
/fehler/403, ohne Kontoanlage oder E-Mail-Abgleich. Die CAF-Sitzungsprüfung bleibt bestehen.
Die Zuordnung Organisationskonto → Konto legt
nur der Systemadministrator an (IStaffAccountAppService.SetOrganisationAccountAsync, Recht
der internen Kontenwelt, Verlaufseintrag 160); Institutionskonten erhalten keine. Schreibvorgänge
nehmen erst die Anwendungssperre RALQM.OrganisationLink, dann die Kontoreservierung, prüfen den
Halter vor dem Entfernen des bisherigen Links, stellen ihn bei Fehlern wieder her und erhöhen die
Revision des Kontos (nicht den Security Stamp). Ein Kennungswechsel reserviert das Konto ebenfalls
und entfernt die Zuordnung vor dem Logout. Den Ausfallweg steuern
OrganisationLoginOptions (Prüfadresse, 60 s, 3/3) und die globale Einstellung
RALQM.OrganisationLogin.ForceFallback hinter RALQM.OrganisationLogin.Manage; jede Änderung
und jede validierte Anmeldung (Weg, Benutzer, Subject) steht im ABP-Sicherheitsprotokoll.
Providerablehnungen sieht Keycloak (LOGIN_ERROR, IDENTITY_PROVIDER_LOGIN_ERROR);
eine lokal unzulässige Zuordnung erzeugt keinen erfolgreichen Portal-Anmeldeeintrag.
Getrennte Lese- und Pflegerechte am Beispiel der Wertelisten
Der Slice ValueLists definiert drei Rechte, wo zwei naheliegend gewesen wären:
| Recht | Bedeutung | Vergeben an |
|---|---|---|
RALQM.ValueLists |
die Pflegeseite /administration/wertelisten sehen |
nur RALQMAdministrator |
RALQM.ValueLists.Manage |
anlegen, umbenennen, sortieren, deaktivieren, Standardfristen setzen | nur RALQMAdministrator |
RALQM.ValueLists.Read |
Auswahloptionen für Dropdowns auflösen | alle drei internen Rollen |
Das dritte Recht existiert, weil Referent und Geschäftsführung ihre Auswahlfelder füllen müssen,
ohne die Pflegeseite betreten zu dürfen. Es lässt sich nicht einsparen: ABP verbindet in
MethodInvocationAuthorizationService die [Authorize]-Angaben der Klasse und der Methode
mit logischem UND und leitet zur Prüfzeit keine Eltern-Kind-Implikation aus der
Permission-Definition ab — AddChild ist eine Definitions- und Oberflächenangelegenheit, kein
Prüfmechanismus. Wer Manage besitzt, besitzt deshalb nicht automatisch Read; wer Read
besitzt, kommt nicht an die Pflegeseite. Aus demselben Grund trägt der Pflegedienst auf
Klassenebene nur das schwächste Recht (RALQM.ValueLists) und jede schreibende Methode
zusätzlich Manage — ein strengeres Klassenattribut würde die lesende Methode unerreichbar machen,
statt sie zu schützen. Ein hearings- oder institutionseigenes Leserecht schied aus: Es hätte eine
Referenz von ValueLists.Contracts auf jene Contracts verlangt und damit einen Projektzyklus.
Read ist ein Geschwisterrecht, kein Kind — und das ist eine Vergabe-Entscheidung. Zur
Prüfzeit spielt die Definitionshierarchie keine Rolle (siehe oben), zur Vergabezeit aber sehr
wohl: Die Rollenoberfläche (RolePermissionsPage.ApplyGrant, aus der ABP-eigenen Permission-UI
übernommen) setzt beim Anhaken jedes Elternrecht und beim Abhaken jedes Kindrecht
innerhalb derselben Gruppe. Als Kind von RALQM.ValueLists hätte das Anhaken des Leserechts für
Referent und Geschäftsführung also zwangsläufig auch die Pflegeseiten-Permission vergeben — genau
das, was die Route und der Menüeintrag prüfen — und das Abhaken von RALQM.ValueLists hätte das
Leserecht mitentzogen. Der Zielzustand wäre über die Oberfläche weder herstellbar noch reparabel
gewesen, sondern nur durch den Seeder. Manage bleibt bewusst Kind von RALQM.ValueLists: Wer den
Katalog bearbeiten darf, muss die Seite auch öffnen können. Durchgesetzt wird beides von
ValueListsPermissionContractTests (Definitionsform) und
RolePermissionUiTests::Granting_only_the_value_list_lookup_right_leaves_the_maintenance_permission_alone
sowie …::Withdrawing_the_maintenance_permission_keeps_the_value_list_lookup_right — beide bauen
die Gruppe aus dem echten Provider, nicht aus einer abgeschriebenen Form.
Institutionspflege durch den Referenten
Seit RAL-QM-HP-10 pflegt der Referent die Institutionsstammdaten selbst; zuvor hielt die Rolle nur Lesen und Export.
| Recht | Bedeutung | Vergeben an |
|---|---|---|
RALQM.Institutions |
Liste und Bearbeitungsmaske lesen, Dublettensuche (Namensabgleich), Nennung laufender Verfahren je Kontakt | alle drei internen Rollen |
RALQM.Institutions.Create |
anlegen, mit Dublettenwarnung; prüft auch der CSV-Import | RALQMAdministrator, RALQMCaseOfficer |
RALQM.Institutions.Update |
ändern, umbenennen mit Dublettenwarnung, deaktivieren (bei laufenden Verfahren nur mit Bestätigungskennzeichen im Aufruf), reaktivieren; Kontakte anlegen und ändern, Standardansprechpartner festlegen, Kontakte deaktivieren (den Standard nie), Vertretung zuweisen, Pflichtpartner-Kennzeichen setzen (nur mit aktivem Standard) und entfernen | RALQMAdministrator, RALQMCaseOfficer |
RALQM.Institutions.Export |
Institutions- und Kontaktliste exportieren | RALQMAdministrator, RALQMCaseOfficer |
RALQM.Institutions.Delete |
löschen, geschützt über den Nutzungsport | nur RALQMAdministrator |
Institutionen werden deaktiviert, nicht gelöscht; Delete bleibt deshalb beim Administrator.
Create schaltet zugleich den CSV-Import frei, weil der Import dasselbe Recht prüft — eine
hingenommene Nebenwirkung (Spec A5), kein eigenes Import-Recht. Durchgesetzt von
PermissionOwnershipTests::Case_officer_maintains_institutions_without_deleting_them (Komposition
aller drei Rollen) und
InstitutionAuthorizationPipelineTests::Case_officer_composition_creates_and_updates_through_the_real_abp_proxy_but_never_deletes
(realer ABP-Proxy gegen SQL Server).
Die Kontaktregeln aus RAL-QM-HP-9 laufen
unter demselben Recht Update und sitzen im Aggregat Institution: höchstens ein
Standardansprechpartner je Institution, immer aktiv, der erste aktive Kontakt wird es selbsttätig,
ein Wechsel wird vor den übrigen Kontaktänderungen desselben Aufrufs angewendet und als zwei
Speicherschritte in einer Transaktion gespeichert; der Standard kann weder deaktiviert noch
entfernt werden; eine Vertretung ist ein anderer aktiver Kontakt derselben Institution mit
Zeitraum; das Pflichtpartner-Kennzeichen wird zuletzt gesetzt, damit sein Guard den Kontaktstand
desselben Aufrufs sieht, und der Guard greift nur beim Setzen: Ein bestehendes Kennzeichen bleibt
auch ohne aktiven Standard bestehen (RAL-QM-HP-9 E13). Die Deaktivierung eines Empfängers laufender
Verfahren (RAL-QM-HP-9 AC-5, zweiter Guard) verlangt ein Bestätigungskennzeichen je Kontaktzeile
(UpdateInstitutionContactDto.ConfirmDeactivation). Der Anwendungsdienst fragt bei jedem Speichern
erneut, und zwar zuletzt: nach allen fachlichen Prüfungen des Aufrufs und vor dem ersten
Speicherschritt (RAL-QM-HP-9 E14). Er fragt über IInstitutionContactUsageProvider die laufenden
Verfahren aller Kontakte ab, die der Aufruf ohne Kennzeichen deaktiviert, und weist mit
RALQM.Institutions:ContactDeactivationRequiresConfirmation ab. Die Abweisung nennt alle
unbestätigten Empfänger mit ihren Verfahren und die Zahl der verschiedenen Verfahren als
Exception-Daten; nichts wird gespeichert. Weil jede fachliche Abweisung vorher kommt, etwa der
Standard-Guard oder die Vertretungsregeln, bestätigt der Aufrufer nur ein Speichern, das sonst
gelingt. Die Bestätigung der Institution (RAL-QM-HP-10 AC-10) bleibt vor der ersten Mutation:
Deaktiviert ein Speichern Institution und Empfänger-Kontakt zugleich, kommen beide Fragen
nacheinander, die der Institution zuerst. Die Oberfläche fragt noch nicht nach; der
Bestätigungsdialog folgt mit der Institutionsmaske (RAL-QM-HP-9, Schritt Institutions-Oberfläche).
Lese- und Pflegerecht der Institutionsgruppen (RAL-QM-HP-3)
Der Slice Institutions definiert für die Institutionsgruppen (SPEC-RAL-QM-HP-3) zwei eigene Rechte:
| Recht | Bedeutung | Vergeben an |
|---|---|---|
RALQM.InstitutionGroups |
Gruppenübersicht, Gruppenmaske und Mitgliederliste lesen | alle drei internen Rollen |
RALQM.InstitutionGroups.Manage |
Gruppen anlegen, umbenennen, beschreiben und auflösen; Institutionen zuordnen und entfernen | RALQMAdministrator, RALQMCaseOfficer |
Muster sind die Institutionsrechte, nicht die Wertelisten: Ein drittes Recht braucht es nicht, weil
keine Rolle Gruppen lesen muss, ohne die Übersicht zu sehen. Referent und Systemadministrator
halten beide Rechte ausdrücklich, weil ABP zur Prüfzeit aus Manage kein Leserecht ableitet (siehe
Wertelisten). Die Rolle Institution
erhält keines. In der Definition ist RALQM.InstitutionGroups ein eigener Wurzelknoten der Gruppe
RALQM, kein Kind von RALQM.Institutions; als Kind würde das Anhaken in der Rollenoberfläche auch
das Institutionsrecht vergeben. Manage ist Kind des Leserechts: Wer Gruppen pflegt, muss sie
öffnen können. Durchgesetzt von
PermissionOwnershipTests::Institution_groups_are_read_by_every_internal_role_and_maintained_by_case_officer_and_administrator
(Komposition aller vier Rollen),
PermissionOwnershipTests::Permission_definitions_have_the_expected_parent_child_relationships
(Definitionsform) und
InstitutionGroupAuthorizationPipelineTests::The_manage_right_maintains_groups_while_the_read_right_alone_only_reads
(realer ABP-Proxy gegen SQL Server: Lesen erlaubt, jede Pflegeoperation abgewiesen, Daten unverändert).
Der Gruppendienst trägt das Leserecht auf der Klasse und Manage an jeder Schreiboperation — dieselbe
Form wie bei den Wertelisten, weil ABP Klassen- und Methodenattribut mit logischem UND verbindet:
Ein strengeres Klassenattribut würde das Lesen unerreichbar machen. Fachfehler der Gruppen tragen den
eigenen Namensraum RALQM.InstitutionGroups, der in den Institutions-Contracts auf dieselbe
Ressource abgebildet wird.
Kontoprovisionierung
Zwei getrennte, kontrollierte Wege binden Menschen an Keycloak-Konten — beide über denselben schmalen, fail-closed Provisionierungsport, nie über E-Mail-Gleichheit:
- Institutionskontakte: RAL legt die dedizierten Institutionskonten an — ausgelöst aus der
institutionsübergreifenden Kontaktsuche, keine Selbstregistrierung; je Institution mehrere
Benutzerkonten (je Kontakt eines), korreliert über
sub. Ein vorhandenes Konto erhält eine erneute Einladung statt eines Dublettenkontos, Mehrdeutigkeit scheitert geschlossen (ExternalAccountProvisioningErrorCodes). - Mitarbeitendenkonten: ausschließlich über
/administration/mitarbeitendenkonten, mit Name, E-Mail und genau einer internen Produktrolle; Rollenwechsel, Aktivieren/Sperren, Kennungswechsel, Wiedereinladung, Papierkorb und Wiederherstellen sind optimistisch concurrency-geschützte, auditierte Writes mit Verlaufseintrag (StaffAccountErrorCodes); Sperre und Kennungswechsel wirken sofort auf Keycloak und die offenen Sitzungen. Institutionskonten tragen die Rolle Institution und eine Bindung an Institution und Ansprechpartner; Referent und Systemadministrator sehen und pflegen sie in derselben Übersicht, interne Konten nur der Systemadministrator. Die ABP-Benutzerseite ist kein unterstützter GZ-Kontenpfad. Die Einladung (Keycloak Execute-Actions) gilt 7 Tage (actionTokenGeneratedByAdminLifespan); ein älterer Einladungsverweis lässt sich nicht widerrufen, nur durch Ablauf entwerten.
Selbstbedienung am eigenen Konto (RAL-QM-HP-13)
Der Kontoinhaber pflegt sein Konto über IOwnAccountAppService — einen Dienst, der
ausschließlich am Konto des Aufrufers arbeitet und keine Konto-Id entgegennimmt; er ist
lediglich durch Angemeldetsein autorisiert, weil auch eine Rolle ohne jedes Kontenrecht ihre
eigenen Angaben pflegt. Die Oberfläche dazu (OwnAccountPanel) liegt im geteilten UI-Baustein
src/UI/Blazor/Account, weil die interne Shell (/konto) und das Institutionsportal
(/portal/konto) dieselbe Komponente einbetten und ein Feature-UI kein fremdes Feature-UI
referenzieren darf.
Passwörter verlassen Keycloak nie. Weder Erstvergabe noch Änderung noch Zurücksetzen laufen
über das Portal: die Anwendung startet die Keycloak-Aktion UPDATE_PASSWORD über einen
Host-Endpunkt mit max_age=0 und prompt=login, damit auch eine gerade genutzte Provider-Sitzung das aktuelle
Passwort erneut verlangt. Keycloak authentifiziert dabei erneut und
meldet das Ergebnis im Rücksprung. Erst dann erneuert die Anwendung den Security Stamp, beendet
alle übrigen Sitzungen des Kontos — lokal über CAFSessionStore.RevokeSubject mit Ausnahme der
aktuellen Sitzung, beim Provider über die Sitzungsliste — und bestätigt per E-Mail. Ein
abgebrochener oder vom Provider als fehlgeschlagen gemeldeter Rücksprung ändert nichts. Ein
Architekturtest hält fest, dass Vertrag, Port und Oberfläche kein Passwortfeld, keine
Passworteingabe und keinen Reset-Endpunkt tragen.
Der Passwortabschluss reserviert das kontogebundene Vorgangstoken exklusiv. Zuerst
beendet er die übrigen Provider-Sitzungen; Security Stamp und Kontoverlauf werden danach
in einer eigenen transaktionalen ABP-Unit-of-Work festgeschrieben. Erst der erfolgreiche
Commit verbraucht das Token und erlaubt CAF-Sitzungswiderruf und Bestätigungsmail.
Provider- oder Persistenzfehler geben die Reservierung für einen Retry innerhalb der
ursprünglichen Frist frei. Die Mail bleibt nach Commit best effort, auch bei Abbruch.
Der Host erneuert bei Erfolg das Cookie und leitet permissionbasiert nach /konto oder
/portal/konto, jeweils mit Ergebnisparameter und erhaltenem PathBase.
Den Aktionsstatus übernimmt der Host aus TokenValidatedContext.ProtocolMessage,
unabhängig von GET oder form_post. Der vorhandene CAF-Validator läuft zuerst;
ein abgewiesenes Ergebnis wird nicht übernommen. Bis zum bestehenden Ticket-Admission-Guard
bleibt die bekannte Statuskategorie ausschließlich im laufenden HttpContext.Items,
an denselben Vorgang gebunden. Erst danach wird sie am Einmalvorgang gespeichert.
Fehlende/unbekannte Werte und mehrfache Statusparameter bleiben geschlossen. Weil die native
OIDC-Nachricht bei Mehrfachwerten nur den ersten behält, prüft der Host zusätzlich die Anzahl
in der bereits geparsten Query/Form (IFormFeature.Form), ohne die Form erneut zu lesen.
Der server-only Start am bestehenden IOwnAccountAppService bindet den Vorgang an
RequireMineAsync und dessen record.Subject; das Subject wird nicht als DTO oder aus
einem optionalen Anwendungs-Cookieclaim transportiert. Das validierte Provider-Subject
muss beim Attach unter derselben Store-Sperre exakt zum gespeicherten Subject passen.
Der spätere Passwort- und Zweitfaktorabschluss prüft zusätzlich die aktuelle Kontozuordnung,
bevor Provideraufrufe, Security Stamp, Verlauf, Sitzungswiderruf oder Mail folgen. Eine
zwischenzeitliche Umverknüpfung sowie fehlende/fremde Subjects bleiben ohne diese Wirkungen.
Der reale Gegenbeleg hp13callback20261016a auf 41491906 war POST/Form=success,
Query=MISSING und Portal=failed; die transportunabhängige Korrektur benötigt ihren neuen Lauf.
Das geteilte Kontoformular bietet nach einem Lesefehler einen erneuten Ladeversuch. Bei veraltetem Stempel bleiben Eingaben erhalten, bis der Inhaber ausdrücklich „Aktuellen Stand laden und Eingaben verwerfen“ wählt. Erst diese Aktion ersetzt Formular und Stempel gemeinsam. Speicherbestätigung und Validierungsfehler erhalten nach dem interaktiven Render den Fokus; jedes Profilfeld hat Label und eigene Validierungsmeldung.
Zweiter Faktor (RAL-QM-HP-11, ADR-19)
Der zweite Faktor ist ein Keycloak-TOTP. Das Konto-Panel zeigt nur, ob einer eingerichtet ist,
und startet über die Host-Endpunkte /konto/zweiter-faktor-einrichten und
/konto/zweiter-faktor-entfernen die Keycloak-Aktionen CONFIGURE_TOTP bzw.
delete_credential:{id} (mit max_age=0). Geheimnis, QR-Code und Codes bleiben bei Keycloak; der
Admin-Port liest vom Credential nur Id und Typ. Der Abschluss entscheidet am Credential-Bestand,
beendet dann die übrigen Sitzungen, erneuert den Stamp und schreibt den Kontoverlauf. Ein
Systemadministrator setzt den Faktor eines anderen Kontos über einen persistenten, fortsetzbaren
Auftrag zurück; der Kontoinhaber erhält eine Benachrichtigung ohne Zugangsdaten. Die Kontenübersicht
zeigt den Faktor (eingerichtet, nicht eingerichtet, unbekannt) und offene Rücksetzaufträge.
Nach bestätigter Entfernung des gebundenen Faktors werden dessen Credential-IDs im selben persistierten Auftragsschritt geleert. Bis zum erfolgreichen Providerabschluss bleiben sie für Wiederanlauf und Schutz eines später neu eingerichteten Faktors gebunden. Operation-ID, Schritt, Akteur und Zeitpunkte bleiben für Fortsetzung und Replay-Schutz erhalten; bereits gespeicherte Altaufträge werden dadurch nicht rückwirkend bereinigt. Die noch zu bestätigenden Aufbewahrungsregeln für Aufträge, Kontoverlauf und Betriebsprotokolle stehen in der HP11-Spec.
Die Kommunikationssprache folgt dem einzigen HP101-Modell: interne Konten tragen
RALQM.Profile.CommunicationLanguage in ihren ExtraProperties, Institutionskonten lesen
über den Institutions-Contract ausschließlich ihren gebundenen Kontakt. Die getrennte
Eigenkonto-Sprachaktion überträgt die Locale vor dem Speichern zum Provider; der Kontoverlauf
hält nach ADR-22/E24 alte und neue Sprache fest. Es gibt dafür kein zusätzliches ABP-U-Setting.
Die Rücksetzmail liest bei Auftragsanlage die aktive Empfängerpräferenz; fehlend oder inaktiv
bedeutet hier ausdrücklich de-DE, unabhängig von HP101s veränderlichem globalen Standard.
NoticeCultureName in den ExtraProperties des Auftrags hält diese Kultur fest. Retry und
Altauftrag fragen keine aktuelle Präferenz ab; ein fehlender Alt-Snapshot bedeutet Deutsch.
Der Snapshot bestimmt die Lokalisierung von Betreff/Text und die Darstellung des ursprünglichen
UTC-Rücksetzzeitpunkts über HP101s HearingMessageInstants. Empfängeradresse und Anzeigename
werden weiter beim Versand gelesen, die vollständige Mail wird nicht eingefroren. Dies ist die
begrenzte HP11-Sonderregel aus ADR-19; die übrigen Kommunikationswege aus ADR-22 bleiben erhalten.
Angeforderte Authorize-Parameter reicht CAF Authentication nur präfixgebunden durch
(CAFAuthorizeParameters); übrige Authentication-Properties sind interner Zustand und erreichen
den Anmeldedienst nie.
Die persönlichen Angaben (Anrede, Titel, Funktionsbezeichnung, Vor- und Nachname, Telefon, Mobil) liegen führend am ABP-Benutzer — Name und Telefon in dessen eigenen Spalten, der Rest als ExtraProperties; eine zweite Tabelle entsteht nicht. Nach Keycloak gespiegelt wird ausschließlich der Name, damit dessen eigene Mails korrekt adressieren. Anmeldename und Anmeldekennung sind nicht selbstbedienbar (RAL-QM-HP-18 AC-6), die Stammdaten der Institution bleiben unberührt.
Die Fehlversuchssperre ist von der Deaktivierung getrennt: sie entsteht in Keycloaks
Brute-Force-Erkennung, ändert den Aktivstatus nicht und wird in der Kontenübersicht zusätzlich zum
Aktivstatus angezeigt. Aufheben darf sie allein der Systemadministrator über das eigene Recht
RALQM.Accounts.Unlock; der Sperrzustand wird je Seite beim Provider gelesen und fällt bei
dessen Ausfall auf „unbekannt“ zurück, ohne die Übersicht zu blockieren. Einen Filter auf den
Sperrzustand gibt es bewusst nicht: Keycloak kennt keine Liste gesperrter Konten, der Zustand
träfe erst nach der Seitenabfrage ein und ein Filter würde Gesamtzahl und Seitenfolge verfälschen.
Details zu Dokument- und Portalzugriffswegen (intern, Institutionskonto, Direkt-Share; im Host gesperrter CAF-Direktshare) stehen in Laufzeitsicht; Multi-Tenancy ist deaktiviert, Keycloak-Gruppen ersetzen keine GZ-Rollen oder ABP-Permissions.
Aktivierungszustimmung als Zugangsbedingung (RAL-QM-HP-39)
Ein Institutionskonto erhält Fachzugang erst mit einem Aktivierungsnachweis. Die Bedingung sitzt in
derselben einzigen Prüfung InstitutionAccountAccessReader.GetCurrentAsync, durch die jeder
Portalaufruf läuft; fehlt der Nachweis, antwortet jeder Portaldienst mit PortalAccessMissing.
GetActivationCandidateAsync liefert dasselbe Konto ohne diese eine Bedingung und dient nur dem
Zustimmungsschritt (IConsentActivationAppService), der dadurch selbst keine Kontoregeln
nachbaut. Die Weiterleitung von Portalseiten auf /portal/zustimmung ist Bedienhilfe und prüft
nur den Nachweis in der Datenbank; die Sicherheitsgrenze bleibt die Zugangsprüfung. Sie liest in
einer eigenen, nicht transaktionalen Unit of Work: ABPs Anfrage-Unit-of-Work (UseUnitOfWork)
überspringt Razor-Komponenten-Endpunkte, und der Nachweisleser fragt in der Unit of Work seines
Aufrufers. Ohne sie lief die Abfrage auf einem bereits verworfenen DbContext, jede Prüfung
scheiterte als technischer Fehler, und kein neues Konto erreichte die Zustimmungsseite (Korrektur
02.10.2026). Die Regel dahinter: Eine Abfrage aus GetQueryableAsync muss innerhalb der Unit of
Work ausgeführt werden, die sie erzeugt hat. Ohne umgebende Unit of Work öffnet und schließt ABP
für den Aufruf GetQueryableAsync allein eine, und die spätere Ausführung über AsyncExecuter
trifft deren verworfenen DbContext. Der Nachweisleser (ConsentProofStore) baut solche Abfragen;
wer ihn außerhalb einer Unit of Work aufruft, öffnet sie deshalb selbst. Pflege der
Fassungen ist ein Verwaltungsrecht (RALQM.Consents.Documents, .Publish) allein des
Systemadministrators; Nachweise sind nur in der Rückmeldungsansicht unter
Hearings.Responses.Read sichtbar und haben keinen eigenen Endpunkt
(ADR-11).
2. Persistenz und EF Core
RAL-QM-HP-72 serialisiert Kontoverwaltung und neue Zuständigkeiten über die Authorization-eigene
Kontenzeile. Reguläre Deaktivierung, interner Rollenwechsel und Papierkorb reservieren
sie mit aktuellem Stempel vor der Hearings-Nutzungsprüfung und vor jedem Provideraufruf.
Anlage und Übergabe eines Verfahrens reservieren das Zielkonto über den prozesslokalen
IStaffResponsibilityReservation in derselben Transaktion. Die anschließende frische
Eignungsprüfung liest nur dieses Konto; sie hält keine anderen Kontosperren.
Bei Anlage bleibt der berechtigte aktive interne Ersteller zuständig; das bestehende
Anlegerecht wird nicht auf die Referentenrolle verengt. Übergaben verlangen weiterhin
einen aktiven Referenten als Ziel. Die Klärungsliste erkennt aktive interne Ersteller
einschließlich Geschäftsführung und technischem Bootstrap-Administrator als gültige
Zuständige; fehlende, inaktive oder nicht eindeutig interne Konten bleiben Klärungsfälle.
Hearings beantwortet IHearingResponsibilityGuard für alle nicht abgeschlossenen oder
abgebrochenen Verfahren. Explizites EmergencyDeactivateAsync darf offene Zuständigkeiten
belassen, erzeugt EmergencyDeactivated und widerruft Provider-/lokale Sitzungen.
Die separate GF-Klärungsliste /anhoerungen/zustaendigkeit-klaeren verlangt Hearings.Default
und Hearings.Approve; persönliche Freigabeaufgaben bleiben auf PendingApproval beschränkt.
Verfahrensupload und Versionsersatz (RAL-QM-HP-75) bewahren die ABP-Auditaktion mit Akteur,
Operation, IDs, Typ/Größe, Stempel und Fachmerkmalen. Dateiname, Stream, Anzeigename und
Beschreibung bleiben aus den Parametern ausgeschlossen. Die ausgeschlossenen Pflichtwerte
tragen [Required] für die ABP-Proxy-Validierung, ohne C# required: diese Kombination
mit JsonIgnore würde die Vorbereitung des Audit-Serialisierers abbrechen. Der echte
ABP-/SQL-Pfad prüft die gespeicherten erlaubten Metadaten. HearingDocument bleibt außerhalb
der Entity-History-Allowlist.
RAL-QM-HP-70, RAL-QM-HP-71 ergänzen zusätzliche Hearings-Empfängerstände und Erinnerungsberichte mit
unveränderlicher Auswahl und festem internem Empfänger. ReminderRunId korreliert Hauptaufträge,
weitere Empfänger, Vertretungskopien und korrigierte Folgeaufträge. Der Bericht liest aktuelle
Transportzustände; er ist unter Hearings.Default geschützt. Seine kurze E-Mail trägt nur den
geschützten Link. Concurrency schützt Benachrichtigungsclaims. Ein Prozessabbruch nach SMTP-Annahme
vor Speicherung kann eine erneute Benachrichtigung auslösen (At-least-once).
- SQL Server ist der einzige relationale Provider; es gibt genau einen
HearingPortalDbContextund einen Migration Host im ProjektHearingPortal(Host). - Jedes Modul definiert seine Entities und eine eigene
Configure{Feature}()-ModelBuilder- Erweiterung in seiner Runtime; der Host ruft diese Erweiterungen nur auf und besitzt keine fachliche Konfiguration. - Migrationen werden ausschließlich im Host erzeugt und ausgeführt
(
HearingPortal/Migrations), gegen eine echte, disposable SQL-Server-Datenbank getestet und mitdotnet ef migrations has-pending-model-changesals Pending-Model-frei nachgewiesen. - Beziehungen innerhalb eines Moduls verwenden echte Foreign Keys und Indizes. Über Modulgrenzen
werden ausschließlich IDs gespeichert (
InstitutionId,DocumentId, seit RAL-QM-HP-4 auchMarkTypeId/ProcedureTypeIdaufRALQMHearings,CountryIdaufRALQMInstitutionsundFunctionIdaufRALQMInstitutionContacts— die übrigen neuen Spalten dieser Tabelle aus RAL-QM-HP-9,Phone,IsDefault,DeputyContactId,DeputyFromUtcundDeputyUntilUtc, sind moduleigen, undDeputyContactIdist deshalb ein echter Fremdschlüssel, siehe unten —, seit RAL-QM-HP-16HearingIdundHearingDocumentIdaufRALQMFilingHearingUsages) — keine Cross-Module-Navigation, kein Cross-Module-Foreign-Key. Die Wertelisten sind dafür kein Sonderfall, sondern der jüngste Anwendungsfall derselben Regel: Ein Fremdschlüssel aufRALQMProcedureTypeswäre bequem und genau die Kopplung, die die Modulgrenze verhindert. Ob eine so gespeicherte ID gültig ist, prüft der schreibende Anwendungsdienst über den Vertrag des besitzenden Slices, bevor er sie übernimmt: Hearings bestätigt Existenz und Aktivität einer Institution überIInstitutionAppServicebeim Anlegen eines Verfahrens (seit RAL-QM-HP-10, AC-9), beim Wechsel des Antragstellers, beim Hinzufügen von Teilnehmern und Nachbeteiligten; der Pflichtpartner-Leser liest nur aktive Institutionen. DieDocumentIdbezieht Hearings im selben Arbeitsschritt vom Besitzer aus dem Upload, statt sie zu prüfen. Die Anlage weist ab, bevor eine Referenznummer reserviert ist. - Mutable Aggregate tragen optimistische Concurrency (
ConcurrencyStamp); stale Schreibzugriffe scheitern deterministisch statt still zu überschreiben. Zeitpunkte sind UTC über ABPsIClock. - RAL-QM-HP-40:
RALQMHearingResponses.SequenceNumberist durch einen positiven SQL-Check und einen gefilterten Unique-Index über Teilnahme/Sequenz geschützt. Die historische Bestandsmigration setzt vorhandene aktive und soft-gelöschte Zeilen auf 1, ohne Inhalte oder frühere Zeitpunkte zu ändern. Der technische Schreibwechsel begrenzt den Einzelantwortindex auf Sequenz 1, ergänzt die eindeutige Auftragskennung und schützt festgeschriebene Abgaben einschließlich ihrer Anlagenzuordnungen auf dem Persistenzpfad vor Änderung und Löschung. Bestehende Antworten erhalten keine erfundene Auftragsidentität oder Einwilligung. - RAL-QM-HP-36:
RALQMHearingResponses.Originhält fest, auf welchem Weg eine Abgabe entstand –10Portal,20intern erfasst,0nicht nachgewiesen (SQL-Check[Origin] IN (0, 10, 20)). Die MigrationAddHearingResponseOriginfügt die Spalte mit dem Standardwert 0 hinzu; alle vorhandenen Zeilen, aktive wie weich gelöschte, lesen danach „nicht nachgewiesen“ – ohneUPDATEund ohne Rückschluss aus der Benutzer-ID. Der Standardwert bleibt an der Spalte, anders als beiSequenceNumber: Dort hätte er eine Tatsache erfunden, hier ist 0 genau die Aussage über eine Zeile ohne festgehaltene Herkunft. Neu schreiben kann die Anwendung ihn nicht: Das Aggregat verlangt beim AnlegenPortaloderInternalRecording, und jeder Schreibweg nennt seinen Wert selbst. Der Rückweg entfernt Check und Spalte; ein erneuter Hinweg liest wieder jede Zeile als „nicht nachgewiesen“ (HearingResponseOriginMigrationSqlServerTests). - Fachliche/auditrelevante Daten werden nicht hart gelöscht: Institutionen erst nach Nutzungsprüfung, der Hearing-Prozess über benannte Zustände (Abbruch, Widerruf, Zurückziehen).
- Kontakte einer Institution werden weich gelöscht und nie aus der Sammlung des Aggregats genommen (RAL-QM-HP-9, A5); Begründung und Nachweise unten. Die Anlagen einer Stellungnahme wurden in RAL-QM-HP-38 ebenso weich gelöscht; seit der Festschreibung durch RAL-QM-HP-40 ist auch diese Entfernung gesperrt (unten).
- Der Verfahrensverlauf (
RALQMHearingHistoryEntries, RAL-QM-HP-7) ist append-only auf dem Persistenzpfad: einSaveChangesInterceptorder Hearings-Runtime weist jedes Update und Delete eines Eintrags mitHistoryEntryImmutableab (registriert überAbpDbContextOptions.PreConfigure, weilConfiguredie eine Standardaktion setzt, die dasUseSqlServer()des Hosts ersetzt; nachgewiesen in den erzeugtenDbContextOptionsund gegen die echte Datenbank), der Lesevertrag kennt keine Mutation, ein Architekturtest hältsrcfrei von Update/Delete-Aufrufen auf dem History-Repository, vonExecuteDelete/ExecuteUpdateund vom Tabellennamen außerhalb des Mappings. Die Zeile trägt nur Ids, Katalogwerte und Zeitpunkte; wer gehandelt hat, löst das Lesemodell beim Lesen über den Lesevertrag der Authorization auf (interne Konten wie das gebundene Institutionskonto einer Portalaktion, das zusätzlich als solches gekennzeichnet wird; seit RAL-QM-HP-87 nie aus den Kontakt-Snapshots des Aggregats, die der Empfängerwechsel aus RAL-QM-HP-6 umschreibt; „System“ ohne Person; ohne benennbares Konto die Kurz-Id). Alte und neue Werte einer Datenänderung kommen aus der ABP Entity History des Verfahrens — gelesen über den PortIHearingEntityHistoryReaderaufIAuditLogRepositoryhinter der Hearings-Berechtigung des Aufrufers, nie über den berechtigungsgeschützten AuditLogging-Application-Service — und werden in der Zeitleiste dem Ereignis derselben Operation zugeordnet (Feld und Zeitfenster; eine StammdatenkorrekturCoreDataCorrectednennt ihr Feld im Detail). Die Verlaufstabelle bleibt PII-frei, die Entity History ist der Feld-Diff. Das erste Öffnen der Teilnahmeansicht ist Zustand des Teilnehmers (FirstOpenedAtUtc), kein Nachschlagen in der Verlaufstabelle: der Übergang schreibt das Ereignis, der Concurrency-Stamp des Aggregats entscheidet ein Rennen.HearingParticipationOpeningTransactiontoleriert den verlorenen Stempelkonflikt und wiederholt ausschließlich ein SQL-Deadlock-Opfer (1205, auch in EF-Ausnahmehüllen) bis zu zweimal nach kurzer Pause. Jeder Versuch erhält eine eigene Unit of Work mit frischer Konten-/Objektprüfung; der verworfene Versuch hinterlässt weder Öffnungsmarke noch Verlauf. Andere Fehler und eine neue Zugriffsabweisung bleiben Fehler. Nachweis:HearingPortalFirstOpeningConcurrencyTests(echter Deadlock, Rollback, frischer Kontext, Abweisung beim Wiederholen und Versuchslimit) sowieHearingParticipationOpeningTransactionTests. - Die verfahrensübergreifende Recherche im Verlauf
(RAL-QM-HP-45) ist dieselbe
Lesesicht über alle Verfahren: Zeitraum, Urheber (internes Konto oder „System“), Verfahren,
Institution und Ereignisarten werden in SQL ausgewertet — die Institution über die Kindobjekte
der Teilnehmer dieser Institution (Teilnehmer, Grants, Einladungen, Bindungen, Stellungnahmen,
Anhänge, Antworten) und über die Institutions-Id als Subjekt, letzteres nur für die drei
Ereignisarten, denen das Lesemodell die Institution zuschreibt (Antragsteller-Korrektur,
Nachforderung eingereicht/freigegeben) —, ebenso Zählung, Whitelist-Sortierung und Seitenwahl;
Namen, Konten, Institutionen und die Feld-Diffs der Entity History löst das mit der Zeitleiste
geteilte Lesemodell
HearingHistoryReadModelfür die Seite auf. Gültige JSON-Strings der Entity History werden genau einmal dekodiert; ungültige oder abgeschnittene Werte bleiben unverändert sichtbar. Der CSV-Writer maskiert die dekodierten Fachwerte. Die Entity History wird je Aufruf in einer Abfrage für alle Verfahren der Seite gelesen (EntityId IN (...)); als Zuordnungskandidaten eines Diffs gelten alle diff-tragenden Verlaufszeilen des Verfahrens, nicht nur die der Seite — ein Diff, dessen Ereignis außerhalb der Seite liegt, erscheint nirgends, nie an einem gleichartigen Ereignis der Seite. Die Zellregeln der drei CSV-Exporte (Semikolon, CRLF, BOM, Formelschutz einschließlich führender Leerzeichen und Steuerzeichen) teilt der modul-lokale HelferHearingCsvCells. Ein Ende vor dem Beginn wird vor jedem Lesen abgewiesen (HistoryPeriodInverted). Die CSV-Ausleitung der Treffer nimmt dieselben Filter und dieselbe Sortierung ohne Seitengrenze, läuft unter dem Exportrecht des Moduls (RALQM.Hearings.Export), wird oberhalb der HöchstzahlRALQM.Hearings.HistoryExportMaxRows(Standard 5000, gepflegt auf der Seite Fristvorgaben, Teil der Protokoll-Allowlist) vor dem Lesen einer Zeile abgewiesen (HistoryExportLimitExceeded) und hinterlässt am Audit-Eintrag ihres Aufrufs die Zeilenzahl (ExtraProperties["HistoryExportRowCount"]und Kommentar); die CSV-Bytes bleiben Rückgabewert. Eigenständige Datenänderungen ohne Verlaufszeile gehören der Zeitleiste je Verfahren, nicht der Recherche. -
Protokollierung mit einer benannten Ausnahme: Institution und Kontakt stehen in der ABP Entity History (
RALQMInstitutionsEntityHistory), jeder Application-Service-Aufruf im Audit-Log. Die interne Notiz einer Institution (RAL-QM-HP-10, A2) ist per[DisableAuditing]auf der Entity- und der DTO-Eigenschaft von beidem ausgenommen: keinAbpEntityPropertyChanges-Eintrag, kein Schlüssel in den Aktionsparametern. Die Änderung selbst bleibt sichtbar — alsAbpEntityChanges-Zeile mit dem Benutzer des Audit-Logs und überLastModifierId/LastModificationTimeam Aggregat; ABP schreibt für diese Basisfelder keine Eigenschaftszeilen. Durchgesetzt vonInstitutionAuditEntityHistorySentinelTests(Institutions.SqlServer, eigene migrierte Datenbank, Muster des Hearings-Sentinels). Seit RAL-QM-HP-7 (AC-3) gilt dasselbe für die Konfiguration: der SelektorRALQMSettingsEntityHistoryerfasst die ABP-Einstellung (Setting), undHearingSettingsEntityHistoryContributorverwirft vor dem Speichern des Audit-Logs jede Einstellungsänderung außerhalb der AllowlistProtocolledSettingsOptions— der Selektor allein erfasste jede ABP-Einstellung bis hin zu Mail-Zugangsdaten. Die Allowlist ist die Vereinigung der Beiträge der Features: die drei Fristvorgaben (HearingsSettings.ProtocolledNames, Hearings) und seit RAL-QM-HP-27 die sieben Absenderangaben der Organisation (OrganisationSenderSettings.All, Settings-Runtime) sowie seit RAL-QM-HP-45 die Höchstzahl der Protokollausleitung (HearingsSettings.HistoryExportMaxRows). Eine geänderte Fristvorgabe, ein geändertes Absenderfeld oder eine geänderte Höchstzahl steht mit altem und neuem Wert im Audit-Protokoll,DispatchBatchSizeund ABP-eigene Einstellungen ohne jede Zeile (SettingsAuditEntityHistorySentinelTests,OrganisationSenderAuditEntityHistorySentinelTests, je Einstellungsname). -
Absender jeder Aussendung (RAL-QM-HP-27). Die Organisation pflegt Name und Anschrift einmal unter
/setting-management/organisation;HearingOutboxManagermischt den Absenderblock als{{Absender}}in jedes Nachrichtenmodell, bevor der Text je Empfänger festgeschrieben wird — so trägt jede danach erzeugte Nachricht den aktuellen Absender, jede bereits erzeugte den ihres Moments. Ohne vollständigen Absender (Name, Straße, PLZ, Ort) verweigert der Manager den Enqueue vor dem ersten Provider-Aufruf (RALQM.Settings:OrganisationSenderMissing, Nullversand wie bei unaufgelösten Platzhaltern); die Anschreibenerzeugung aus RAL-QM-HP-24 erhält dieselbe Sperre überIOrganisationSenderReader.RequireAsync().
Eigenständige Verfahrenskopie (RAL-QM-HP-12)
RALQMHearings trägt nullable ClonedFromHearingId, CloneOperationId, CloneActorUserId
und CloneRequestHash (char(64), nicht auditiert). Der gefilterte eindeutige Index
IX_RALQMHearings_CloneOperation bindet einen Auftrag an genau ein Ziel, auch wenn das Ziel
später weich gelöscht wird. Bestandsverfahren bleiben ohne Herkunft. Herkunft und Auftrag
haben keine öffentlichen Setter; der einzige Initialisierungspfad verweigert eine zweite Bindung.
Detail, Liste und CSV führen die Quell-ID; der Zielverlauf schreibt ClonedFromHearing (770).
Vorschau und Anlage verlangen Hearings.Default und .Create. Dateiauswahl/-kopie verlangt
zusätzlich Documents.Default, .Download und .Manage; ohne diese Rechte liest die
Vorschau keine Dateimetadaten. Die normale Institutions-Vertragsautorisierung gilt zusätzlich.
Ein Replay prüft die heutigen Rechte erneut, liefert bei gleichem Auftrag das bestehende Ziel
vor Prüfung inzwischen veralteter Stempel und verweigert andere Akteure/Nutzlasten.
Eine neue Kopie reserviert ihren verantwortlichen Ersteller über den bestehenden
Authorization-Vertrag IStaffResponsibilityReservation.ReserveCreatorAsync. Aktuelle
Kontoeignung und konkurrierende Deaktivierung folgen damit denselben Regeln wie bei der
regulären Neuanlage; die Reservierung bleibt Teil der Kopiertransaktion.
Die Serializable-Unit-of-Work hält Quelllesesperren bis zum Commit; sie verändert weder
Quellstempel noch Quellhistorie. Dateikopien verwenden den bestehenden transaktionalen
Datenbank-BLOB-Vertrag von IDocumentFilingPort; ein anderer Provider wird vor der Kopie
abgewiesen. Fehlende Bytes oder Fehler in späteren Teilschritten rollen auch bereits erzeugte
Dateien zurück. Individuell widerrufene Grants bleiben ausgenommen; allein durch das
Verfahrensende widerrufene Zuordnungen können auf neue IDs abgebildet werden. Pflichtunterlagen
verwenden weiterhin die reguläre Zuordnung an alle Zielbeteiligten.
ID-only über zwei Modulgrenzen am Beispiel des Verwendungsnachweises
RALQMFilingHearingUsages (RAL-QM-HP-16)
verbindet in einer Zeile fünf Kennungen aus vier Besitzbereichen: SourceEntryId (eigener Slice),
SourceDescriptorId (CAF Documents), HearingId und HearingDocumentId (Hearings) sowie
AdoptedByUserId (ABP Identity). Alle fünf sind blanke Guid-Spalten ohne Navigation und ohne
Fremdschlüssel — die Regel des vorigen Absatzes, hier über zwei Modulgrenzen gleichzeitig.
Die Tabelle führt darüber hinaus keine fremden Fakten: kein Verfahrenskennzeichen, keinen
Verfahrenstitel, keinen Status, keinen Dateinamen. Die holt die Abfrage zur Laufzeit über
IHearingDocumentAdoptionPort.DescribeAsync und filtert sie dabei nach den Leserechten des
Aufrufers. Eine denormalisierte Kopie wäre bequem und würde genau das dauerhaft preisgeben, was
§1 zurückhalten soll — und nach einer Umbenennung oder
einem Statuswechsel des Verfahrens zusätzlich falsch sein.
Zeilen werden nie gelöscht. Sie sind der fachliche Tombstone aus
SPEC-RAL-QM-HP-19: Papierkorb und endgültiges
Entfernen betreffen nur die Ablagefassung, der Herkunftsnachweis bleibt in jedem Status auflösbar.
Die committete Zeile ist zugleich der Beleg der Operation — der eindeutige Index auf OperationId
entscheidet eine wiederholte Übernahme, nicht ein zusätzlicher Zustand im Aggregat.
Data-preserving Renames
Die laufende RALQM-Umbenennung zeigt das verbindliche Muster für Identifier-Änderungen: Die
Migration RenamePersistedIdentifiersToRALQM
(HearingPortal/Host/Migrations/20260825174437_RenamePersistedIdentifiersToRALQM.cs) benennt
Tabellen (z. B. QualityMarksHearings → RALQMHearings, QualityMarksInstitutions →
RALQMInstitutions, CafDocumentShareGrants → CAFDocumentShareGrants) und Indizes per
RenameTable/RenameIndex um, statt Daten zu löschen und neu anzulegen. Bereits ausgerollte
Migrationen behalten dabei ihre historischen Bezeichner (z. B. Constraint-Namen wie
FK_GzHearings_… bleiben in älteren Migrationsschritten unverändert); nur der aktuelle
Modellstand und neue Migrationen verwenden das neue Präfix. Diese Regel gilt für jede künftige
Umbenennung persistierter Kennungen.
Kreis plus Kennzeichen am Beispiel der Pflichtpartner
RAL-QM-HP-10 (O4) trennt bei Institutionen den
Kreis (InstitutionType: Fachkreis, Verkehrskreis) vom Pflichtpartner-Kennzeichen
(IsMandatoryPartner, eigene Bit-Spalte). Die Migration AddInstitutionMandatoryPartnerFlag
legt die Spalte an und stellt jede Bestandszeile mit dem zurückgezogenen Typwert 0 auf
Verkehrskreis mit gesetztem Kennzeichen um, auch weich gelöschte Zeilen, damit keine Zeile einen
undefinierten Kreis behält, und entfernt danach den von der Spaltenanlage abgeleiteten
DEFAULT 0 auf Type (wie RAL-QM-HP-4 bei den Wertelisten-Referenzen): ein roher INSERT ohne
Kreis scheitert, statt den zurückgezogenen Wert still zu speichern. Ein Abbruchweg wie bei den
Wertelisten fehlt bewusst: die Zeilen bleiben lesbar und in der Maske korrigierbar. Down()
stellt den Default wieder her, setzt markierte Zeilen auf den alten Typwert zurück und entfernt
die Spalte; für jeden markierten Fachkreis ist das verlustbehaftet und in der Migration
dokumentiert. Die Enum-Werte 10 und 20 bleiben der Persistenzvertrag, der Wert 0 bleibt
unbelegt und wird vom Aggregat abgewiesen.
Beteiligungsgrund als Pflichtspalte mit Bestandsübernahme (RAL-QM-HP-5)
RAL-QM-HP-5 (AC-3, A2) gibt
jeder Beteiligung einen Beteiligungsgrund (HearingParticipationReason: Pflichtpartner 10,
manuell 20) als Pflichtspalte ParticipationReason auf RALQMHearingParticipants – voll benannt,
weil WithdrawalReason daneben steht und etwas anderes meint. Der Grund folgt dem
Pflichtpartner-Kennzeichen der Institution im Moment der Zuordnung und ist danach unveränderlich
(E2); die eine Regel dafür, HearingParticipationReasonRule, liegt im Hearings-Contract, damit
Einzelzuordnung, automatische Einbindung, Kopie, Nachbeteiligung, Gruppenzuordnung und der
Demo-Seed des Hosts sie nicht verschieden ableiten. Das Aggregat weist den unbelegten Wert 0 ab
(InvalidParticipationReason). Die Migration AddHearingParticipantReasonAndAccessRevocation
folgt dem Muster des Kreises: Sie legt die Spalte mit DEFAULT 0 an, trägt den Bestand im
selben Schritt nach – jede Zeile, auch zurückgezogene und weich gelöschte, erhält 10, wenn ihre
Institution heute das Kennzeichen trägt, sonst 20; fehlt die Institution, gilt manuell – und
entfernt danach den Default, sodass ein roher INSERT ohne Grund scheitert, statt die 0 still zu
speichern. Kein Abbruchweg: Die Nachtragsregel lässt keine Zeile ohne Grund zurück. Dieselbe
Migration bringt die Spalte AccessRevokedAtUtc (nullable datetime2, UTC) für den gezielten
Zugangsentzug aus AC-10, damit die Story genau eine Schemaänderung ausliefert. Down() entfernt
beide Spalten; der nachgetragene Grund ist danach verloren, was für die Bestandszeilen
(Demo-Daten) hingenommen ist.
Die Spalte AccessRevokedAtUtc ist der Zustand „Zugang entzogen“ je Beteiligung (AC-10, E6):
kein zweiter Statusraum, keine eigene Tabelle. Geschrieben wird sie nur vom Aggregat
(Hearing.RevokeParticipantAccess, RestoreParticipantAccess) und nur in Dispatched und
Adjudication; ein zweiter Entzug (AccessAlreadyRevoked) und eine Freigabe ohne Entzug
(AccessNotRevoked) werden abgewiesen, außerhalb des laufenden Verfahrens jeder Wechsel
(AccessChangeRequiresRunningHearing) – nach dem Ende bleibt ein entzogener Zugang entzogen.
Status, Empfänger, Grants und Fristen der Beteiligung bleiben unberührt; es gibt keine Begründung.
Jeder Wechsel erhält einen Verlaufseintrag (AccessRevoked 600, AccessRestored 610, Subjekt die
Beteiligung, keine Details); der Katalog bleibt geschlossen und wird nie umnummeriert.
Empfängerstand als Snapshot-Spalten und eingefrorener Versandstand (RAL-QM-HP-6)
RAL-QM-HP-6 trennt zwei
Stände, ohne einen zweiten Versandbeleg anzulegen. Der operative Stand einer Beteiligung sind
ihre Snapshot-Spalten auf RALQMHearingParticipants: neben Name, Anrede, Anredeform, Titel und
E-Mail seit der Migration AddHearingRecipientStand auch InstitutionStreetSnapshot,
InstitutionPostalCodeSnapshot, InstitutionCitySnapshot, InstitutionCountrySnapshot
(Anzeigename des Landes) und ContactFunctionSnapshot (Anzeigename der Funktion) sowie
RecipientStandUpdatedAtUtc als Zeitpunkt des letzten Befehls. Alle neuen Spalten sind nullable
und werden nicht aus heutigen Stammdaten befüllt: ein Bestand ohne Anschrift zeigt „nicht
festgehalten“, nie einen erfundenen historischen Wert. Der Stand ist ein Textbeleg – Land und
Funktion stehen als Namen, nicht als Katalog-Ids, damit eine spätere Umbenennung im Katalog den
Beleg nicht umschreibt. Der Versandstand liegt auf der Postausgangszeile
RALQMHearingOutboxMessages (RecipientInstitutionName, RecipientStreet, RecipientPostalCode,
RecipientCity, RecipientCountry, RecipientSalutation, RecipientTitle, RecipientName,
RecipientFunction, dazu das bestehende ToEmail), eingefroren vom Renderer im Moment des
Einstellens und danach nie geändert; Zeilen von vor der Story bleiben NULL. Die drei Befehle der
Story (Übernahme, Empfängerwechsel, Adresskorrektur) ändern nur die Snapshot-Spalten der
Beteiligung, laufen unter dem Verfahrensstempel und schreiben je einen Verlaufseintrag
(RecipientStandUpdated 640, RecipientContactChanged 650, RecipientEmailCorrected 660) mit
Feldnamen bzw. Kontakt-Ids, nie mit Werten; die Übernahme ist zusätzlich an den ComparisonStamp
der Vorschau gebunden (SHA-256 über die aktuellen Stammdatenwerte), damit nie Werte übernommen
werden, die niemand gesehen hat. Beide Tabellen bleiben [DisableAuditing] für die Snapshots.
Kontaktmeldung als eigener Datensatz (RAL-QM-HP-41)
RAL-QM-HP-41 legt mit
der Migration AddHearingContactReports genau eine Tabelle an, RALQMHearingContactReports, und
ändert keine bestehende. HearingContactReport ist ein eigenes Aggregat mit Fremdschlüsseln auf
Verfahren und Beteiligung (beide Restrict), nicht Kind des Verfahrensaggregats: Melden und
Zurückziehen ändern weder Verfahren noch dessen Stempel. Die Zeile trägt die gemeldete Person,
meldendes Konto und UTC-Zeitpunkt, Zustand, Abschlusszeitpunkt und -konto, Ziel, den übernommenen
Kontaktbezug, die stattdessen übernommene Person und die interne Notiz. Zustand und Ziel sind
durch Check-Constraints begrenzt; ihre Zahlenwerte sind Migrationsvertrag. Der gefilterte
eindeutige Index IX_RALQMHearingContactReports_OpenPerParticipant ([State] = 0) lässt je
Beteiligung höchstens eine offene Meldung zu; eine Verletzung wird als „bereits offen“ gemeldet.
Die Funktion steht als Katalog-Id, damit eine gespeicherte Meldung übernehmbar bleibt; der
Empfängerstand erhält bei der Übernahme wie immer den Anzeigenamen.
Die Beteiligung braucht keine neue Spalte: ContactId war schon nullable. Ein Empfänger „aus
Kontaktmeldung, nur dieses Verfahren“ ist abgeleitet – kein Kontaktbezug und die jüngste
übernommene oder ersetzte Meldung der Beteiligung mit Ziel „nur dieses Verfahren“
(HearingContactReportRules.FindHearingOnlyRecipientReport,
ADR-14).
Übernehmen und Ersetzen laufen als serialisierbare Unit of Work über beide Bausteine; alle
Prüfungen liegen vor dem ersten Speicherschritt, weil ABP die Entity-Änderungen eines
erfolgreichen Speicherns auch dann ins Audit-Log schreibt, wenn der Aufruf danach scheitert – wie
beim Standardansprechpartner.
Ein Deadlock-Opfer wird als Konflikt gemeldet. Die Tabelle ist [DisableAuditing] und liegt
außerhalb der Entity History von Hearings; der neue Stammdatenkontakt wird von Institutions wie
jede Kontaktpflege protokolliert. Nachweise: HearingContactReportSqlServerTests,
InstitutionAuthorizationPipelineTests (einen Kontakt hinzufügen); die Migration läuft im
SQL-Fixture der *.SqlServer-Suiten aus leerer Datenbank, has-pending-model-changes prüft das
Gate.
Kommunikationsschritt, Begleitdokument und Versandbeleg (RAL-QM-HP-24)
RAL-QM-HP-24 trennt den gebundenen
Vorlagensatz (RAL-QM-HP-26, unveränderlich) vom bearbeitbaren Wortlaut: RALQMHearingCommunicationSteps
hält je Verfahren, Zweck und Sprache (eindeutiger Index
IX_RALQMHearingCommunicationSteps_Hearing_Purpose_Culture, seit RAL-QM-HP-101) Betreff, Text, Herkunft
(SourceTemplateId, SourceRevision, SourceCultureName, IsFallback), Initialisierung (Akteur oder null für automatisch), UpdatedAtUtc,
ReleasedAtUtc und die Institutionsabweichungen als eine JSON-Spalte (DeviationsJson; kleine
Liste je Schritt, nie per SQL gefiltert). Der Schritt ist Kind des Hearing-Aggregats: jede
Textänderung bewegt den Verfahrensstempel, eine Einreichung oder ein Versand, der eine
Textänderung kreuzt, endet als Konflikt. Text und Abweichungen sind [DisableAuditing]; der
Verlauf trägt Zweck und Beteiligung, nie den Wortlaut. RALQMHearingOutboxMessages erhält
CoverDocumentId/CoverDocumentFileName (die Datei aus CAF Documents, keine zweite
Metadatentabelle), SentSubject/SentBody (die Strings, die der Transport bekam, einmal bei
MarkSent, nie umgeschrieben; Altzeilen NULL = „unvollständiger Altbeleg“) und den
Bounce-Marker BouncedAtUtc/BouncedAttemptNo/BounceReasonCode; IsUndeliverable ist
berechnet (Bounce des letzten Versuchs bei Sent). RALQMHearingOutboxBounces ist das
append-only Ingest-Protokoll je Meldung (OutboxMessageId+ExternalReference eindeutig), damit
dieselbe Meldung einmal wirkt und ein verspäteter Bounce eines älteren Versuchs sichtbar bleibt,
ohne den neueren Erfolg zu überschreiben.
Kommunikationssprache je Empfänger (RAL-QM-HP-101)
RAL-QM-HP-101 macht die Sprache der Verfahrensnachrichten zu einer Eigenschaft des Empfängers, nicht des Bearbeiters (ADR-22):
- Sprachen. Aktive Sprachen und Standardsprache kommen aus der Sprachverwaltung
(
ILanguageProvider, EinstellungAbp.Localization.DefaultLanguage);HearingLanguageslöst sie zentral auf, Kennungen sind die Kulturnamen der Sprachverwaltung (de-DE,en). Hearings rechnet Kulturnamen nicht um; die Altkennungende/enstellt der Migrator einmalig um (Inhalte, Sprachstände, gebundene Sätze; strukturierte Ereignisse 10101, 10103–10106) und entfernt dabei wortgleiche Kopien des Standardtexts unter weiteren Sprachen in jeder Vorlage, jede gemeldet (E11), über die einzige Löschoperation des Vorlagenports (IManagedTemplateContentPort.DeleteAsync). - Kontakt.
InstitutionContact.CommunicationLanguage(optional, 16 Zeichen) wird mitRALQM.Institutions.Updateund Institutionsstempel gepflegt; leer, unbekannt oder inaktiv liest sich als Standardsprache (HearingLanguages.ResolveEffectiveAsync); eine gespeicherte, später deaktivierte Sprache bleibt am Kontakt, blockiert kein Speichern der Institution und gilt bis zur Änderung als Standardsprache, der Wechsel auf eine inaktive Sprache wird abgewiesen (E12). Hearings liest sie permissionfrei überIInstitutionContactLanguageReaderausInstitutions.Contracts. - Sprachstände.
RALQMHearingCommunicationStepsist eindeutig je Verfahren, Zweck und Sprache. Der Editor bietet nur die wirksamen Sprachen der Empfänger an („Anpassen pro Sprache“ wie in der Textvorlagenverwaltung: Bezugssprache lesend links, sichtbar abgesetzt, Zielsprache bearbeitbar rechts, nie dieselbe Sprache; die Zielsprachenwahl nennt die Empfänger je Sprache); ein Speichern nennt die nicht angepassten Sprachen als Hinweis, eine Abweichung eines Empfängers in einer anderen Sprache ebenso; der Editor beginnt in der Standardsprache. Die Empfängerliste für Abweichung und Endfassung zeigt alle Institutionen mit ihrer Sprache; Abweichung und Endfassung folgen der Sprache der gewählten Institution; ungespeicherte Änderungen werden beim Wechsel von Sprache, Institution oder Zweck abgefragt; ein gesperrter Sprachstand vergleicht nur („Sprachen vergleichen“, Felder deaktiviert); die Knöpfe stehen nebeneinander wie überall (RAL-QM-HP-101 E15, E16, E19–E21; Vereinfachung vom 16.10.2026). Eine Sprache ohne gebundene Fassung und ohne eigenen Text spiegelt den jeweils aktuellen Text der Standardsprache (HearingCommunicationMirror): Nachsehen friert nichts ein, erst ein eigener Text oder eine Abweichung legt den Sprachstand an, erst der eigene Text macht ihn eigenständig (E13). Vor der ersten Zeile dieser Sprache entsteht er automatisch aus dem dann aktuellen Standardtext und trägt das Rückfallkennzeichen (IsFallback,SourceCultureName). DerOutputStampumfasst alle Sprachstände und folgt dem Standardtext, solange eine Sprache ihn spiegelt. - Versand. Kein Sendeweg nennt eine Sprache (
HearingOutboxEnqueueRequest.CultureNamenull);HearingOutboxRendererlöst sie je Zeile aus der Kontaktsprache des Haupt- oder gewählten Zusatzempfängers auf (der Sprachleser ist Pflichtparameter), rendert Anrede, Linkzeile, Datenschutzzeile, Zusatzblöcke und den Portalhinweis der Endfassung (HearingLocalizedModelParts) in dieser Sprache und meldet sie;HearingOutboxManagerfriertCultureNameundContentCultureNameauf der Zeile ein, die Vertretungskopie und eine Zustellkorrektur tragen beide. Datumswerte reisen roh (HearingMessageDates,yyyy-MM-dd; nur die Datumsschlüssel des Modells,DateKeys) und werden im Kurzdatum der Zeilensprache geschrieben; der Antwortabsatz der Bescheidung entsteht aus Erwiderung und Votum (HearingAdjudicationReplyBlock); das Begleitschreiben datiert in der Zeilensprache, Grußformel, Beschriftungen, Seitenzahl und PDF-Titel kommen aus deren Ressourcen (HearingCoverLetterTexts), sein Dateiname bleibt als technischer Bezeichner deutsch (E14). - Interne Mails (Runde vom 16.10.2026). Freigabe- und Einreichungshinweis, Störungsmeldung,
Rückmeldehinweis, Erinnerungsbericht und Abschluss-Erinnerung gehen je Empfänger in dessen
Kommunikationssprache hinaus:
IStaffNotificationRecipientReaderliefert sie (StaffNotificationRecipientDto.CultureName), die Prozessoren rendern je Ziel, Zeitpunkte schreibtHearingMessageDates.FormatInstantwie in den Empfängernachrichten (E26); Berichts- und Abschlussdokumente bleiben in der Standardsprache (E27). - Konten (Runde vom 16.10.2026). Ein Mitarbeitendenkonto trägt seine Sprache als Zusatzeigenschaft
des ABP-Benutzers (
RALQM.Profile.CommunicationLanguage), ein Institutionskonto liest die seines gebundenen Kontakts (AccountCommunicationLanguage). Jede Sprachänderung – Referent am Kontakt, Empfänger oder Mitarbeitender am eigenen Konto, Verwaltung in der Kontoverwaltung – setzt zuerst daslocale-Attribut des Anmeldedienstes (IKeycloakAdminClient.SetLocaleAsync) und wird erst dann gespeichert; nimmt der Dienst sie nicht an, wird die ganze Änderung abgewiesen (E23). Institutions meldet Kontaktänderungen vor dem Speichern überIInstitutionContactLanguageSynchronizer; die Selbstbedienung schreibt den gebundenen Kontakt überIInstitutionContactLanguageWriter. Kontomails der Anwendung rendern unter der Kontosprache (HP11-Reset: Snapshot und fester Deutsch-Fallback gemäß ADR-19); der Kontoverlauf hält jede Änderung fest (CommunicationLanguageChanged, E24). - Rundnachricht (Runde vom 16.10.2026).
HearingCircularträgt neben dem Text der Standardsprache die Texte weiterer Sprachen (TextsJson, ganz oder gar nicht je Sprache, ein wortgleicher Text ist ein Spiegel und wird nicht gespeichert; E28, E35); die angebotenen und beim Anlegen aus der Vorlage vorbelegten Sprachen sind Standardsprache und Empfängersprachen der Gruppe (E34), der Editor folgt/versand(Umschalter, Bezugssprache lesend, Zielsprache mit Spiegel der Standardsprache), ein Text einer deaktivierten Sprache bleibt oder wird entfernt, nie geändert (E36); jede Institution erhält die wirksame Sprache ihres Standardkontakts, ohne eigenen Text den Standardtext mitContentCultureNamean der Zeile (E29); die Empfängerprüfung nennt in einem Satz die Institutionen, die den Standardtext erhalten, Zeilen und Ergebnis tragen kein Kennzeichen, der Postausgang zeigt Sprache und Rückfall der Zeile; nach dem Versand stehen die Texte untereinander, lesend; ein Text einer deaktivierten Sprache ist nur lesbar und entfernbar (E36). Zeitpunkte aller Mails schreibtHearingMessageInstants(Hearings.Contracts), auch die Kontomails von Authorization (E38). - Eingangsbestätigung.
HearingResponseNotification.CultureNamefriert die wirksame Sprache des Empfängers beim Speichern des Auftrags ein; der Worker schreibt die Bestätigung in ihr, das Empfangsdatum im Format dieser Sprache. - Anzeige. Zustellstatus und Nachrichtendetail nennen die Sprache der Zeile mit dem Anzeigenamen
der Sprachverwaltung und den Rückfall im Wortlaut der Vorschau (
HearingParticipantDeliveryStatusDto,HearingOutboxMessageDto:CultureName,ContentCultureName,IsFallback,LanguageDisplayName,ContentLanguageDisplayName); der Verlauf nennt die Sprache eines Sprachstand-Eintrags.
Amtliche Abbruchbegründung (RAL-QM-HP-42)
RAL-QM-HP-42 ergänzt RALQMHearings um
das Kennzeichen IsCancellationReasonOfficial (Migration AddOfficialCancellationReason, bit,
Standard false): true genau dann, wenn Hearing.Abort den Grund gesetzt hat – der Grund
eines laufenden Verfahrens ist seit der Story die amtliche, den Institutionen übermittelte
Begründung. Stornierungen vor dem Versand (Cancel) und jeder Altbestand behalten false und damit
den internen Lesevertrag; eine spätere Veröffentlichung im Portal (RAL-QM-HP-62) darf sich nur auf
gekennzeichnete Gründe stützen. Das Kennzeichen ist Prozesszustand, keine protokollierte
Datenänderung (HearingHistoryReadModel.ProtocolledProperties unverändert); der Text bleibt wie
bisher außerhalb von Verlauf, Audit und Logs. Die Abbruchmitteilung selbst ist eine gewöhnliche
Postausgangszeile (CancellationNotice, ProtectedPayload null, Idempotenzschlüssel je
Beteiligung); die Begründung liegt im ModelJson unter Begruendung und im gerenderten Text –
beide [DisableAuditing] wie jede Zeile.
Archivkennzeichen (RAL-QM-HP-44)
RAL-QM-HP-44 ergänzt
RALQMHearings um IsArchived (bit, Standard false, Index IX_RALQMHearings_IsArchived),
ArchivedAtUtc und ArchivedByUserId (Migration AddHearingArchiveFlag). Das Kennzeichen ist
Prozesszustand, keine protokollierte Datenänderung; der Verlauf trägt Archived (750) und
RestoredFromArchive (760) mit Actor und Zeit, ohne Detail. Die Rückholbegründung liegt allein im
ABP-Audit-Log des Aufrufs, vollständig als Zusatzeigenschaft ArchiveRestoreReason (die
Aktionsparameter leert ABP ab 2000 Zeichen; [DisableAuditing] hält den Grund dort heraus, Review
!169), und wird weder am Aggregat noch im Verlauf noch in Logs gespeichert. Kein globaler EF-Filter: jede
Listenabfrage nennt das Kennzeichen selbst (Active schließt es aus, Closed verlangt es, All
ignoriert es); Historie, Direktzugriffe, Dokumentreferenzen und Retention sehen archivierte
Verfahren unverändert. Bestandsverfahren bleiben unarchiviert; ein Endstatus allein ist keine
Archiventscheidung.
Veröffentlichungskennzeichen und öffentliche Kennung (RAL-QM-HP-47)
RAL-QM-HP-47 ergänzt RALQMHearings um
IsPublished (bit, Standard false, Index IX_RALQMHearings_IsPublished), PublishedAtUtc,
PublishedByUserId und PublicId (eindeutig, gefiltert auf gesetzte Werte, Index
IX_RALQMHearings_PublicId; Migration AddHearingPublication). Die öffentliche Kennung entsteht beim
ersten Kennzeichnen und bleibt auch nach Rücknahme und Ende erhalten; sie ist weder Aktenzeichen noch
Verfahrens-Id. Kennzeichen und Sichtbarkeit sind getrennt: kein globaler Filter, jede öffentliche
Lesung nennt Kennzeichen und Status (HearingPublicationRule.PublicStatuses) selbst. Die
Freigaberücknahme setzt das Kennzeichen zurück (Verlaufseintrag 800), damit ein geänderter und neu
freigegebener Entwurf erst nach erneuter Kennzeichnung öffentlich wird. Der Änderungszeitpunkt des
Bestands ist der späteste aus der LastModificationTime des Aggregats und der Änderungszeit der
referenzierten Einträge von Kennzeichnungsart und Verfahrensart (IValueListLookup.GetChangeTimesAsync),
weil der Bestand deren aufgelöste Namen trägt; eine Umbenennung in der Werteliste erscheint so im
Delta. Die Namen löst der Abruf immer in de-DE auf (SQL-Nachweise in der Spec).
Entfernungen sind Verfahren mit Kennung, die nicht mehr sichtbar sind; sie verlassen das Portal nur
als Kennung mit Zeitpunkt.
Votum, Fassungskette und Bescheidungsstand je Beteiligung (RAL-QM-HP-46)
RAL-QM-HP-46 ergänzt drei Tabellen
(Migration AddAdjudicationVoteAndPartialDispatch):
RALQMHearingResponseReplies:Vote(int, nullbar; 10 Bestätigung, 20 Ablehnung) undPreviousReplyId(die ersetzte Fassung). Der eindeutige IndexUX_RALQMHearingResponseReplies_HearingResponseId_PreviousReplyIdist nicht gefiltert: SQL Server behandeltNULLin einem eindeutigen Index als Wert, eine Stellungnahme hat deshalb genau eine Erstfassung und jede Fassung höchstens einen Nachfolger. Die Fassungen bilden eine Kette; zwei parallele Korrekturen derselben Fassung können nicht beide gespeichert werden. Der Dienst prüft die gelesene Fassung zuerst selbst und wertet nur die Verletzung dieses Index als denselben Konflikt (AdjudicationReplyConflict). Der Index ersetzt den einfachen Index aufHearingResponseId, dessen führende Spalte er teilt. Antworten bleiben append-only.RALQMHearingParticipants:AdjudicationDispatchedAtUtcundAdjudicationReplyId– wann die Beteiligung ihre Bescheidung erhielt und mit welcher Fassung. Beide „first write wins“; die Fassung ist eine schlichte Kennung ohne Fremdschlüssel, wie der Verweis der Antwort auf ihre Abgabe.RALQMHearings:AdjudicationFullyDispatchedAtUtc– der Zeitpunkt der vollständigen Übermittlung.AdjudicationDispatchedAtUtcbleibt der Erstversand und sperrt Variante und Komposition; Abschlusserinnerung (RAL-QM-HP-43) und Abschlussvoraussetzung (RAL-QM-HP-51) lesen den neuen Zeitpunkt.
Sichtbarkeit ist nie ein eigener Wert: Portal und Rückmeldungsübersicht leiten den übermittelten
Stand aus dem Stand der Beteiligung ab (HearingPortalRules.DispatchedReplies) – je Abgabe die
Fassung, die bei der Übermittlung an diese Beteiligung wirksam war.
Bestandsübernahme ohne Erfindung: Keine Bestandsantwort erhält ein Votum. Die vorhandenen Antworten einer Stellungnahme werden in der Reihenfolge der Regel für die wirksame Fassung verkettet (Antwortzeitpunkt, dann Kennung als Kleinbuchstaben-Hex ohne Bindestriche, ordinal), bevor der eindeutige Index entsteht. Jedes versandte Verfahren gilt zu seinem Versandzeitpunkt als vollständig übermittelt, weil ein Versand bisher immer die eine Welle an alle war. Bedient ist, wer einen Bescheidauftrag im Postausgang hat; seine Fassung ist die damals wirksame seiner letzten Abgabe. Eine früher ohne Antwort bediente Beteiligung behält den Zeitpunkt und nennt keine Fassung.
Dateiinhalt nach gescheiterter Unit of Work (RAL-QM-HP-51)
Der Datenbank-BLOB-Provider speichert Inhalt in derselben Transaktion wie den Deskriptor; ein
Rollback nimmt beides zurück. Der optionale Dateisystem-Provider schreibt die Datei sofort. Für
Erstellungen über IDocumentContentPort.CreateAsync (Abschlussbericht, Begleitbriefe, Anlagen einer
Stellungnahme, Verfahrenskopie) räumt deshalb der Documents-Baustein selbst nach, ohne Port- oder
Konsumentenänderung: Er merkt jede neue Inhalts-Id an der laufenden Unit of Work vor; scheitert sie,
prüft er nach dem Rollback in einer neuen Unit of Work, welche Deskriptoren committet sind, und
löscht nur die übrigen Dateien über den Blobnamen. Ein Konsument kann das nicht leisten: nach dem
Rollback fehlt der Deskriptor, über den er löschen dürfte, und vor dem Rollback blockiert oder
scheitert jeder weitere Befehl derselben Transaktion. Grenzen und Zusicherung:
Documents-Vertrag. Seit RAL-QM-HP-81
prüft die Bereinigung den Deskriptor ausdrücklich unter ReadCommitted, ihre Zeitgrenze ist
Konfiguration (CAFDocuments:Storage:RollbackCleanupTimeLimit), und ein wiederkehrender
Abgleichslauf entfernt beim Dateisystem-Provider jede Datei ohne committeten Deskriptor, die älter
als die Mindestzeit ist (CAFDocuments:Storage:Reconciliation) – auch nach einem Prozessabbruch.
Ein Löschfehler ist ein echter Rest und wird als Fehler mit Inhalts-Id und Fehlerklasse gemeldet;
eine gescheiterte Kompensation eines Konsumenten ist nur eine Warnung
(Risiken).
Rückläufer und Unzustellbarkeit (RAL-QM-HP-76, ADR-17)
Jeder Versandversuch trägt eine signierte Message-ID (HearingMessageIdCodec, HMAC über Zeile und
Versuch); mit Hearings:DeliveryReports:ReturnAddress gehen Mails mit dieser Rücklaufadresse hinaus.
HearingDeliveryReportWorker liest das Rückläuferpostfach per IMAP, HearingDeliveryReportProcessor
ordnet eine RFC-3464-Meldung mit Action: failed genau dann zu, wenn sie genau eine gültig signierte
Referenz nennt - über HearingBounceRecorder, dieselbe Regel wie der interne Erfassungsweg
(Ergebnis je Versuch, Verlauf DeliveryBounced, Störung nur für den aktuellen Versuch, Dubletten über
die Meldungsreferenz). Alles andere landet ohne Text in der Klärungsliste /unzustellbarkeiten
(Recht RALQM.Hearings.DeliveryReports.Review), wo es nur mit Begründung erledigt werden kann.
Die Empfängeradresse einer Meldung wird nie zur Zuordnung benutzt.
Schadsoftwareprüfung hochgeladener Dateien (RAL-QM-HP-50, ADR-16)
RAL-QM-HP-50 ergänzt CAF Documents um einen Prüfstand je Inhalt und
einen dauerhaften Prüfauftrag. Der Stand liegt als ExtraProperty CAF.Modules.Documents:ScanState
am ABP-Dateideskriptor; fehlt er (Altbestand), gilt die Datei als „in Prüfung“. Die Tabelle
CAFDocumentScanJobs (Migration AddDocumentScanJobs, Schlüssel = Dokument-Id) hält Herkunft,
Versuchsnummer, Anspruch, nächsten Versuch, Beginn des Fehlerfensters, Fehlercode und Signaturname.
Index (State, NextAttemptAtUtc). Deskriptor und Auftrag werden in derselben Unit of Work geschrieben.
Ablauf und Regeln:
- Lesen: OpenContentAsync und der Share-Link liefern nur unbedenklichen Inhalt.
- Upload: wird sofort geprüft (InlineTimeout, 10 s). Bei Befall wird er abgewiesen
(ContentInfected mit Dateiname); ohne Ergebnis wird er gesperrt gespeichert.
- Worker: Anspruch je Versuch, Übernahme nach StuckAttemptTimeout, Ergebnis nur für den
laufenden Versuch. Fehler werden mit 1 min, verdoppelt, höchstens 1 h wiederholt, nach 24 h ist
die Prüfung Failed. Uploads gehen vor Altbestand; den Bestand reiht der Worker seitenweise ein, die neuesten Dateien zuerst (die der laufenden Verfahren). Standarddurchsatz rund 300 Dateien je Minute.
- Ergebnisse: Ein Endstand wird als DocumentScanStateChangedEto veröffentlicht. Hearings
macht daraus Störungen der Quelle DocumentScan.
- Ausnahmen: Kopien erben den unbedenklichen Befund. Systemerzeugte PDFs werden nicht geprüft.
Individuelle Frist und korrigierter Zustellauftrag (Audit 29.09.2026)
Die Migration AuditRedeliveryAndParticipantDeadlines ergänzt ausschließlich Hearings-eigene
Tabellen. An der Beteiligung stehen die nullable UTC-Frist und Begründung sowie ein
Revisionszähler mit Ausgangswert 0. Die Begründung bleibt aus dem generischen Audit
ausgeschlossen. ExtendDeadlineAsync serialisiert am Verfahren und prüft dessen Stempel;
Frist, abgeleiteter Beteiligungsstand, neue Fristaktionen und Verlauf werden gemeinsam gespeichert.
Auch eine spätere zweite Verfahrensfrist erzeugt für betroffene individuelle Fristen eine neue
Planungsrevision, wenn sich deren wirksamer Tag verschiebt; terminale alte Jobs bleiben erhalten.
Die Postausgangszeile hält RedeliverySourceId, RedeliveryOperationId,
SupersededByMessageId und RedeliveryCompletedAtUtc. Gefilterte Unique-Indizes auf Quelle
und Operation verhindern mehrere Nachfolger oder mehrdeutige Wiederholungen. Der alte Auftrag
behält Empfängerstand, Text und Versuchshistorie; ein neuer Auftrag erhält nur die ausdrücklich
bestätigte operative E-Mail als neue Transportadresse. Es entstehen keine modulübergreifenden
Navigationen oder Fremdschlüssel. Die Referenz auf den erfolgreichen Nachfolger ersetzt keinen
eigenen SMTP-Versuch des Vorgängers und setzt dessen SentAtUtc nicht.
Nach einem Abbruch zwischen Nachfolgererfolg und Vorgängerabgleich ergänzt der periodische
Incident-Detector fehlende Erledigungszeitpunkte anhand reziproker Links desselben Verfahrens
und derselben Beteiligung. Höchstens 500 passende Zeilen je Durchlauf halten den Abgleich
begrenzt; weitere Durchläufe vervollständigen die Kette ohne erneuten Versand.
Standardansprechpartner als Kennzeichen mit gefiltertem eindeutigem Index (RAL-QM-HP-9)
RAL-QM-HP-9 (AC-2, A6) macht den
Standardansprechpartner zu einer eigenen Spalte IsDefault (bit NOT NULL) auf
RALQMInstitutionContacts. Geschrieben wird sie nur vom Aggregat Institution
(SetDefaultContact tauscht alten und neuen Standard in einem Aufruf); die Invariante „höchstens
ein Standard je Institution“ sichert zusätzlich der gefilterte eindeutige Index
IX_RALQMInstitutionContacts_DefaultPerInstitution über InstitutionId mit dem Filter
[IsDefault] = 1 AND [IsDeleted] = 0. Der Schlüssel ist bewusst InstitutionId allein und nicht
(InstitutionId, IsDefault): Unter dem Filter ist das Kennzeichen konstant, und im Schlüssel
würde EF für die zwei Zeilen eines Wechsels Ordnungskanten über den eindeutigen Wert ableiten,
die in einem Zirkelfehler enden. Einen Wechsel in einem SaveChanges liefert keine Indexform: EF
setzt die beiden UPDATEs einer Tabelle in Primärschlüsselreihenfolge ab, und SQL Server prüft den
gefilterten Index je Anweisung; sortiert der neue Standard zuerst, scheitert seine Anweisung am
noch gesetzten alten Kennzeichen. Ein Standardwechsel wird deshalb in zwei Speicherschritten
innerhalb einer Transaktion persistiert (Institution.ClearDefaultContact, speichern,
SetDefaultContact, speichern); ein Zwischenstand ohne Standard ist für andere Verbindungen nicht
sichtbar. InstitutionSqlServerTests weist beide Schlüsselreihenfolgen nach und hält den
scheiternden Einzelschritt fest. Beide Speicherschritte stehen am Ende von
InstitutionAppService.UpdateAsync; der Wechsel selbst und alle fachlichen Prüfungen laufen
vorher im Speicher. Das hat einen Grund über die Ordnung hinaus: ABP hängt die Entity Changes jedes
erfolgreichen SaveChanges sofort an das Audit-Log des Aufrufs, und dieses Audit-Log wird auch bei
einem gescheiterten Aufruf gespeichert. Eine fachliche Abweisung nach einem Speicherschritt rollt
die Fachdaten zurück, hinterließe aber Einträge in der Entity History für Änderungen, die nie
galten (nachgewiesen und festgehalten durch
InstitutionAuditEntityHistorySentinelTests.A_refused_update_leaves_no_entity_history_of_the_rolled_back_swap).
Ein technischer Fehler im zweiten Speicherschritt, etwa eine Zeitüberschreitung, ist davon nicht
erfasst: Dann stehen die Änderungen des ersten Schritts im Protokoll, obwohl sie zurückgerollt
wurden. Das gilt für jeden Anwendungsfall mit mehreren Speicherschritten in einer Unit of Work. Weich gelöschte Zeilen bleiben durch den Filter außen vor. Der
bestehende Index über (InstitutionId, SortOrder) bleibt unverändert.
Die Migration AddInstitutionContactDefaultPhoneDeputy legt die Spalten an und übernimmt den
Bestand nach A6, bevor sie den gefilterten Index erzeugt: Je Institution ohne gesetzten Standard
wird der bisher abgeleitete Standard gekennzeichnet — der erste aktive, nicht gelöschte Kontakt
nach Reihenfolge, Nachname, Vorname, mit der ID als deterministischem Gleichstandsentscheid.
Institutionen ohne aktiven Kontakt erhalten keinen Standard; weich gelöschte Zeilen gewinnen nie.
Das UPDATE ist wiederholbar, weil es nur greift, wo noch kein Standard steht. Down() entfernt
Index, Fremdschlüssel und Spalten.
Dieselbe Migration bringt die Telefonnummer Phone (nvarchar(64) NULL, A2: keine
Formatprüfung, kein Index) und die drei Vertretungsspalten aus AC-7: DeputyContactId als
Selbstbezug auf RALQMInstitutionContacts — innerhalb des Moduls und deshalb, anders als die
ID-only-Spalten über Modulgrenzen, ein echter Fremdschlüssel mit DeleteBehavior.Restrict. Er
greift nur bei harten Löschungen (HardDeleteAsync, Purge): Kontakte werden weich gelöscht,
RemoveContact setzt IsDeleted, und die Regel aus A5, dass ein als Vertretung eingetragener
Kontakt nicht entfernt werden kann, ist eine Aggregatregel in Institution.RemoveContact —
sowie DeputyFromUtc und DeputyUntilUtc als nullable datetime2 in UTC (A10; offenes Ende =
NULL). Sie sind bewusst DateTime wie die Fristen in HearingDeadlineRule, deren
Kalenderdatumsvergleich A10 vorschreibt, und keine DateOnly-Spalten nach C-07, damit die Story
keine zweite Zeitsemantik einführt.
Die Entity History (RALQMInstitutionsEntityHistory) erfasst die neuen Spalten wie die übrigen
Kontaktfelder; anders als bei der internen Notiz ist nichts ausgenommen.
Kontakte entfernen als Soft Delete (RAL-QM-HP-9)
RAL-QM-HP-9 (A5) entfernt Kontakte als
Soft Delete: Institution.RemoveContact setzt über InstitutionContact.MarkAsRemoved das
ABP-Kennzeichen IsDeleted und lässt den Kontakt in der Sammlung des Aggregats. Herausgenommen
wäre er ein verwaister Pflichtabhängiger, den EF Core unter DeleteBehavior.Restrict nicht
löschen darf; der Aufruf scheiterte, bevor ABPs Soft Delete greifen konnte („association … has
been severed“). Die Beziehung bleibt deshalb Restrict, ohne Modelländerung und ohne Migration.
Das Speichern schreibt ein UPDATE der Zeile, ABP setzt DeletionTime und DeleterId und führt
die Änderung in der Entity History als Löschung.
Institution.Contacts und jede Kontaktregel des Aggregats blenden entfernte Kontakte aus; nur
die Prüfung auf doppelte Kontakt-IDs sieht alle Zeilen. Spätere Ladevorgänge und EF-Abfragen über
die Navigation hält ABPs Query-Filter frei.
Eine entfernte Zeile ändert nur IsDeleted. Der Grund ist eine Eigenheit von ABP 10.6: Leert der
Speichervorgang, der die Zeile löscht, auch den selbstbezogenen Schlüssel DeputyContactId,
erkennt EF Core diesen als erste Änderung; ABP hält die Zeile dann für eine reine
Fremdschlüssel-Änderung und setzt weder DeletionTime noch DeleterId. Deshalb leert das
Entfernen den Vertreter-Eintrag nicht. Werden ein Kontakt und seine Vertretung oder zwei einander
vertretende Kontakte im selben Aufruf entfernt, zählen ihre Einträge für die Regel aus A5 nicht,
in jeder Reihenfolge; die Einträge bleiben wirkungslos an den entfernten Zeilen stehen. Ein
Vertreter, der für einen bleibenden Kontakt eingetragen ist, bleibt unentfernbar.
Nachweis auf SQL Server: InstitutionAuthorizationPipelineTests (Removing_*,
A_removed_contact_is_no_longer_found_by_the_deputy_reader) und
InstitutionAuditEntityHistorySentinelTests.Removing_a_contact_is_recorded_in_the_entity_history.
Stellungnahme in einem Aufruf (RAL-QM-HP-38)
RAL-QM-HP-38 speichert Antwort, Anlagen, Verlauf und Beteiligungsstand einer Stellungnahme in einer Serializable-Transaktion, die erst nach dem vollständigen Lesen der Dateien beginnt (Ablauf in Laufzeitsicht §6.4). Drei Persistenzregeln folgen daraus:
- Reservierung und eindeutige Folge. Seit RAL-QM-HP-40 reserviert der Portal-Schreibweg zuerst die Teilnehmerzeile, bevor er vorhandene Antworten und die nächste Sequenz liest. Dadurch werden zwei Schreiber derselben Teilnahme geordnet. Erstabgabe und interne Erfassung verlangen eine leere Folge; eine Ergänzung verlangt einen Vorgänger. Der frühere Einzelantwortindex wird auf Sequenz 1 begrenzt und schützt damit auch die interne Erstaufnahme. Die positive Sequenz und die Auftragskennung bleiben eindeutig. Dieselbe Kennung mit gleichem Akteur und Inhalt liefert die schon gespeicherte Abgabe, bei Abweichung einen Operationskonflikt. Die vollständige Zugangs-, Status- und Fristprüfung bleibt auch vor der Wiederholung erforderlich. Historische Antworten ohne Auftragskennung erlauben keine behauptete Wiederholung.
- Wiederholung bei Deadlock. Die Speicherphase läuft in einer eigenen Unit of Work
(
HearingPortalWriteTransaction,requiresNew). Wählt SQL Server sie als Opfer (Fehler 1205 in der Ausnahmekette, die EF Core inDbUpdateExceptionund zuweilenInvalidOperationExceptionhüllt –SqlServerDeadlockVictim), wiederholtHearingResponseStorageRetrysie bis zu zweimal mit den bereits gelesenen Dateien; kein anderer Fehler wird wiederholt, und die interne Erfassung wiederholt nichts. Die verbleibenden Sperren, die eine Wiederholung nötig machen, stehen in Risiken. - Festschreibung statt Anlagenänderung. Neue Dateien dürfen nur während der atomaren Erstellung ihrem neuen Beitrag zugeordnet werden. Nach dessen Festschreibung werden Änderungen, zusätzliche Anlagen sowie weiche und harte Löschung auf dem Persistenzpfad abgewiesen. Das gilt auch für interne Aufrufer. Bescheidtexte bleiben eigene Objekte. Frühere weich gelöschte Zuordnungen werden weder entfernt noch wiederhergestellt; ihre Dateien bleiben unter dem Retention-Schutz und über den Portal-Abruf unerreichbar.
Nachweise auf SQL Server: HearingResponseSubmissionSqlServerTests (ein Aufruf, Rollback, Grenzen,
fremde IDs, unveränderte Vorgänger, Sequenzvergabe und Auftragswiederholung, erzwungene Blockade
mit Wiederholung) und HearingResponseKindMigrationSqlServerTests (umgeschriebene Kategoriewerte).
Eingangsbestätigung und Referentenhinweis (RAL-QM-HP-35)
RAL-QM-HP-35 ergänzt RALQMHearingResponseAttachments um Sha256
(nchar(64), Kleinbuchstaben-Hex der übernommenen Bytes, NULL für Altanlagen – keine nachträgliche
Prüfsumme) und führt RALQMHearingResponseNotifications ein (Migration AddHearingResponseNotifications):
je Antwort und Empfängerart (Institution 10, ResponsibleCaseOfficer 20) ein Auftrag, eindeutig über
den gefilterten Index IX_RALQMHearingResponseNotifications_Response_Audience solange er kein Folgeauftrag
ist, Folgeaufträge eindeutig über PreviousNotificationId. Empfänger werden beim Anlegen eingefroren
(operative Kontaktadresse nach RAL-QM-HP-6, zuständiger Referent nach RAL-QM-HP-8). Lebenszyklus wie der
Freigabe-Benachrichtigungsauftrag aus RAL-QM-HP-25: Anspruch je Versuch, Wiederholung nach
HearingIncidentOptions.NotificationRetrySeconds, Störung unter IncidentSource.Notification, Pause nach
72 Stunden ohne erreichbaren Empfänger, Fortsetzen nur als verknüpfter Folgeauftrag. Die Wartephase
eines Versands ist wie im Postausgang auf StuckAttemptTimeout begrenzt: Ein nicht antwortender
Transport bleibt mit Versuchsnummer beobachtet, der Lauf geht weiter, ein spätes Ergebnis gilt nur für
denselben Versuch, nach einer zweiten Frist wird übernommen. Bewusst kein
Postausgangs-Zweck: keine Vorlagenbindung je Verfahren, kein PDF-Begleitschreiben, keine Vertretungskopie.
„Wiederholen“ auf der Störungsseite (Recht Incidents.Retry) stellt einen laufenden Auftrag sofort fällig
oder setzt einen pausierten an die aktuelle Kontaktadresse bzw. den aktuell Zuständigen fort.
Institutionsgruppen: Name, Mitgliedschaft und Revisionszähler (RAL-QM-HP-3)
RAL-QM-HP-3 legt die Tabellen
RALQMInstitutionGroups und RALQMInstitutionGroupMembers an. Drei Festlegungen weichen bewusst
vom Bestand ab:
- Der Name ist eindeutig, nicht nur gewarnt. Verglichen wird mit derselben Regel wie bei den
Institutionen (
InstitutionNameDuplicateRule.Normalize: ohne Leerzeichen, ohne Beachtung der Groß-/Kleinschreibung), aber als gespeicherte SpalteNormalizedName, die das Aggregat beim Benennen mitführt, und mit dem gefilterten eindeutigen IndexIX_RALQMInstitutionGroups_NameUniqueauf[IsDeleted] = 0— Vorbild ist der Standardansprechpartner. Ein Index auf dem Namen allein erkennt „Nord West“ und „NordWest“ nicht als gleich. Nach dem Auflösen ist der Name wieder frei. Die Datenbank vergleicht unter der Spaltensortierung und hält zusätzlich „ß“ und „ss“ für gleich, der Code nicht; beides ist mit eigenen SQL-Tests festgenagelt (InstitutionGroupSqlServerTests). - Die Mitgliedschaft wird hart gelöscht.
InstitutionGroupMemberist eine reineEntity<Guid>ohne Auditfelder, die Beziehung zur Gruppe steht aufCascade— nur so darf EF Core die aus der Sammlung genommene Zeile löschen. Beim Auflösen fallen beide Schritte in einen Speichervorgang: Die Mitgliedschaften verlassen die Sammlung und werden gelöscht, die Gruppe wird weich gelöscht. Dass die Entity History danach die Löschung der Gruppe und je Mitgliedschaft einen Eintrag mit Gruppe und Institution enthält, hältInstitutionGroupAuditEntityHistorySentinelTests.Dissolving_records_the_group_deletion_and_every_membership_with_its_institutiongegen die migrierte Datenbank fest — das ist die Bedingung, unter der das harte Löschen zulässig ist. Das ist die Gegenrichtung zu Kontakte entfernen und erlaubt, weil die Zeile außer den zwei Verweisen keinen Inhalt trägt: Gruppe und Mitgliedschaft stehen im SelektorRALQMInstitutionsEntityHistory, der beim harten Löschen die Werte mitschreibt. Die Institution wird als echter Fremdschlüssel mitRestrictreferenziert (modulintern); weil Institutionen weich gelöscht werden, behält eine gelöschte Institution ihre Mitgliedschaftszeile und fällt nur aus den Lesewegen. - Ein Revisionszähler macht Mitgliederänderungen an der Gruppe sichtbar.
MutationRevision(MusterFilingArea.MutationRevision) wird bei jeder wirksamen Zuordnung und Entfernung erhöht, damit die Gruppenzeile mitgeschrieben wird und ABP ihren Concurrency-Stamp erneuert. Ohne den Zähler bleibt die Gruppe beim Einfügen einer KindzeileUnchanged— gemessen inInstitutionGroupSqlServerTests.A_member_change_writes_the_group_row_so_that_abp_can_renew_its_stamp; dass ABP den Stempel dann tatsächlich erneuert, hältInstitutionGroupAuthorizationPipelineTests.A_member_change_renews_the_stamp_on_the_real_abp_pathauf dem echten Aufrufweg fest. Das ist die Voraussetzung dafür, dass eine offene Bestätigung zum Auflösen scheitert, wenn inzwischen Mitglieder geändert wurden.
Expand/Contract am Beispiel der Wertelisten
Der Umbau von Enum und Freitext auf Katalogtabellen (ADR-07) ist das Muster für jede Umstellung, die Daten neu verankert: erst erweitern, dann übertragen, in einem späteren Schritt entfernen.
AddValueListslegt die vier TabellenRALQMMarkTypes,RALQMProcedureTypes,RALQMCountriesundRALQMContactFunctionsan, ergänzt die vier Id-Spalten anRALQMHearings,RALQMInstitutionsundRALQMInstitutionContacts, spielt den Katalog ein und überträgt den Altbestand: Enum-Werte werden auf feste Seed-Kennungen abgebildet, Freitext-Länder per normalisiertem Namensabgleich zugeordnet (nicht Zuordenbares wird als inaktive Ausprägung angelegt, statt es zu verlieren), Positionstexte werden zu Ausprägungen der Funktionsliste. Im selben Schritt wird der globale Setting-Wert der zweiten Rückmeldefrist von „28 Tage nach der ersten“ auf den kumulativen Wert umgerechnet. Die alten Spalten bleiben dabei stehen.- Erst spätere Migrationen entfernen sie:
DropHearingLegacyTypeColumnsdie beiden int-Spalten aufRALQMHearings,DropInstitutionLegacyTextColumnsdie FreitextspaltenCountryundPosition.
Alle drei Migrationen prüfen, ob noch eine Zeile ohne Wertelisten-Bezug übrig ist, und brechen in
diesem Fall mit THROW 51660 innerhalb der Migrationstransaktion ab — bei den beiden
Entfernungsschritten vor dem DROP COLUMN, sodass kein nicht abgebildeter Wert vernichtet
wird, sondern der Rollout stehen bleibt. Die Datenübertragung ist bis auf eine Ausnahme wiederholbar
geschrieben (Einfügungen IF NOT EXISTS, Backfills nur auf noch unbesetzten Zeilen): Die
Setting-Umrechnung ist eine Rechnung und würde bei einem zweiten Lauf doppelt addieren; sie ist
allein durch __EFMigrationsHistory geschützt und in der Migration entsprechend vermerkt.
Die Seed-Kennungen dieser Migration sind ein Vertrag (ValueListSeedIds) — Demo-Daten und
Tests referenzieren sie; ein geänderter Wert bricht sie und entkoppelt Bestandszeilen von ihrem
Katalogeintrag. Wertelistenpflege ist außerdem in der ABP Entity History erfasst
(RALQMValueListsEntityHistory), damit nachvollziehbar bleibt, wer eine Ausprägung umbenannt oder
deaktiviert hat.
Fassungskatalog und Zustimmungsnachweise (RAL-QM-HP-39)
RALQMConsentDocumentVersions und RALQMConsentProofs sind reine Einfügetabellen; ein
SaveChanges-Schutz weist Ändern und Löschen beider Typen ab. Die Fassungen tragen je Art eine
laufende Nummer mit eindeutigem Index (Art, Nummer). Gültig zum Zeitpunkt T ist die Fassung mit der
höchsten Nummer unter allen mit „gültig ab ≤ T“; Rückdatieren ist ausgeschlossen, deshalb ändert
eine neue Veröffentlichung nie, welche Fassung zu einem vergangenen Zeitpunkt galt. Veröffentlicht
wird in einer serialisierbaren Transaktion gegen die zuletzt gesehene Nummer; eine veraltete
Ansicht oder ein gleichzeitiger Publisher endet im Konflikt statt in zwei gültigen Fassungen.
Nachweise sind über gefilterte eindeutige Indizes begrenzt: je Konto ein Aktivierungsnachweis
([Purpose] = 1), je Abgabe ein Nachweis ([SubjectId] IS NOT NULL). Der Abgabenachweis wird im
Abgabeabschluss von Hearings in die umgebende Unit of Work geschrieben, also in dieselbe
serialisierbare Transaktion wie Antwort und Verlauf. Über die Modulgrenze stehen nur Kennungen
(UserId, HearingResponseId), keine Foreign Keys.
Speicherinventar und Wiederanlauf (RAL-QM-HP-65)
Filing besitzt FilingStorageContextState, FilingStorageInventoryRun,
FilingStorageInventoryItem und FilingStorageFinding. Die Tabellen halten ausschließlich
Generation, Revisionen, Cursor, technische IDs, Längen und Befundkategorien; keine aktuellen
Dateinamen, Pfade, Eigentümer oder Inhalte. CAF Documents liefert über den lesenden
IDocumentStorageInventoryPort Descriptor- und Inhaltsseiten des eigenen Containers.
Hearings inventarisiert seine aktiven, entfernten und historischen Unterlagen, Antworten,
Postausgangsdateien und Rundnachrichten über IHearingStorageReferenceInventory; Filing liest
keine Hearings- oder CAF-Tabelle.
IHearingStorageTrashFacts liefert der unabhängig autorisierten Speicheradministration
zusätzlich höchstens 500 technische Papierkorbfakten je Cursorseite. Hearings entscheidet
Verfahrens-, Referenz-, Grants- und native Ordnerschutzregeln selbst; ausgegeben werden nur
Dokumentkennung, Fristbasis, Schutzende, Beobachtungsstand und Schutz-/Auftragskennzeichen.
Namen, Pfade, Eigentümer und Verfahrenskennungen verlassen diesen Port nicht. Cursorseiten
sind lesende Beobachtungen; sie erteilen weder Fachzugriff noch eine Löschfreigabe.
Der regelmäßige Worker und der manuelle Start verwenden denselben Runner. Jeder Aufruf
schreibt höchstens eine Portion von 128 Ausgangszeilen, aktualisiert die persistierten Cursor
und hält den externen Inspektionslease bis zum SQL-Commit. Standardintervall ist 24 Stunden
(Filing:StorageInventory:Interval, validiert 1 Minute bis 30 Tage); laufende Portionen werden
alle zehn Sekunden fortgesetzt. Inhaltsrevisionen und Längen werden in einem zweiten Durchgang
nachgelesen, anschließend die Descriptoren. Mutationen erhöhen in ihrer bestehenden UoW die
Kontextrevision; ein dabei veralteter Lauf wird entwertet. Ohne aktivierte externe Generation
und durchgängige Mutationsüberwachung gibt es keinen aktuellen Vollerfolg.
Auch die lesende Fortschrittsanzeige vergleicht die externe Generation vor und nach ihren SQL-Lesungen mit Run und Kontext. Ein früherer vollständiger Lauf bleibt nach Rotation, fehlendem Aktivierungsmarker oder defektem Zustand sichtbar, gilt aber nicht mehr als aktuell. Die Beobachtung erwirbt keine weitere Sperre und funktioniert unter bereits gehaltenem Mutations- oder Inspektionslease; sie erteilt keine Freigabe oder Löschberechtigung.
Auch ein mit Enabled=false gestarteter Host hält bei konfiguriertem absolutem
Zustandspfad den externen .lock bis zum Ende seiner Mutation. Die Erstinitialisierung
wartet auf dieselbe Sperre und persistiert darunter zuerst den dauerhaften .activated-
Marker, dann die gesperrte Generation. Bereits gestartete deaktivierte Hosts weisen danach
Mutation, Inspektion und Zustandslesen ab; Zustand oder Aktivierungsmarker allein genügen.
Eine bloße .lock-Datei ist keine Aktivierung. Ein fehlender Zustand bei vorhandenem Marker
bleibt gesperrt und darf nicht mit einer neuen leeren Generation überschrieben werden.
Nur eine vollständig unkonfigurierte Modulinstanz ohne Zustandspfad verwendet einen No-op-Lease.
Globale unprüfbare Bestände sperren den Kontext, eingrenzbare Befunde nur die betroffenen
Löschungen. Ein neuer vollständiger Abgleich kann frühere Befunde ersetzen; Quittieren oder
Neuladen hebt keine Sperre auf. Fehlende Bytes gelten nur bei passendem eigenen Purge-Operations-
und Historiennachweis als erwartete Entfernung. Nach betrieblicher Wiederherstellung bleibt die
außerhalb der Datenbank geführte Generation maßgeblich. Freigabe verlangt einen aktuellen
vollständigen Lauf ohne ungeprüfte Abdeckung oder offene Befunde und bindet dessen Revision.
Vor Löschauftrag und Vollzug liest der DeletionGuard die ausgewählten Descriptoren und
tatsächlichen Inhalte zweimal unter der vorhandenen Mutationslease. Fehlende/mehrfache
Zuordnung, falsche Länge, fremde Speicheridentität oder ein Revisionswechsel blockieren den
Aufruf. Ein dabei neu entdeckter Befund wird vor der Abweisung in einer eigenen Transaktion
festgeschrieben, ohne die bereits gesperrte Kontextzeile zu lesen oder zu verändern. Der
Fachrollback entfernt diesen Befund nicht. Vor dieser Probe hält die äußere Transaktion
keine Befund-Lesesperre; die globale Eintrittsprüfung schließt ihre eigene lesende UoW ab.
Ein unbekanntes historisches Schutzende ist kein Inhaltsfehler: Die Fristpolicy verlangt
dafür ihre konservative volle neue Beobachtungsfrist. Eine leere Schutzrevision bedeutet
hingegen eine nicht verifizierbare Beobachtung und erlaubt weder Vollerfolg noch Löschung.
Prüflauflesen, Start und Freigabe sind getrennte Produktadministrationsrechte unter
RALQM.Filing.Storage; die Seite liegt unter /administration/speicher/prueflaeufe.
AC13 protokolliert den ausdrücklichen Befundabruf über ABPs AlwaysLogSelectors: Die
Auswahl bindet exakt FilingStorageInventoryAppService.GetFindingsAsync, keine fremde
Serviceidentität oder allgemeine Get-Namensregel. Der native Interceptor erzeugt bei Bedarf
seinen eigenen Audit-Scope und übergibt Akteur, UTC, Aktion und technische Run-/Filter-/
Pagingparameter dem AuditStore. Ergebnisse, private Namen, Pfade und Inhaltsbytes sind keine
Auditparameter; ABP ersetzt den CancellationToken-Wert bereits durch null. Start, Fortsetzung
und Freigabe behalten ihr natives Schreibaktionsaudit; der dauerhafte Freigabeakteur steht
zusätzlich am Run. Häufiges GetProgressAsync-Polling bleibt unter der unveränderten
GET-Policy und erzeugt keinen Auditdatensatz je Poll. Autorisierung und frische Eignung werden
dadurch weder ersetzt noch erweitert. Der echte Proxy-/RecordingStore-Nachweis prüft den
Store-Dispatch ohne äußeren Audit-Scope; er behauptet keine zusätzliche SQL-AuditStore-Probe.
Verarbeitungsinventar der Speicherverwaltung
| Daten / Zweck | Speicherort und Empfänger | Aufbewahrung / Grenze |
|---|---|---|
| Zentrale Dauer, Aktivierungsstand, erste Aktivierung und Revision; unveränderlicher Änderungsnachweis mit Actor-ID, Operations-ID und UTC-Zeit | Eigene Filing-Policy-/Änderungstabellen in der App-Datenbank; aktuell geeignete Produktadministration mit getrenntem Policyrecht | Ausgangsdauer 90 Tage, technisch 1–3650 Tage konfigurierbar; Automatik zunächst aus. Inhalts-Purge entfernt keine Policy-/Änderungshistorie. Eine Änderung der Dauer behauptet keine gesetzliche Frist. |
| Fristbasis, Schutzbeobachtung, Auftragsursache, gebuchter Termin und gegebenenfalls manuelles Vorziehen | Jeweils Filing- beziehungsweise Hearings-eigene Zeile und Historie; Fachansichten prüfen weiterhin eigene/gemeinsame Bereiche und Verfahrensrechte | Restore setzt die Fristgeneration zurück. Inhalt verschwindet erst nach tatsächlichem erlaubtem Purge; Referenz und eigener Operations-/Verlaufsnachweis bleiben erhalten. Keine zusätzlichen privaten Dateimetadatenkopien. |
| Prüflauf, Generation, Cursor, technische Referenz-/Inhaltskennungen, Revision, Länge und Befundart | Eigene Filing-Kontext-/Run-/Item-/Findingtabellen; reine technische Administrationsansicht unter Storage.Read | Historische Prüfläufe/Befunde werden nicht automatisch gelöscht; behobene Befunde werden beim passenden neuen Vollabgleich geschlossen. Keine Namen, Pfade, Eigentümer oder Inhaltsbytes. Existenz und Länge belegen keine Byteidentität. |
| Ausdrückliche Freigabeautorisierung mit Actor-ID und UTC-Zeit | Am vollständigen Prüflauf; getrenntes Storage.Release und frische Produktadmin-Eignung | Bleibt als Autorisierungsnachweis erhalten. Ein Versuch ist keine Behauptung erfolgreichen externen Release; dessen aktuelle Bindung wird separat geprüft. |
| Kontextkennung, neue Generation und exakt freigegebener Run/Revision | Kanonische externe Generationsdatei, .activated und .lock im app-eigenen Betriebsverzeichnis; ausschließlich App- und befugte Betriebskonten |
Außerhalb von DB-/Inhalts-Restore erhalten. Fehlender oder beschädigter aktivierter Zustand sperrt statt Rückfall. Keine Nutzerprofile oder Dokumentinhalte. |
Kapazitätsmessung und Bestandsinventar sprechen ausschließlich den belegten App-SQL-/
Dateisystemspeicher an. Neue Seiten verwenden vorhandene In-Process-Dienste; es entstehen
keine Drittanfragen, Cookies, localStorage- oder sessionStorage-Einträge. Fehleransichten
geben keine Providertexte weiter. Der technische Befund ersetzt weder den von RAL zu
formulierenden Aufbewahrungshinweis noch dessen tatsächliche rechtliche Freigabe; dieser
externe Nachweis bleibt in HP65 unter DOD-PRIV-04 ausdrücklich offen.
Verarbeitungsinventar für Zustellmeldungen und Rundnachrichten
Technischer Abgleich vom 19.10.2026 für HP76/77. Die Tabelle beschreibt den Codebestand, keine rechtliche Freigabe und keine Frist. Bereits entschieden sind RAL als Verantwortlicher, Offlimits für Hosting, Keycloak und Mailversand sowie der unterzeichnete AV-Vertrag (HP67 O2/O6/O16). Offen sind Aufbewahrung und Hinweise sowie tatsächliche Betriebszugriffe, Speicher-/Backuporte und der in O6 nicht ausdrücklich benannte Betreiber des Rückläuferpostfachs. Bis dahin sind PRIV-01/03/04 nicht abgeschlossen; die gemeinsame Zuarbeit steht in HP67 §8.3.
| Entität | Eigene gespeicherte Felder / Datenkategorien | Zweck | Speicher | Zugriff / Empfänger | Aufbewahrung |
|---|---|---|---|---|---|
HearingDeliveryReport |
ExternalReference, ReceivedAtUtc, Sender, Subject, Reason, StatusCode, OutboxMessageId, ResolvedAtUtc, ResolvedByUserId, ResolutionNote: Rückläuferreferenz/Eingang, Absender/Betreff, klassifizierter Grund/Status, mögliche Versandzuordnung und interner Klärungsnachweis |
Nicht sicher zuordenbare Meldungen klären; Referenz verhindert doppelte Verarbeitung | RALQMHearingDeliveryReports in der App-SQL-Datenbank |
Interne Konten mit RALQM.Hearings.DeliveryReports.Review; Referent/Systemadministrator laut Rollenkomposition; keine Portalansicht |
Erledigen setzt Bearbeiter/Zeit/Notiz und löscht nichts. RAL entscheidet Frist oder begründete Aufbewahrung einschließlich Dublettenschutz. |
HearingOutboxBounce |
OutboxMessageId, AttemptNo, ExternalReference, ReasonCode, ReceivedAtUtc: Meldungsreferenz, Versuch, klassifizierter Grund und Zeitpunkt; kein Meldungstext oder Adressfeld |
Empfangene Unzustellbarkeit genau einem Versandversuch zuordnen, verspätete und wiederholte Meldungen unterscheiden | RALQMHearingOutboxBounces in der App-SQL-Datenbank |
Versandstatus über die jeweils berechtigten Hearings-/Rundnachrichtendienste, Verarbeitung durch den Hintergrunddienst | Append-only-Verlauf; keine automatische Löschung. RAL entscheidet mit dem Outbox-/Verfahrensnachweis. |
HearingCircular |
InstitutionGroupId, GroupName, CultureName, Subject, Body, TextsJson, SourceTemplateId, SourceTemplateRevision, Status, SentAtUtc, SentByUserId, RecipientCount, AttachmentsJson, SkippedJson: Gruppe, Textfassung der Standardsprache und Texte weiterer Sprachen (TextsJson, RAL-QM-HP-101)/Vorlagenherkunft, Sendemarkierung/Akteur/Zahl, Dokument-IDs/Dateinamen und übersprungene Institutionen/Gründe |
Verfahrensfreie Rundnachricht vorbereiten und einmalig mit eingefrorenem Stand versenden | RALQMHearingCirculars in der App-SQL-Datenbank |
Interne Konten mit RALQM.Hearings.Circulars (Referent/Systemadministrator); Nachrichtentext und Dateien an ausgewählte gültige Standardkontakte/Vertretungen, jeweils als Einzelmail |
Verwerfen löscht Anhanginhalt transaktional und setzt Soft Delete; versandter Wortlaut unveränderlich. RAL entscheidet Fristen für Soft-Delete-Reste, Serien und Nachweise. |
Alle drei Aggregate besitzen zusätzlich die ABP-ID, Concurrency-/ExtraProperties und Erstellungsmetadaten (Zeit und optionale Actor-ID). Rundnachrichten besitzen außerdem Änderungs- und Soft-Delete-Metadaten. Diese technischen Angaben bleiben in derselben Datenbank und haben dieselbe Zugriffs-/Aufbewahrungsgrenze; sie sind keine separaten Empfänger.
- Aktionsaudit:
AbpAuditLogs/AbpAuditLogActionsspeichern zusätzlich Benutzer, Zeitpunkt, Dienst/Methode und technische Eingaben wie Meldungs-ID und gelesenen Stempel. Der Zugriff folgtAuditLogging.AuditLogs, nicht dem Klärungsrecht. Der Klärungsvermerk bleibt ausschließlich anHearingDeliveryReport.ResolutionNote: Seit der Korrektur vom 19.10.2026 schließt[DisableAuditing]die EingabeNoteaus den Aktionsparametern aus. Eine echte ABP-/SQL-Probe prüft die weiterhin gespeicherte Fachnotiz und Auditaktion ohne Freitextkopie. Vor der Korrektur konnten Notizen zusätzlich inParametersstehen; bestehende Auditdaten werden nicht verändert. RAL muss deren Aufbewahrung mitentscheiden. - Betriebslogs des Rückläufereingangs: Nur interne Meldungs-/Outbox-IDs, Versuchsnummer, IMAP-UID, klassifizierter Grund/Ergebnis und Exception-Typ werden protokolliert. Externe Message-IDs, Meldungsfelder sowie Exception- und InnerException-Inhalte bleiben ausgeschlossen, auch bei Abruf- und Disconnectfehlern. Vor dieser Nachprüfung konnten externe Message-IDs und rohe Providerfehler in Logs stehen; bestehende Logs/Backups werden nicht bereinigt und gehören in die noch zu bestätigende Betriebsaufbewahrung. Die Dublettenreferenz bleibt unverändert in den geschützten Fachdatensätzen, damit bestehende Meldungen nicht erneut wirken.
- Postfach:
ImapHearingDeliveryReportMailboxliest vollständige Rückläufer/Antworten temporär als Bytes (bisMaxReportBytes) und verschiebt sie erst nach dem DB-Commit vonFoldernachProcessedFolder. Dort bleiben vollständiger Meldungstext, Header und gegebenenfalls zitierte Originalinhalte beim Postfachbetreiber erhalten. Das Verschieben ist keine Löschung. Betreiber, weitere Zugriffe, Ort und Frist muss RAL-Betrieb bestätigen. Die App speichert aus der Meldung ausschließlich die oben genannten Klärungsfelder; der Parser übernimmt weder vollständigen Meldungstext noch die DSN-Empfängeradresse.StatusCodeübernimmt nur den numerischen erweiterten Status nach RFC 3463 §2, ohne Providerkommentar; ungültige Werte bleiben leer beziehungsweise verwenden bei zugeordneten Bounces den vorhandenen neutralen Fehlercode. Absender und Betreff sind die ausdrücklich gewählten Klärungsfelder, keine aus dem Status abgeleiteten Personendaten. - Outbox und Betriebsnachweise:
HearingOutboxMessagehält pro Einzelmail Empfängeradresse, Institutions-/Kontakt-/Vertretungsstand, Betreff/Körper (vorbereitet und tatsächlich gesendet), Kontext-ID, Versuch, Sendestatus und Bounce-Zuordnung fest.HearingSendAttempt, der Verfahrensverlauf undHearingIncidentergänzen technische IDs, Zeitpunkte, Versuch und Fehlerklassen; keine rohe Providerexception oder zusätzliche Meldungsinhalte im Log. Zugriff bleibt bei den jeweiligen Versand-/Outbox-/Störungsrechten. Offene Retries dürfen durch eine spätere Löschregel nicht ihren eingefrorenen Stand verlieren. RAL entscheidet Aufbewahrung gemeinsam mit den obigen Daten; derzeit kein automatischer Ablauf. - Anhänge: Originalbytes und Descriptor-Metadaten liegen über den CAF-Port in ABP File Management auf dem transaktionalen Datenbank-BLOB-Provider. Die Rundnachricht speichert nur IDs und Dateinamen. Upload prüft den Scan, Versand verlangt Clean. Entwurf verwerfen bzw. Anhang entfernen entfernt die zugehörigen Bytes transaktional; für bereits versandte Serien fehlt die von RAL bestätigte Frist unter Erhalt bestehender Referenzen.
- Transport/Empfänger: SMTP erhält pro Nachricht genau Haupt- oder Vertretungsempfänger, Text und Anhänge; keine gemeinsame CC-/BCC-Liste. Ein Retry benutzt denselben eingefrorenen Wortlaut und dieselbe Adresse. SMTP und IMAP sind serverseitige Verbindungen zum konfigurierten Betreiber, keine Browser-Drittanfragen. Für den Mailversand gilt Offlimits (O6); konkrete RAL-Transportkonfiguration und Betreiber des dedizierten IMAP-Postfachs sind noch nachzuweisen, ohne die bereits bestätigte AV-Grundlage erneut zur Entscheidung zu stellen.
- Browser-Speicher: Beide Seiten verwenden bestehende authentifizierte Interactive-Server- Aufrufe und legen keine neuen Cookies, localStorage- oder sessionStorage-Einträge an. Das Cookie-Inventar bleibt HP67 §3. Der technische Origin-Nachweis steht in den HP76/77-DoD-Einzelbewertungen.
MessagingPrivacyInventoryTests gleicht die gesetzten Entitätsfelder und die drei
Tabellenspeicher mit dieser Tabelle ab und hält die separaten Postfach-/Outbox-/Anhang-
Speicher sichtbar. Die Registrierung dieses Kapitels als HP-gateInputs stellt sicher,
dass eine Änderung am Inventar den prüfenden App-Gate auswählt. Der Test ersetzt nicht die
RAL-Entscheidungen zu Aufbewahrung und Betroffenenhinweisen.
3. Persistierte Kennungen
Zwei getrennte Präfixräume, konsequent nach Ownership:
| Präfix | Geltungsbereich | Beispiele |
|---|---|---|
RALQM |
anwendungsspezifisch (Gütezeichen-Anhörungsportal) | Tabellen RALQMHearings, RALQMInstitutions; Permission-Gruppe RALQM; Fehlercode-Namespace RALQM.<Feature>:…; Rollen RALQMAdministrator, RALQMCaseOfficer, RALQMManagement; Lokalisierungsressourcen RALQMHearings, RALQMInstitutions |
CAF |
wiederverwendbare, anwendungsneutrale CAF-Module | Tabelle CAFDocumentShareGrants (CAF.Modules.Documents) |
Technische Slugs (URLs, Docker-/Config-Bezeichner) bleiben bewusst kleingeschrieben, zum Beispiel
ral-qualitymarks, und folgen nicht dem Groß-Präfix der persistierten Kennungen. Projekt- und
Namespace-Namen (CAF.Applications.RAL.QualityMarks.HearingPortal.*) sind von dieser Konvention
unabhängig und ändern sich durch die Umbenennung nicht.
Diese Trennung ist mehr als Namenskosmetik: Sie macht Ownership beim Lesen einer Tabelle, eines
Fehlercodes oder einer Permission sofort erkennbar, ohne den Quellcode zu öffnen, und verhindert,
dass ein wiederverwendbares CAF-Modul unbemerkt anwendungsspezifisches Wissen aufnimmt (siehe
Bausteinsicht zur Modulgrenze CAF.* → HearingPortal.* verboten).
4. Lokalisierung
- UI-Texte sind Deutsch (
de-DEals führende Kultur), Code-Identifier und Kommentare Englisch, Logs strukturiert/Englisch. - Sprachen der Anwendung und Standardsprache stammen aus der Sprachverwaltung (
ILanguageProvider, EinstellungAbp.Localization.DefaultLanguage); Hearings löst sie zentral überHearingLanguagesauf und rechnet Kulturnamen nicht um (RAL-QM-HP-101, siehe Kommunikationssprache je Empfänger). - Jedes Feature-Contracts-Projekt besitzt seine eigene Lokalisierungsressource und DE/EN-JSON,
zum Beispiel
HearingPortal.Authorization.Contracts/Localization/Authorization/{de-DE,en}.json. DE- und EN-Schlüssel müssen in beide Richtungen übereinstimmen; hart codierte UI- oder Business-Exception-Texte sind verboten. - Fehlercode-Namespaces folgen demselben
RALQM.<Feature>:-Schema wie die Fehlercodes selbst und werden perAbpExceptionLocalizationOptions.MapCodeNamespacean die Ressource des jeweiligen Feature-Contracts-Projekts gebunden (sieheHearingPortalAuthorizationContractsModule.ConfigureServices:MapCodeNamespace("RALQM.Authorization", typeof(HearingPortalAuthorizationResource))). Ein Fehlercode wieRALQM.Authorization:StaffAccounts:ConcurrencyConflictlöst damit automatisch den passenden lokalisierten Text auf. - ABP Language Management liefert den datenbankgestützten Sprach-/Textprovider im Betrieb.
Einen Cookie-Hinweis gibt es nicht (O8 der
Datenschutz-Spec, entschieden
2026-10-01): ABPs Cookie-Einwilligung wird nicht registriert (
AbpCookieConsentOptions.IsEnabledbleibt falsch), keines der beiden Layouts bindet die Hinweiskomponente des UI-Kits ein, undralqm-consentwird nicht gesetzt. Belegt durchShellCompositionTests.No_layout_mounts_the_cookie_notice_and_no_runtime_switch_existsundShellCompositionTests.Shell_registers_each_owned_option_and_menu_contributor_once. - Ausnahme mit klarer Grenze — Wertelisten: Die Anzeigenamen der vier Wertelisten sind
keine Ressourcentexte, sondern Spalten am Datensatz:
NameDeist Pflicht,NameEnoptional, und fehlt das Englische, zeigt auch die englische Oberfläche den deutschen Namen. Grund ist die Herkunft der Texte: Ein Ressourcenschlüssel gehört einem Entwickler, der ihn ausliefert; diese Namen legt ein Administrator zur Laufzeit an und ändert sie, ohne dass jemand etwas ausliefert. Über Language Management wären sie an einem zweiten Ort gelandet, an dem eine neue Ausprägung namenlos bliebe — deshalb dort nicht geführt (Begründung: ADR-07). Unverändert lokalisiert bleibt alles um die Werte herum: Beschriftungen und Hinweise der Pflegeseite, die Namen der Listen selbst und die Fehlercodes unterRALQM.ValueLists:. Die früheren SchlüsselHearings:MarkType:*undHearings:ProcedureType:*sind entfallen.
5. UI- und Cohesion-Grenzen
- Eigene CAF-/GZ-Oberflächen rendern ausschließlich Cohesion (Syncfusion); MudBlazor,
Syncfusion-Rohkomponenten oder Blazorise dürfen von Fachcode nicht direkt verwendet werden.
Ausgenommen sind allein die MVC-Razor-Pages unter
/Account/**auf dem LeptonX-MVC-Theme. Blazor-seitig gibt es keine Ausnahme mehr; die ABP-Administrationsansichten sind Produktseiten, und weder einMudBlazor- noch ein Blazor-LeptonX-Paket ist noch referenziert. Blazorise gelangt transitiv ueber ABPs Blazor-Theming-Paket in den Graphen - gerendert wird davon nichts, und seine Stylesheets werden aus dem globalen Bundle entfernt. CAF.Modules.UI.Blazorregistriert Cohesion, Lizenzprüfung, Assets/Bundles und die Interactive-Server-Policy zentral; es besitzt selbst keine Produktroute.- Feature-Komponenten setzen kein
@rendermodeund bleiben render-mode-neutral; der Host wählt Interactive Server. JavaScript-Interop läuft prerender-sicher erst nach interaktivem Rendern. - Jede datengebundene Oberfläche behandelt, soweit fachlich relevant: Loading, Empty, Error/Retry, Forbidden, Validation, Saving und Stale Concurrency mit Neu-Laden-Option.
- Eine Suche oder ein Neuladen, das die Seite anfordert, während das erste Laden eines Grids
noch läuft, holt Cohesion seit
3.6.3-alpha.0.17nach demCreated-Ereignis einmal nach (UP-57). Die Grid-Adaptoren führen dafür keinen eigenen Lesestand mehr; die ProduktbrückeCAFGridDataAdaptor.CaptureReadStateist am 2026-10-10 entfernt. Gespeicherte Standardansichten fordern nach ihrem Eintreffen weiter selbst ein Laden an. Regel, Grenzen und bUnit-Nachweise: Grid-Muster §15. - WCAG 2.1 AA ist Mindestziel: semantisches HTML, sichtbarer Tastaturfokus, zugeordnete Labels und nicht ausschließlich farbliche Statusanzeige.
Rechtsnavigation und Browser-Speicher (RAL-QM-HP-67)
Der Keycloak-Client des HearingPortals waehlt das app-eigene Login-Theme ralqm-legal.
Es erbt ueber das kundenweite Basistheme ral-v1 die Formulare von keycloak.v2
(RAL-QM-HP-102, ADR-23). Die bestehenden Label-/Control-Korrekturen in template.ftl
und login-config-totp.ftl sowie der native footer.ftl-Hook mit drei lokalisierten
Rechtslinks bleiben app-eigen erhalten. Die absolute Client-BaseUrl bestimmt die Ziele;
Anfrageparameter werden nicht als Rechtsziel verwendet. referrerpolicy="no-referrer"
verhindert die Weitergabe der Anmelde-URL beim Oeffnen. Der Realm-Standard ral-v1 deckt
clientlose Ablaufseiten ab; ohne Clientkontext erscheinen keine geratenen HP-Rechtsziele.
Andere Realms bleiben unveraendert. Lokaler und Kunden-Compose mounten beide Themeverzeichnisse
lesend; die echte Keycloak-Testfixture kopiert beide in ihren eigenen Container.
Der CI-Keycloak-Service liest beide Themes desselben Checkouts ueber den nativen Folder-Provider.
Diese Auslieferungsdefinition ist keine Freigabe oder Durchfuehrung eines Kunden-Deployments.
Ein clientbezogener Login-Footer ersetzt kein realmweit ausgewaehltes E-Mail-Theme.
Die Blazor-Shell behält Rechtslinks in Leiste und Kontomenü. Der Host ergänzt im
MVC-Accountlayout dieselbe lokalisierte Rechtsnavigation und Betreiberangabe über
AbpLayoutHookOptions, LayoutHooks.Body.Last, ausschließlich StandardLayouts.Account.
Er verwendet die vorhandene kompilierte MVC-Partial; die Theme-Layouts werden nicht kopiert.
Der MVC-Skriptbundle setzt nach abp.js und vor der Anwendungskonfiguration
abp.clock.trySetBrowserTimeZoneToCookie = false: das nicht ausgewertete Zeitzonencookie
wird nicht mehr neu angelegt. Die Cookie-Seite und ihre Inventarprüfung bilden dies ab.
Die GDPR-Selbstbedienung beschreibt ausdrücklich nur den lokalen Kontoumfang; eine
vollständige Fachdaten-/Keycloak-Auskunft oder -Löschung wird nicht zugesagt.
Erklärung zur Barrierefreiheit (RAL-QM-HP-79)
Die Shell besitzt /Barrierefreiheit und ihr eingebettetes Register
src/Shell/Legal/known-barriers.json. Die Erklärung verwendet denselben Betreiber wie
das Impressum und die adaptive Rechtsseitenkomposition für anonyme Besucher, interne
Konten und Institutionskonten. Portal-, Anmelde-, Abmelde- und Fehlerlayouts verlinken
dieselbe Route. Semantische Dokumentstruktur bleibt HTML; Bedienelemente folgen Cohesion.
Accessibility:FeedbackEmail, StatementDate und ConformityStatus sind typisierte,
beim Start geprüfte Konfiguration. Fehlende Pflichtangaben verhindern den Start.
Die am 15.10.2026 im Benutzerauftrag ausgewählte Adresse barrierefreiheit@ral.de
steht in der Basisdatei und gilt auch in Development. Einrichtung, Empfang und Betreuung
bleiben als HP79-DEV-04 bis zur betrieblichen Bestätigung offen. Ein Status vollständiger
Konformität ist bei noch vorhandenen Registereinträgen unzulässig.
Jede bekannte Einschränkung hat eine stabile ID, betroffene Wege, Erfassungsdatum,
lokalisierte Beschreibung/Begründung und einen Zeitplan. Die bewusste Entwicklungsabnahme
vom 15.10.2026 lässt diese Einschränkungen offen sichtbar. Sie ist keine Produktionsfreigabe.
BrowserGate prüft die tatsächlich zusammengesetzten kundenseitigen Seiten gegen alle
axe-WCAG-A/AA-Befunde sowie mit Tastatur-/Fokuspfaden. Die technische Prüfausnahmeliste
tests/BrowserGate/a11y-ausnahmen.json bleibt von diesem öffentlichen Register getrennt;
ein Registereintrag macht einen fehlenden Prüflauf nicht erfolgreich.
Bestätigungsdialoge
Zweistufige Entscheidungen folgen einem von zwei Mustern. Festlegung vom 18.09.2026 (Anlass: Review von RAL-QM-HP-5): Bis dahin nannte dieser Abschnitt nur das erste Muster, obwohl die Verfahrensakte ihre Rückfragen seit dem 26.08.2026 nach dem zweiten baut. Das Unterscheidungsmerkmal – gesperrte oder bedienbare Seite – ist damit eine Entscheidung für künftige Oberflächen, keine nachträgliche Beschreibung des Bestands.
Muster 1 – Kit-Bestätigungsdialog, wenn die Seite gesperrt werden soll.
CohesionConfirmDialog-Instanzen im owning .Blazor-Projekt (Stand 18.09.2026: 13 Seiten in
Institutions, Filing, Identity, Gdpr, TextTemplates und Languages – etwa das Löschen einer
Institution und seit RAL-QM-HP-10 die Dublettenwarnung vor dem Speichern und die
Deaktivierungswarnung): Titel, Text und Schaltflächen aus der Feature-Ressource, Visible
einseitig gebunden, die Antwort räumt den auslösenden Zustand als Erstes. Eine Warnung sperrt
nicht — „Trotzdem speichern“ bleibt möglich und ist bewusst nicht die Primäraktion
(SPEC-RAL-QM-HP-10 A1). Nebengrund für diese Komponente: Der Dialog rendert unter bUnit; der
generische CohesionDialog tut das nicht (siehe LanguageTextsPage). Fokus in den Dialog ist
Komponentenfunktion des Kits. Die Rückkehr zum Auslöser leisten drei Institutions-Seiten noch
selbst über ElementFocus in HearingPortal.UI.Blazor (nach Abbrechen und nach der bestätigten
Deaktivierung in der Liste): ein Behelf mit Eintrag im Override-Register des Repositorys
(docs/arc42/02-bausteine.md, nicht im
arc42-Ordner dieser Anwendung), gemessen an 3.6.2-alpha.0.13. Laut Kit-Quelle ist die Ursache
seit 3.6.3-alpha.0.6 behoben; der Browsernachweis für den Rückbau steht aus
(cohesion-upstream.md, UP-23).
Muster 2 – Bereich in der Seite, wenn sie bedienbar bleiben soll. Die Verfahrensakte
(HearingDetailPage) stellt ihre sechs Rückfragen – Abschließen, Stornieren, Abbrechen, Teilnahme
zurückziehen, Unterlage entfernen (RAL-QM-HP-21) und seit RAL-QM-HP-5 Zugang entziehen oder wieder
freigeben – als Bereich an der Stelle der Aktion. Außerhalb der Verfahrensakte fragt nur das eigene
Konto in der Seite zurück (OwnAccountPanel, Signatur entfernen, RAL-QM-HP-89) – dort als
Schaltflächenwechsel an Ort und Stelle, ohne eigenen Bereich. Der Bereich ist role="group" mit
Titel (aria-labelledby), bei Bedarf Frage oder Hinweis (aria-describedby; seit RAL-QM-HP-5 die
Frage des Zugangsentzugs und der Hinweis beim Ausnehmen eines Pflichtpartners), Cohesion-Eingaben
und -Schaltflächen, ohne Backdrop und ohne Fokusfalle: semantisches HTML mit Cohesion-Komponenten
(Zone 1 der Cohesion-Grenze), keine zweite
Dialog-Fassade – und bewusst kein Dialog im ARIA-Sinn, die übrige Seite bleibt lesbar und
bedienbar. Vier der sechs Bereiche tragen ein Eingabefeld (Begründung oder Vermerk) und sind damit
kleine Formulare; „Unterlage entfernen“ und der Zugangsentzug sind reine Ja/Nein-Rückfragen. Den
Fokus führt seit RAL-QM-HP-94 (11.10.2026) jeder dieser Bereiche so wie zuerst der Zugangsentzug: beim
Öffnen auf den Bereich, beim Abbrechen zurück zum Auslöser, nach dem Erfolg auf die Gegenaktion oder,
wo keine bleibt, auf eine Ergebniszeile (#hearing-lifecycle-result, #hearing-document-result); ein
Fehlerfokus geht vor (Zugangsentzug im BrowserGate gemessen, Stufe parallel-sessions; die übrigen
Bereiche in HearingDetailConfirmationFocusTests). Führt ein solcher Bereich den Fokus, dann leistet das die Seite selbst per
id über ElementFocus, weil CohesionButton und CohesionIconButton keine ElementReference
bieten. Das ist reguläre Seitenfunktion und kein Behelf: Es gibt keine Kit-Fokusfalle, die die
Rückgabe übernehmen könnte. So nutzen den Helfer InstitutionGroupAssignPage für ihren
Korb-Umschalter (RAL-QM-HP-3), HearingDetailPage für den Zugangsentzug (RAL-QM-HP-5) und die
übrigen Rückfragen (RAL-QM-HP-94), die Kontaktmeldungs-Panels im Portal und in der Verfahrensakte
(RAL-QM-HP-93, -94), InstitutionBindingPanel, OrganisationLoginPanel, ConsentDocumentsPage und
InstitutionsPage beim CSV-Import (RAL-QM-HP-95) sowie OwnAccountPanel für die Meldung eines
gescheiterten Speicherns (RAL-QM-HP-99).
Die Deaktivierungswarnung (SPEC-RAL-QM-HP-10 AC-10) unterscheidet sich in der Quelle der Frage:
Nicht die Oberfläche fragt vorab, sondern der Anwendungsdienst weist den Wechsel aktiv → inaktiv
ohne Bestätigungskennzeichen ab (RALQM.Institutions:DeactivationRequiresConfirmation, Zahl
der laufenden Verfahren als Exception-Daten), auf beiden Pfaden SetActiveAsync und
UpdateAsync und vor der ersten Mutation. Die Seite erkennt die Abweisung am Fehlercode, stellt
die Frage mit der genannten Zahl und wiederholt den Aufruf mit gesetztem Kennzeichen. So gilt die
Regel auch für jeden Aufrufer ohne Oberfläche; die Zahl stammt vom abgewiesenen Schreibversuch,
der bestätigte Aufruf zählt nicht erneut.
Die Kontaktfrage (RAL-QM-HP-9 AC-5, A7)
folgt demselben Muster mit zwei Unterschieden. Der Dienst stellt sie als letzte Prüfung vor dem
ersten Speicherschritt (E14), und die Abweisung
(RALQM.Institutions:ContactDeactivationRequiresConfirmation) nennt neben der Zahl jeden
betroffenen Kontakt mit seinen Verfahren. Die Maske zeigt genau diesen Stand, nicht den beim
Öffnen gelesenen Nutzungshinweis. „Trotzdem deaktivieren“ ist nicht die Primäraktion. Die
Bestätigung setzt das Kennzeichen nur an den genannten Kontaktzeilen; Abbrechen speichert nichts
und schaltet die genannten Kontakte in der Maske wieder ein. Deaktiviert ein Speichern Institution
und Empfänger zugleich, kommt die Institutionsfrage zuerst, und ihre Antwort reist mit der
Kontaktantwort. InstitutionUiErrorClassifier liest die Abweisung in-process als Vertragsliste und
über den Remote-Proxy als JSON; unbrauchbare Daten ergeben keine Frage. Weitere Kontaktregeln
(Standard, Vertretung, Pflichtpartner-Kennzeichen) nennt die Maske mit ihrem eigenen Text statt des
allgemeinen Speicherfehlers. Den Nutzungshinweis liest die Maske beim Öffnen einmal über
GetContactRunningHearingsAsync; scheitert das, bleibt die Maske benutzbar und zeigt einen
eigenen Hinweis mit Wiederholen.
Dateiauswahl im Portal: ein Feld je Auswahl (RAL-QM-HP-38)
Die Teilnahmeansicht (RAL-QM-HP-38 AC-8) lässt
Anlagen vor dem Absenden hinzufügen und wieder entfernen; gesendet werden sie erst mit der
Stellungnahme, in deren einem Aufruf. Mehrere Auswahlen nacheinander addieren sich. Ein Dateifeld
(InputFile) hält nur die Dateien seiner letzten Auswahl lesbar; deshalb bekommt jede Auswahl,
die Dateien geliefert hat, ein eigenes Feld: Das benutzte bleibt eingebaut, aber hidden – aus
der Anzeige, aus der Tab-Reihenfolge und aus dem Accessibility-Baum –, ein frisches Feld übernimmt
Kennung (participation-attachment-upload), Beschriftung und Hinweis; nach dem Speichern
verschwinden die benutzten Felder. Bei der Auswahl weist die Seite ab, was die Konfiguration
abweist – Dateityp nach den erlaubten Endungen aus der Übersicht, Größe je Datei, Anzahl über die
verbleibenden Plätze –, ohne dass ein Byte gesendet wird. Beim Senden ist die konfigurierte Größe
die Obergrenze jedes Browser-Lesevorgangs, und der Server prüft Typ, Inhalt und Größe erneut. Nach
jeder Abweisung des Servers bleiben Eingaben und gewählte Dateien im Formular; nur die neutrale
Abweisung lädt neu, Stempelkonflikt und ResponseAlreadySubmitted bieten das Neuladen als eigene
Aktion an. Nachweise:
ParticipationPortalUiTests (Several_selections_add_up_and_each_one_keeps_its_own_input_until_the_send,
A_file_of_a_type_the_policy_does_not_accept_is_refused_when_chosen,
A_file_over_the_size_and_a_selection_over_the_count_are_refused_when_chosen).
6. Fehlerbehandlung
Produktfehlerseiten (RAL-QM-HP-80)
Der Host beantwortet leere 403/404/500 von Produktrouten direkt mit einem statischen
ErrorDocument und der gemeinsamen ShellErrorView. Der HTTP-Status bleibt erhalten,
Cache-Control: no-store, private verhindert Zwischenspeicherung; es gibt keinen Redirect
und keinen erneuten Circuit der fehlgeschlagenen Seite. Unbehandelte Ausnahmen vor Beginn
der Antwort verwenden außerhalb von Development dasselbe Dokument mit HTTP 500 und dem
serverseitigen ASP.NET-Request-Identifier. Development behält die Entwickler-Fehlerseite.
Der Fehlerpfad liest ausgelieferte DE/EN-Ressourcen und rendert vorhandene Cohesion-/Portal-
Templates ohne datenbankgestützte Menüs, Profil- oder Language-Management-Abfragen. Die
Institutionsrolle wählt nur das datenfreie Portal-Chrom, nie einen Fachzugriff. /api,
/health, /swagger und /_blazor werden nicht in HTML umgewandelt; MVC-Kontoseiten
behalten ihren separaten ABP-Handler. Der anonyme Darstellungsendpunkt /fehler/{statusCode}
enthält ausschließlich die drei Fehlervorlagen, keine Exception-Auslösung oder Fachdaten.
Im Router verwenden NotFoundPage, Zugriff-abgelehnt-Seite und NotAuthorized dieselbe
Vorlage. Der Fokus liegt auf ihrer einzigen h1, der Rückweg ist ein gewöhnlicher Anker auf
/. Lokalisierte ConnectionStatus-Elemente und circuitunabhängiges Reload begleiten die
Framework-Reconnect-Klassen. Entscheidungen: ADR-13;
Kriterien und Nachweise: SPEC-RAL-QM-HP-80.
Fachliche Fehlerverträge
- User-facing Fehler verwenden stabile, im owning Feature definierte Error Codes nach dem Schema
RALQM.<Feature>:<Bereich>:<Grund>(z. B.RALQM.Authorization:Provisioning:AmbiguousEmail,RALQM.Authorization:StaffAccounts:InvalidRole) statt Klartext oder generischer Exceptions. - Jeder Fehlercode ist über den Code-Namespace des Feature-Contracts-Projekts lokalisiert (siehe Abschnitt 4) — ein neuer Fehlercode ohne DE/EN-Paritätstext gilt als unvollständig.
- Platzhalter im Text eines Fehlercodes füllt die Abweisung über ihre Exception-Daten, und zwar
nach Schlüssel:
{Schlüssel}wird durchData[Schlüssel]ersetzt,WithData("0", …)füllt{0}. Nach dieser Regel formuliert ABP die Abweisung für die HTTP-API (DefaultExceptionToErrorInfoConverter). Dieselbe Regel wendetHearingUiErrorClassifier.DescribeCommunicationErrorauf jeden Hearings-Code an, den es nicht gesondert beschreibt – und gilt damit nur auf den Hearings-Seiten, die ihre Abweisungen darüber beschreiben: Bescheidung, Verfahrensakte samt Erinnerungsauswahl (HearingReminderBatchPanel), Einreichung, Versand, Kommunikationsvorlagen und der Kommunikationsschritt (HearingCommunicationStepPanel). Protokollrecherche und Teilnahme im Portal formulieren ihre Platzhaltercodes selbst. Die übrigen Oberflächen, die den bloßen Ressourcentext eines Codes zeigen (Freigabe und ihre Rücknahme, Postausgang, Antworten, Empfängerstand, individuelle Frist, Anlage, Kopie, Vorlagenbindung), rufen keine Operation auf, die einen Platzhaltercode wirft. Der bloße Text ist kein Ersatz, er enthält die Platzhalter unformatiert (RAL-QM-HP-46: „Bescheide versenden“ zeigte „({0})“, die Erinnerungsauswahl „{0}“ statt der Institutionen). Jeder Platzhaltertext nennt deshalb genau die Schlüssel, die jede seiner Wurfstellen anhängt – in beiden Sprachen gleich, bevorzugt benannt ({institutions},{count}); ein Positionsplatzhalter{0}nur zuWithData("0", …). Was nicht jede Wurfstelle anhängt, gehört nicht in den Text des Codes:UnresolvedCommunicationPlaceholdernennt nur{placeholder}, denn Vorlagen-, Vorschau- und Wortlautprüfung hängen nur ihn an. Empfängerkennung, Zweck und Kanal ergänzt erst die Aussendung (HearingOutboxRenderer); die HTTP-API liefert sie in den Fehlerdaten, die Seiten nennen Empfänger und Kanal in einem eigenen Satz (Templates:UnresolvedPlaceholder, RAL-QM-HP-26 AC-6). Ein solcher eigener Zweig (HearingUiErrorClassifier.CodesWordedByOwnBranch) ergänzt die Schlüsselregel für die Seite, er ersetzt sie nicht.HearingUiErrorClassifierTestshält für jeden Platzhaltertext der Hearings die Schlüssel seiner Wurfstellen fest und wird rot, wenn der Text andere nennt (die Schlüssel selbst sichern die Tests der Wurfstellen);HearingExceptionLocalizationTestsprüft jeden Platzhaltertext mit ABPs echtem Konverter. Die Abweisung der Wertelisten-Prüfung (RALQM.ValueLists:EntryInactive,:EntryNotFound) ist kein Hearings-Code, und die Hearings-Ressource hat für sie keinen Text: Verfahrensakte und Anlage formulieren sie überHearingUiErrorClassifier.DescribeValueListRefusalaus der Wertelisten-Ressource nach derselben Schlüsselregel (RAL-QM-HP-4 AC-2,HearingUiErrorClassifierValueListTests). - Geschützte Application Services unterscheiden deterministisch zwischen Validation, Not Found, Forbidden und Concurrency, soweit diese Unterscheidung keine Information an anonyme Nutzer leakt. Bei Ablehnung bleibt die Persistenz unverändert.
- Für aufgegebene Gastdownloads und im Host gesperrte Direkt-Shares gilt bewusst das Gegenteil:
unterschiedliche interne Ablehnungsgründe werden auf dieselbe äußere Antwort abgebildet (nicht
enumerierbare Fehlerform,
no-store,nosniff), damit IDs oder Tokens nicht erraten werden können. - Externe Calls (Keycloak-Admin-Port,
IEmailSender) klassifizieren Fehler als Validation, Not Found, Authorization, Conflict oder Unavailable und verwenden Idempotency Keys statt stiller Wiederholung mit Nebenwirkung.
Kommunikationsvorlagen und Verfahrensstände (RAL-QM-HP-26)
RALQMHearingCommunicationTemplates speichert ausschließlich Name, Zweck, Kanal, Zustand,
Revision und native Inhaltsreferenz. Die Texte liegen in ABP Text Template Management;
TextTemplates.Runtime erlaubt neue unveränderliche Definitionen innerhalb der besitzenden
Transaktion und liest dynamische Definitionen ohne einen veralteten Prozesscache. Statische
ABP-Definitionen behalten Vorrang. Die generische ABP-Pflege prüft alle registrierten
ITextTemplateWriteGuard vor Update und Restore. Die einzige Löschoperation des Ports
(IManagedTemplateContentPort.DeleteAsync) gehört der einmaligen Kennungsumstellung und
Kopienbereinigung des Migrators (RAL-QM-HP-101); eine verwaltete Vorlage ist sonst unveränderlich.
Draft → Active → Retired verwendet optimistische Concurrency. Ein gefilterter eindeutiger Index schützt Purpose/Channel bei Active; der Ersatz läuft unter Serializable. Ein SQL-Deadlock oder die Verletzung genau dieses Indexes wird als Concurrency-Konflikt zurückgegeben. Das eigene Pflegerecht erhalten Referent und Produktadministrator, die Geschäftsführung liest über Hearings.Default. Bestehende technische ABP-Grants ersetzen den Fachschreibpfad nicht.
Bei der Verfahrensanlage werden alle aktiven Texte in allen aktiven Sprachen der Sprachverwaltung
samt Referenz und Revision in Hearing.CommunicationTemplatesJson festgeschrieben (seit
RAL-QM-HP-101 sprachneutral: eine Katalogvorlage trägt je aktiver Sprache einen Text, der Text der
Standardsprache ist Pflicht, Kennungen sind die Kulturnamen der Sprachverwaltung). Fehlt eine
Sprachfassung, antwortet die Standardsprache; dieser Rückfall wird im Verfahrensstand gekennzeichnet
eingefroren (ContentCultureName je Eintrag).
Altverfahren können den angezeigten aktuellen Satz einmalig mit Actor, UTC-Zeit und gelesenem
Verfahrensstempel übernehmen. Fehlende Zwecke sperren den jeweiligen Kommunikationsschritt.
Der Seed läuft nur im Migrator. Er importiert die effektiven Altslots einmalig in einen leeren
Katalog und ersetzt dabei die Literalsignatur „RAL Anhörungsportal“ durch {{Absender}};
bestehende Verfahrensstände bleiben unverändert. Bei gefülltem Katalog ersetzt er bei jedem
Lauf aktive Nachrichtenvorlagen, deren Text noch die Literalsignatur trägt, über den
HearingCommunicationTemplateManager durch einen aktiven Ersatz gleichen Namens mit ersetzter
Signaturzeile (RAL-QM-HP-66, wiederholbar, Altvorlage stillgelegt, individuelle Texte erhalten,
Audit-Scope für die Entitätsänderungshistorie); Vorlagen ohne Signaturzeile und ohne
Platzhalter bleiben stehen, sie und Ersätze ohne {{Ansprechperson}} werden je Sprache als
strukturierte Ereignisse gemeldet. Nach demselben Muster stellt er die beiden aktiven
Erinnerungsvorlagen um, deren Text noch den ausgelieferten Wortlaut vor RAL-QM-HP-84 trägt
(Betreff „Erinnerung, zweite Frist läuft“, Satz „Es läuft nun eine zweite Frist bis zum
{{Frist}}.“; zweite Erinnerung mit dem Betreff „Statusänderung“ und dem Satz „läuft die zweite
Frist für {{Institution}} am {{Frist}} ab.“): die eine Textregel HearingReminderWordingUpgrade
ersetzt genau Betreff und Satz durch den ausgelieferten neutralen Wortlaut, alles Übrige bleibt
zeichengenau; ein Text ohne den ausgelieferten Wortlaut bleibt stehen und wird je Sprache
gemeldet, wenn er weiter von einer „zweiten Frist“ spricht. Dieselbe Regel gilt beim Import eines
gespeicherten Altslots. Gebundene Textsätze laufender Verfahren bleiben unverändert; eine
Laufzeitregel wie für die Signatur gibt es für den Wortlaut nicht (Entscheidung 08.10.2026).
Nachtrag RAL-QM-HP-51: ausdrückliche Ergänzungsbindung für nach RAL-QM-HP-26 eingeführte Zwecke. Die Regel
„Fehlende Zwecke sperren den jeweiligen Kommunikationsschritt“ gilt unverändert. Der erste nach RAL-QM-HP-26
eingeführte Zweck, die Endfassungsbenachrichtigung (FinalVersionDelivery, 70), fehlt in jedem vorher
gebundenen Verfahren; dafür gibt es einen ausdrücklichen Ergänzungsweg nach dem Altfallmuster, keinen
stillen Rückfall auf den Katalog (SPEC-RAL-QM-HP-51):
- Domäne.
Hearing.SupplementCommunicationTemplatesist rein additiv: nur Zwecke ohne gebundenen Eintrag und nur aus der Allowlist der nach RAL-QM-HP-26 eingeführten Zwecke (Hearing.SupplementableTemplatePurposes, heute genau {70}). Verweigert wird inCompleted/Cancelledund ohne vorhandene Bindung – dort bleibt die Altfall-ÜbernahmeBindCurrentTemplatesAsyncder Weg –, FehlercodeTemplateSupplementNotAllowed. Neue Einträge werden hinter das bestehende JSON gehängt; der gebundene Bestand bleibt byteidentisch. - Anwendungsdienst.
IHearingCommunicationTemplateAppService.SupplementMissingTemplatesAsyncfolgtBindCurrentTemplatesAsync: RechtUpdate, Verfahrensstempel, erwartete Revision je aktiver Katalogvorlage. Actor und UTC-Zeit werden festgehalten; der Verlauf erhältCommunicationTemplatesSupplemented(830; Subjekt Verfahren, Detail Zweck und Revision, PII-frei). - Auslöser ist ausschließlich die Oberfläche. Abschluss-Panel und kombinierter Abschluss zeigen bei
HearingDto.IsFinalVersionTemplateMissing(70 fehlt und mindestens ein Endfassungsempfänger mit wirksamem Endfassungs-Grant – dieselbe Empfängermenge wie die Vorprüfung im Abschluss) den HinweisHearingFinalVersionTemplateNoticemit Revision und Betreff der aktiven Vorlage und der Aktion „Vorlage übernehmen“; der Abschluss-Button ist bis dahin mit Begründung gesperrt. Der Abschluss selbst ergänzt nie. - Vorprüfung im Abschluss. Vor jeder Nebenwirkung weist der Abschluss mit
TemplateNotResolvable(purpose 70) ab, wenn mindestens ein Endfassungsempfänger mit wirksamem Endfassungs-Grant (Regel 7) existiert und 70 nicht gebunden ist (Laufzeitsicht, Schritt 6). Ohne Empfänger braucht der Abschluss keine 70. Die RAL-QM-HP-42-Festschreibung „fehlender Zweck → vollständiger Rollback“ bleibt unverändert. - Seed. Bei gefülltem Katalog importiert der Migrator zusätzlich die nach RAL-QM-HP-26 eingeführten Zwecke,
für die keine einzige Katalogzeile besteht (heute nur 70; Ereignis 7071
HearingTemplateMissingPurposeImported), mit demselben Auflöser, derselben Signaturregel und demselben Audit-Pfad, wiederholbar ohne Wirkung. Eine Zeile des Zwecks in jedem Zustand – auch Entwurf oder stillgelegt – wird respektiert. Fehlende Alt-Zwecke importiert er nicht: Sie sind bewusste oder abweichende Katalogzustände (RAL-QM-HP-42-Festschreibung), keine still zu aktivierenden Lücken. - Verfahren von vor RAL-QM-HP-26 (
CommunicationTemplatesJson= null) scheitern weiterhin am ersten fehlenden Zweck; ihr Weg bleibtBindCurrentTemplatesAsync.
HearingOutboxRenderer liefert Nachricht und optionalen Dokumenttext aus demselben
Empfängermodell. Der Dokumentvertrag bereitet Text vor; Binärdatei, Anlage und Ablage werden
in RAL-QM-HP-24 umgesetzt. Anredeform/Titel gehören Institutions und werden auf den Teilnehmer
kopiert. Freie Bestandsanreden werden unverändert verwendet. Alle fünf Arten mit Frist behalten
ihre bisherigen Datumsquellen; Abschluss und Abbruch führen keinen Datumsplatzhalter ein.
In einem gebundenen Nachrichtentext wird die Literalsignatur beim Rendern durch {{Absender}}
ersetzt — nie angefügt —, die Bindung selbst bleibt unverändert (RAL-QM-HP-66).
Unbekannte, beschädigte oder nicht auflösbare Ausdrücke verhindern den vollständigen
transaktionalen Enqueue. Der Worker prüft außerdem den gesamten noch offenen Batch vor dem
ersten externen Send, einschließlich verzögerter Retries. Klartextlinks bleiben transient.
Vorlagentexte, Teilnehmersnapshots und verschlüsselte Payloads werden nicht auditiert.
Empfängerstand je Zeile (RAL-QM-HP-6 AC-1). Der Renderer, die eine Stelle, die den Teilnehmer
jeder Aussendung lädt und prüft, friert dessen operativen Empfängerstand in RenderedHearingMessage
ein; HearingOutboxManager schreibt ihn vor dem Insert auf die Zeile (Recipient*-Spalten, siehe
§2). Kein Sendeweg
kann eine Teilnehmernachricht ohne Stand einstellen; eine spätere Änderung der Beteiligung oder der
Stammdaten erreicht keine eingestellte Zeile.
Kommunikationsschritt und Begleitdokument (RAL-QM-HP-24). Der Renderer liest den Wortlaut aus
dem Kommunikationsschritt des Zwecks – mit der Abweichung der Beteiligung, wenn sie eine hat –,
legt den Schritt für automatische Auslöser vor der ersten Zeile aus der gebundenen Vorlage an
(genau einmal, Systemeintrag) und setzt ReleasedAtUtc, sodass der Wortlaut ab der ersten Zeile
eines Zwecks festgeschrieben ist. Nennt der Wortlaut weder {{Link}} noch eine Portaladresse,
hängt HearingPortalLinkRule die Linkzeile einmal an; Link ist Platzhalter jedes Zwecks, und der
Worker füllt ihn für jede Zeile, die ihn trägt, mit dem tokenfreien Teilnahmeziel aus RAL-QM-HP-31 – auch
für die bisher credential-freien Arten. Je Teilnehmernachricht komponiert der Renderer den
Brief (HearingCoverLetterContent: Briefkopf aus dem vollständigen Organisationsabsender
(RequireAsync, sonst Abweisung vor Dokument und Zeile), Anschrift aus dem eingefrorenen
Empfängerstand, Ansprechperson, Datum, Betreff, Wortlaut ohne die Mail-Signaturblöcke, Zeichnung
– Einladung und Bescheid die freigebende Geschäftsführung, sonst der Zuständige, als Text ohne
Bild); HearingOutboxManager schreibt ihn mit HearingCoverLetterPdfWriter (PDF 1.4, Helvetica
WinAnsi, kein Paket) über IDocumentContentPort vor dem Insert und bindet die Datei an die
Zeile; die Vertretungskopie trägt dieselbe Datei, ein Replay legt keine zweite an. Der Worker
sendet eine Zeile mit Dokument als MailMessage mit Anhang, öffnet die Datei je Versuch über den
Port (dieselben Bytes, nie ein fremdes Dokument) und hält bei MarkSent den versendeten Wortlaut
fest. Die Endfassung der Oberfläche (IHearingCommunicationStepAppService.GetFinalPreviewAsync)
komponiert denselben Brief über HearingOutboxRenderer.ComposeLetter ohne Nebenwirkung; ihr
OutputStamp (Wortlaut, Abweichungen, Absenderblock, Zeichnungs-Id, gedruckter Zeichnungs- und
Ansprechpersonenblock) ist der Fingerabdruck, den
der Erstversand zurückverlangt (CommunicationOutputOutdated), wenn die Versandseite ihn mitgibt.
Ausnahme: Endfassungsbenachrichtigung ohne Begleitbrief (RAL-QM-HP-51, E4). Ob eine
Teilnehmeraussendung einen Brief trägt, entscheidet genau eine Regel: HearingCoverLetterRule.Requires(kind)
ist für jede Nachrichtenart wahr außer für die Endfassungsbenachrichtigung (FinalVersionDelivery, 70).
Alle Stellen lesen dieselbe Regel: der Renderer komponiert für 70 keinen Brief und verlangt deshalb
auch keinen vollständigen Briefkopf-Absender, HearingOutboxManager ruft kein CreateAsync auf und
bindet kein CoverDocumentId, Endvorschau und OutputStamp führen weder Briefdatei noch
Zeichnungsblock, und die Zusammenstellung einer Phase weist 70 als leer ab
(CoverDocumentCompilationEmpty). Der Worker versendet eine Zeile ohne Dokument als einfache
Nachricht. Die Endfassung selbst – die aktiven Abschlussanlagen – wird nie als Anhang versandt: Die
Benachrichtigung verweist credential-frei ({{Portalhinweis}}, {{Link}}) auf den Portalabruf nach
RAL-QM-HP-30/RAL-QM-HP-62, den die Endfassungs-Grants des Abschlusses öffnen. Nachweis:
HearingOutboxCoverDocumentTests.The_manager_stores_a_cover_letter_exactly_for_the_kinds_that_require_one
(Theorie über alle Arten). SPEC-RAL-QM-HP-24 AC-5 trägt den Nachtrag.
Vertretungskopie (RAL-QM-HP-9 AC-7, A10, A11). Hat der Kontakt eines Teilnehmers in dem Moment,
in dem eine Aussendung in den Postausgang gelegt wird, eine wirksame Vertretung, entsteht eine
eigene Postausgangszeile an die E-Mail-Adresse der Vertretung. Aufgelöst wird die Vertretung an
genau einer Stelle, in HearingOutboxManager, und damit für jede Nachrichtenart: über den
permissionfreien Port IInstitutionContactDeputyReader aus Institutions.Contracts, mit dem
UTC-Zeitpunkt der ABP-Clock beim Einstellen; Zeitfenster und Aktivität prüft
Institution.FindEffectiveDeputy. Die Kopie entsteht nur, wenn die Hauptzeile tatsächlich
eingefügt wurde; eine Wiederholung mit bereits vorhandenem Schlüssel erzeugt keine nachträgliche
Kopie. Sie liegt in derselben Unit of Work und in derselben Batch-ID wie die Hauptzeile und
unterliegt ohne Ausnahme derselben Alles-oder-nichts-Regel der Aussendung. Sie ist unverändert:
gleicher Teilnehmer, gleiche Nachrichtenart, gleicher gerenderter Text samt Modell und derselbe
verschlüsselte Link-Payload und – seit RAL-QM-HP-6 – derselbe eingefrorene Empfängerstand, weil
die Kopie denselben Empfänger vertritt, und – seit RAL-QM-HP-24 – dasselbe Begleitdokument; nur
Kennung, Empfängeradresse und Idempotenzschlüssel unterscheiden sich. Der Schlüssel ist der vollständige Schlüssel der Hauptzeile mit dem Suffix :dep. Stimmt die
Adresse der Vertretung ohne Groß- und Kleinschreibung und ohne Randleerzeichen mit der
Empfängeradresse der Hauptzeile überein, entsteht keine Kopie (E12). Zustellstatus des Verfahrens
und Postausgangsverwaltung zeigen die Kopie als zweite Zeile desselben Teilnehmers mit der Adresse
der Vertretung, ohne eigene Beschriftung und ohne neue Spalte; im Zustellstatus folgt sie der
Hauptzeile. Sendefehler der Kopie laufen je Zeile über die normalen Wiederholungen und Störungen
des Postausgangs und berühren die Hauptzeile nicht. Seit RAL-QM-HP-31 trägt die Kopie einen tokenfreien Portal-Tiefenlink. Sie vermittelt
kein Zugriffsrecht; die Vertretung benötigt ein eigenes aktives Institutionskonto. Wer
RALQM.Institutions.Update hält, bestimmt weiterhin die Adressierung künftiger Kopien,
aber keine Kontobindung. Die Vertretungszuweisung bleibt in der Entity History nachvollziehbar.
Accounts.ManageInstitutionBinding gehört Referent und Systemadministrator. Widerruf und
Rücknahme sind getrennt von Kontosperre und Teilnahmeentzug, mit Akteur, UTC-Zeit, Concurrency
und idempotenter Operation-ID. Die Kontoübersicht zeigt auch widerrufene Bindungen.
7. Teststrategie
Die Lösung trennt Nachweise nach Risiko statt einer einzigen Testebene zu vertrauen:
| Ebene | Prüft |
|---|---|
| Architekturtests | Projekt-, Paket-, Modul- und Quellcodegrenzen (z. B. CAF.* → HearingPortal.* verboten) |
| Modul-/Application-Tests | Invarianten, Permissions (positiv/negativ über den realen ABP-Proxy), Fehler, Idempotenz |
| SQL-Server-Integrationstests | Mapping, Constraints, Concurrency, echte Rundreisen, from-empty |
| bUnit-Tests | gerenderte Zustände, Fokusverhalten, Cohesion-Provider-Scan |
| BrowserGate (separat, exklusiv) | realer Stack, Anmeldung, Hauptprozess, Permission-Denial, Assets, responsive Bedienbarkeit, axe/WCAG |
Der zentrale Einstieg ist tools/scripts/Invoke-QualityGate.ps1. Er bestimmt betroffene Apps
aus den vollständigen Ref-Diffs und den transitiven Projektreferenzen vor und nach der Änderung.
Das app-eigene Gate führt Preflight, Restore, Build ohne Warnings/Errors, alle App-Solutiontests,
dotnet ef migrations has-pending-model-changes und den BrowserGate aus. Fehlende oder
übersprungene Pflichtnachweise machen den Lauf rot. -App ral/qualitymarks/hearingportal
erzwingt die App-Prüfung; -All prüft CAF und alle ausführbaren Apps zur Vollabnahme.
Der versionierte pre-push-Hook verlangt einen sauberen Arbeitsbaum am gepushten Tipp und
bindet sein frisches Ergebnis an alle Ref-Paare. Verschiedene Tipps in einem Push werden
abgewiesen. Nur das verifizierte Ergebnis wird als Git-Note refs/notes/quality-gate angeheftet.
Reine Doku-/Jira-Änderungen prüfen Links und Reporting; unbetroffene App-Gates sind ausdrücklich
NOT_APPLICABLE. Am Commit bleibt nur die Prüfung des gestageten Diffs auf Secrets,
gesperrte Pfade und Konfliktmarker.
Die konkrete Nachweismatrix je Änderungsart (Contract/Permission, Domainregel, geschützter Read/Write, Concurrency, EF-Migration, Dokument-/Portalpfad, Blazor-Komponente, Skript, Dokumentation) steht im Entwicklungsleitfaden §15.
Weiterführend
- Bausteinsicht — Modulgrenzen und Abhängigkeitsrichtung
- Laufzeitsicht — Requestablauf, Dokumentzugriffswege, Hearing-Lebenszyklus
- Architekturentscheidungen — begründete Grundsatzentscheidungen
- ../DEVELOPMENT-GUIDE.md — normative Regeln je Änderungsart
- ../GETTING-STARTED.md — lokaler Stack und Betriebseinstieg
- ../../conventions/ — themenspezifische Coding-Konventionen
8. Störungen und Betriebsbereitschaft (RAL-QM-HP-37)
Der fachliche Vertrag steht in SPEC-RAL-QM-HP-37.
Hearings besitzt RALQMHearingIncidents, deren Versuchshistorie in
RALQMHearingIncidentFailures und RALQMHearingIncidentNotifications. Quellart und
Quell-ID identifizieren einen Vorgang eindeutig; ein erneutes Bereitstellen erledigt keinen Fehler.
Dieselbe Quellart Notification trägt seit RAL-QM-HP-25 auch die Zustellfehler der
Freigabe-Benachrichtigung (RALQMHearingApprovalDecisionNotifications, Vorgangsart
Notification:ApprovalDecision, Codes notification-failed und notification-recipient-missing);
technische Fehler werden weiterhin wiederholt. Nach 72 Stunden seit dem ersten Empfängerfehler
pausieren Entscheidungsaufträge zur fachlichen Klärung (RAL-QM-HP-69, ADR-09). Die Geschäftsführung
bestätigt einen verknüpften Folgeauftrag; Originalempfänger und Versuche bleiben erhalten.
Der pausierte Auftrag wird nicht automatisch erneut versucht, und
der Detector behandelt ihre Tabelle wie die Störungsbenachrichtigungen (verwaister Claim →
process-interrupted, Erledigung mit dem Versandzeitpunkt).
Erst der erfolgreiche Abschluss setzt den Erledigungszeitpunkt. Endfehler erhalten einen
persistenten, pro Verfahren/Vorgangsart/Fehlercode gebündelten Benachrichtigungsauftrag. Der
Benachrichtigungsfehler selbst unterdrückt weitere Alarmnachrichten und bleibt nachholbar.
Ein separater periodischer Detector erkennt ausbleibende Ergebnisse auch dann, wenn der
Dispatch-Pass selbst auf einen Provider wartet. Er gleicht außerdem gespeicherte Quellergebnisse
mit der Störungssicht ab, um einen Prozessabbruch zwischen beiden Schreibschritten nachzuholen.
Ein lokal noch laufender Versand wird nach Timeout für ein weiteres StuckAttemptTimeout
beobachtet und nicht parallel neu gestartet; antwortet der Transport auch dann nicht, wird der
Versuch als unterbrochen abgeschlossen und die Nachricht regulär wiederholt. Jede
Benachrichtigungszustellung läuft in einer eigenen Unit of Work, damit ein an einen parallelen
Worker verlorener Claim die übrigen Zustellungen des Durchlaufs nicht blockiert.
Der Fristenprozessor speichert Fehlzustand und Störungshistorie gemeinsam in seiner
Fehlertransaktion; die erfolgreiche Ausführung erledigt die Störung in derselben Transaktion.
Altfehler werden ohne nachträgliche Alarmflut importiert. Die UI kennzeichnet unvollständige
Althistorien und ersatzweise verwendete Zeitpunkte des letzten bekannten Quellzustands.
Authorization löst aktive interne Empfänger über einen schmalen Contract auf; es gibt keine fremden Identity-Repositories im Hearings-Feature. Administrator und Referent erhalten die getrennten Rechte zum Lesen/Wiederholen, Geschäftsführung erhält das Leserecht. Es gilt dieselbe verfahrensübergreifende interne Sicht wie bei der vorhandenen Verfahrensliste.
Die technische Zustandsauskunft bleibt im Host. Regelmäßige ASP.NET-Health-Probes prüfen Datenbank, Dateiablage, SMTP und weiterhin Keycloak. Datei-Probes verwenden ausschließlich einen synthetischen Marker im bestehenden BLOB-Container; SMTP-Probes senden keine E-Mail. Ein In-Memory-Snapshot enthält nur freigegebene Betriebsmittelkennungen, Status und Prüfzeit. Ein veralteter oder fehlender Snapshot ist nicht bereit. Zustandswechsel gehen in das bestehende strukturierte Betriebslog, damit ein Datenbankausfall den Protokollpfad nicht voraussetzt.
/health/live bleibt vom Zustand der Abhängigkeiten unabhängig, /health/ready gibt weiterhin
nur den Gesamtstatus aus. /health/status ergänzt die datensparsame Einzelsicht und prüft die
direkte Client-IP gegen eine konfigurierte CIDR-Allowlist (standardmäßig Loopback). Sie verlangt
keine DB-abhängige Authentifizierung. Bei Reverse-Proxy-Deployment ist eine zusätzliche Sperre
oder Netzwerkfreigabe am Proxy erforderlich; die Loopback-Adresse des Proxys ist kein Nachweis
für einen berechtigten externen Client. Der Deploy-Stack sperrt die Route im Caddyfile über
OPS_ALLOWED_CIDR und reicht die Client-IP per X-Forwarded-For an die Anwendungs-Allowlist
durch. Konfiguration und noch ausstehender RAL-Betriebsnachweis
stehen in der Spec; Quellcode allein belegt keine produktive Einsatzbereitschaft.
Institutionsimport und interne Notizen (RAL-QM-HP-49)
Institution.InternalNote ist eine optionale nvarchar(2000)-Spalte auf
RALQMInstitutions. Die bestehende RAL-QM-HP-10-Migration besitzt diese Spalte; RAL-QM-HP-49 ergänzt keine zweite Notiz. Das Aggregat begrenzt ihre Länge; die bestehenden Create-/Update-Permissions und
der optimistische Concurrency-Stamp schützen auch Notizänderungen. Öffentliche
Institutionsreferenzen, Kontakte und Portalverträge erhalten kein Notizfeld.
ABPs DisableAuditing schließt die Notiz aus den betreffenden DTO-Parametern und aus der
Entity-History aus. Dasselbe gilt für InstitutionImportInput.FileContent: Die importierte
Datei wird nicht als Action-Parameter protokolliert. Die ABP-Auditaktionen und zulässige
Entity-Änderungen bleiben erhalten. SQL-/ABP-Proxy-Tests prüfen sowohl die fehlenden Inhalte
als auch die weiterhin vorhandenen Auditereignisse.
Der CSV-Import ist create-only und validiert alle Kontakte vor dem Insert des Aggregats. Bekannte Namen werden getrimmt und ohne Beachtung der Groß-/Kleinschreibung erkannt; aufeinanderfolgende Wiederholungen und Dubletten innerhalb einer Datei werden übersprungen. Eine globale Namenseindeutigkeit bei konkurrierenden Neuanlagen wird damit nicht eingeführt. Der Export nutzt die Listenfilter ohne Paging und liefert die interne Notiz ausschließlich nach ausdrücklicher Wahl für die einzelne Exportaktion. Der genaue Dateivertrag steht in SPEC-RAL-QM-HP-49.
Der Kontaktteil der Datei trägt seit Teil 2 zusätzlich Anredeform, Titel, Telefonnummer und das
Standardkennzeichen. Er erzeugt keine neue Spalte in der Datenbank: alle vier Felder bestehen
seit RAL-QM-HP-9 und RAL-QM-HP-26, und es entsteht keine Migration. Das Standardkennzeichen steht je
Kontaktblock und genau einmal je Zeile. Der gefilterte eindeutige Index bleibt dabei
unberührt, weil die Institution samt Kontakten als ein Insert geschrieben wird, in dem genau
eine Kontaktzeile das Kennzeichen trägt; MarkAsMandatoryPartner fasst ohnehin keine
Kontaktzeile an. Die
Vertretung bleibt außerhalb der Datei, weil ihre Zuweisung einen aktiven Vertreter verlangt und
der Import alle Kontakte aktiv anlegt — die Invariante wäre auf diesem Pfad unerreichbar.
09. Architekturentscheidungen
Dieses Kapitel hält die wesentlichen, dauerhaft wirksamen Architekturentscheidungen in
ADR-Kurzform fest: Titel, Kontext, Entscheidung, Konsequenz. Details zu Bausteinen stehen in der
Bausteinsicht, zu Qualitätsanforderungen in der
Qualitätsanforderungen bzw. dem
Qualitätsbaum. Die vollständige, laufend gepflegte
Konventions-Bewertung inkl. Vor-/Nachteilsabwägung steht in
docs/conventions-decisions.md.
ADR-01 · No-Layer-ABP statt klassischer 8-Projekt-Schichtung
- Kontext: ABP-Projekte werden üblicherweise in Domain, Application, EntityFrameworkCore, HttpApi, Blazor usw. je Modul zerlegt. Für einen modularen Monolithen mit überschaubarer Modulzahl erzeugt das viel Projekt-/Verkabelungs-Overhead ohne echten Nutzen.
- Entscheidung: Jedes Fachmodul besteht im Normalfall aus höchstens drei Assemblies:
*.Contracts(DTOs, Interfaces, Permissions, Localization, öffentliche IDs), einer Runtime (Domain, Application, EF-Mapping in einer Assembly) und optional*.Blazor(Feature-UI). Domain, Application und Persistence bleiben logische, aber nicht separat materialisierte Schichten. Eine weitere Assembly entsteht erst, wenn sie unabhängig konsumiert, paketiert, ersetzt oder betrieben werden muss. - Konsequenz: Weniger Projekte/Referenzen, schnellere Builds, geringere Einstiegshürde. Die
Abhängigkeitsrichtung (Contracts ↔ Runtime ↔ Blazor, keine Rückkanten) bleibt trotzdem eine
Compile-Time-Eigenschaft, durchgesetzt durch Architekturtests statt durch Projektgrenzen
allein (siehe
ADR-06).
Konvention ABP-11 in
conventions-decisions.mdmarkiert die klassische 8-Schichtung entsprechend als N/A für dieses Repository.
ADR-02 · Monorepo mit Host + wiederverwendbaren CAF-Modulen + einer RAL-Anwendung
- Kontext:
CAF.Modules.*(Authentication, Documents[.Contracts], UI.Blazor) sind anwendungsneutrale Bausteine;HearingPortalwar zum Entscheidungszeitpunkt die einzige existierende Anwendung, die sie konsumiert. Getrennte Repositories hätten Versions-Ping-Pong zwischen Framework und Anwendung erzwungen, obwohl beide im selben Entwicklungstakt reifen. - Entscheidung: Ein Repository (
CAF.slnx) bündeltmodules/(CAF-Bausteine) undapplications/RAL/QualityMarks/HearingPortal/src/(Host, Shell, Contracts, Features). Die Ordnerstruktur der beiden Solutions führt die Bausteinsicht §5.1. - Konsequenz: Ein Commit kann Framework und Anwendung atomar ändern; Refactorings über die
Grenze sind ohne Cross-Repo-Release möglich. Im Gegenzug muss die Modulgrenze
CAF.Modules.* → Applications.*verboten bleiben, sonst verwischt das Monorepo den eigentlichen Zweck der Module (wiederverwendbar, anwendungsneutral) — durchgesetzt in ADR-06. Die vier CAF-Bausteine bleiben dabei bewusst Quellcode-Bausteine und werden nicht paketiert (ADR-03); der Host konsumiert sie ausschließlich perProjectReference.
ADR-03 · CAF-Bausteine als Quellcode-Bausteine mit Vertragsdatei (VERTRAG.md)
- Kontext:
CAF.Modules.Authentication,CAF.Modules.UI.Blazor,CAF.Modules.DocumentsundCAF.Modules.Documents.Contractssollen wiederverwendbar bleiben, ohne dass Konsumenten sich auf undokumentierte interne Details verlassen. Eine frühere Fassung dieser Entscheidung sah echte NuGet-Pakete vor (IsPackable=true, eigenePackageId/Version, Pack-Skript). Das wurde zurückgenommen: es gab keinen Konsumenten außerhalb dieses Repositorys, also war es Paketinfrastruktur ohne Abnehmer — mit Versionspflege, Feed-Frage undNU5104-Rauschen als laufenden Kosten. - Entscheidung: Die Bausteine sind Quellcode-Bausteine, keine NuGet-Pakete. Jedes der vier
csproj setzt
IsPackable=falseund trägt keinePackageId, keineVersionund keinPackageReadmeFile; der Host konsumiert sie ausschließlich perProjectReference. Die verbindliche Vertragsgrenze bleibt die deutschsprachigeVERTRAG.mdim Wurzelverzeichnis des jeweiligen Projekts — als Quelltext-Vertrag: zugesicherte öffentliche Fläche, ausdrückliche Nicht-Zusicherungen, Versionierungsregel für den Fall einer späteren Paketierung. Ein Pack-Skript existiert nicht. - Konsequenz: Kein Versions-Ping-Pong und kein Feed-Zwang für die tägliche Entwicklung; die
Wiederverwendbarkeit ist eine Eigenschaft des Abhängigkeitsgraphen
(ADR-06), nicht
einer Paketgrenze. Der Vertrag ist trotzdem geschrieben und maschinell verankert:
FrameworkPackagingTestspinnt genau vier CAF.Modules-Projekte, deren Nicht-Packbarkeit samt fehlender Paketidentität, und dass jedeVERTRAG.mdexistiert, nicht leer ist und beide Pflichtabschnitte trägt. Ein versehentlichesIsPackable=trueoder eine gelöschte Vertragsdatei bricht den Build. Preis: Ein Konsument außerhalb dieses Repositorys ist heute nicht bedienbar — er bräuchte zuerst eine erneute Paket- und Feed-Entscheidung. Ein zweites Produkt im Repository funktioniert ohne Änderung.
ADR-04 · RALQM als data-preserving Umbenennung persistierter Kennungen
- Kontext: Das Produkt hieß im Code zunächst
Guetezeichen, dannQualityMarks; die verbindliche Kurzform für persistierte, anwendungsspezifische Kennungen ist inzwischenRALQM(TabellenRALQMHearings/RALQMInstitutions, Fehlercode-PräfixRALQM.<Feature>:, Permission-GruppeRALQM, RollenRALQMAdministrator/RALQMCaseOfficer/RALQMManagement). Technische Slugs (z. B. Docker-/Keycloak-Client-IDs wieral-qualitymarks) bleiben bewusst lowercase und wurden nicht mitgezogen. - Entscheidung: Jede Umbenennung persistierter Bezeichner erfolgt ausschließlich über eine
data-preserving EF-Migration (
RenamePersistedIdentifiersToRALQM, sieheapplications/RAL/QualityMarks/HearingPortal/src/Host/Migrations/) mit korrekt gespiegeltemDown(); historische Migrationen behalten ihre alten, zum jeweiligen Zeitpunkt gültigen Bezeichner (z. B.AddCafDocumentShareGrants) und werden nicht nachträglich editiert (Konvention EF-03). Bestehende Dev-Datenbanken werden über ein eigenständiges, nicht-destruktives Skript migriert (applications/RAL/QualityMarks/HearingPortal/tools/Migrate-DevDatabaseToRalqm.ps1: klont das Docker-Volume, benennt DB/Login auf der Kopie um, Quelle bleibt Rollback-fähig). - Konsequenz: Rename-Operationen sind reversibel und laufen ohne Datenverlust, auch auf Anwendungsdatenbanken mit Bestand (verifiziert per Round-Trip apply→revert→re-apply sowie gegen echte Dev-Daten: Tabellen-/User-/Grant-Zahlen vor/nach Migration identisch). Der Preis ist zusätzliche Migrations- und Skript-Pflege statt einer einfachen Such-Ersetzen-Operation im Quellcode.
ADR-05 · Cohesion als verbindliche UI-Bibliothek für Fachcode
- Kontext: ABP liefert LeptonX/MudBlazor für Account-, Administrations- und Themenseiten mit. Für die eigene Gütezeichen-Fachoberfläche soll es eine einheitliche, kapselnde Komponentenbasis geben statt direkter Vendor-Kopplung in jeder Feature-Komponente.
- Entscheidung: Eigene CAF-/RALQM-Seiten verwenden ausschließlich Cohesion, zentral über
CAF.Modules.UI.Blazorregistriert (Lizenzprüfung, Assets/Bundles; Paket aus dem GitLab-Gruppen-Feed, zentrale Floating-Version3.*-*). MudBlazor, Syncfusion oder Blazorise dürfen von Fachcode nicht direkt gerendert werden; ausgenommen sind allein die MVC-Razor-Pages unter/Account/**, die auf dem LeptonX-MVC-Theme bleiben. Die ABP-Administrationsansichten waren zunächst ebenfalls ausgenommen und sind es nicht mehr: sie sind durch Produktseiten ersetzt, und die Blazor-Vendor-Pakete sind entfernt. Nur Interactive Server wird unterstützt, kein WebAssembly; Feature-Komponenten bleiben render-mode-neutral (kein@rendermodeim Feature-UI). - Konsequenz: Vendor-Details sind in Wrappern gekapselt, ein späterer UI-Bibliothekswechsel
bliebe lokal begrenzt. Fehlende generische UI-Primitives gehören in die separat versionierte
Cohesion-Bibliothek, nicht in Fachcode-Workarounds. Die Regel ist kein Stilhinweis, sondern
arch-test-erzwungen (BL-01/BL-02 in
conventions-decisions.md).
ADR-06 · Strikte Modulgrenzen durch Architekturtests statt Konvention allein
- Kontext: Ordnerstruktur und Namensschema allein verhindern in der Praxis keine Querabhängigkeiten — insbesondere unter Zeitdruck oder bei automatisiertem/agentischem Edit. Der No-Layer-Ansatz (ADR-01) und das Monorepo (ADR-02) erhöhen dieses Risiko zusätzlich, weil alle Module im selben Prozess und Repository liegen.
- Entscheidung: Die Abhängigkeitsrichtung ist explizit tabelliert (siehe
Bausteinsicht) und über
Architekturtests erzwungen, u. a.:
CAF.Modules.* → Applications.*verboten, Contracts referenzieren nie Runtime/EF/Host, Feature-Blazor referenziert nie die eigene oder eine fremde Runtime, GZ-Runtime referenziert nie fremde Runtime/Entities/Repositories/DbSets/Tabellen, kein Modul referenziert den ausführbaren Host, keine neue Fachlogik/Fachentity im Host. Über Modulgrenzen werden nur IDs gespeichert, nie Cross-Module-Foreign-Keys oder -Navigation (z. B.InstitutionId/DocumentIdstatt Entity-Referenz). - Konsequenz: Grenzverletzungen sind Build-Fehler, nicht Review-Findings. Renames und
Restrukturierungen (z. B. die Gruppierung der Feature-Slices unter
applications/RAL/QualityMarks/HearingPortal/src/Features/<Feature>/oder die RALQM-Umbenennung) dürfen laut Projektregel die Grenzregeln selbst nie lockern, sondern ausschließlich Pfad-Literale in den Tests nachziehen. Das hält die Compile-Time-Eigenschaft auch über viele aufeinanderfolgende Strukturänderungen hinweg stabil.
ADR-07 · Wertelisten als Katalogtabellen statt Enum
- Kontext: Kennzeichnungsart und Verfahrensart waren C#-Enums, als
intaufRALQMHearingsgespeichert und über Localization-Schlüssel (Hearings:MarkType:*,Hearings:ProcedureType:*) beschriftet; Land und Funktion eines Ansprechpartners waren Freitextspalten ohne Liste. Ein persistierter Enum-Wert ist ein Migrationsvertrag: Die Zahl steht in jeder Zeile, eine neue Ausprägung oder ein geänderter Anzeigename bedeutet einen Quelltext-Release, und ein entfernter Wert lässt Bestandszeilen zurück, die keinen Namen mehr auflösen. Der Fachbereich verlangt für alle vier Listen Pflege durch den Systemadministrator über die Oberfläche und zusätzlich Standardfristen je Verfahrensart — Begleitdaten, die ein Enum überhaupt nicht tragen kann (SPEC-RAL-QM-HP-4, FR-PV-13/FR-PV-16). - Entscheidung: Vier Katalogtabellen (
RALQMMarkTypes,RALQMProcedureTypes,RALQMCountries,RALQMContactFunctions), ein Aggregat je Liste im eigenen Feature-Slice ValueLists. Jede Ausprägung trägt eine unveränderliche Guid-Kennung und einen stabilen technischenCode; fremde Module speichern ausschließlich die Kennung, ohne Foreign Key. Anzeigenamen liegen je Kultur am Datensatz (NameDePflicht,NameEnoptional, Rückfall auf Deutsch), nicht als Localization-Schlüssel. Ausprägungen werden nie gelöscht, nur deaktiviert; eine deaktivierte bleibt an Datensätzen sichtbar, die sie bereits tragen, und wird für neue nicht mehr angeboten. Es gibt keinen Cache. Die Verfahrensart trägt optional die drei Standardfristen (erste und zweite Rückmeldefrist, Abschlusserinnerung) als Owned Value Object in ihrer eigenen Tabelle. - Konsequenz: Die Compile-Time-Sicherheit des Enums ist bewusst aufgegeben — kein
vollständigkeitsgeprüfter
switchüber die Ausprägungen, kein Kompilierfehler, wenn eine neue hinzukommt. An ihre Stelle treten Laufzeitprüfungen im Aggregat und im Anwendungsdienst (EnsureSelectableAsync, Fachfehler statt stiller Annahme). Zweiter, konkreterer Preis: Die Sortierung der Verfahrenslisten nach Verfahrensart entfällt serverseitig, weil der Anzeigename jetzt in einer anderen Tabelle liegt und ein Join über die Modulgrenze verboten ist;HearingListSortQueryführt das Feld nicht mehr, eine Anfrage darauf fällt auf die Standardsortierung zurück statt zu scheitern, und die Grid-Spalte ist als nicht sortierbar markiert. (Nach der Kennzeichnungsart ließen sich die Listen ohnehin nie sortieren.) Der CSV-Listenexport schreibt seither unter den unveränderten SpaltenköpfenMarkType/ProcedureTypedie aufgelösten Anzeigenamen — kulturabhängig und jederzeit umbenennbar, ohne stabile Id-Spalte zum Rückfallen; bewusst offengelassen, siehe Spec. Weil Ausprägungen nur deaktiviert werden, wächst der Katalog dauerhaft — auch um Einträge, die nie benutzt wurden; das ist der Preis dafür, dass kein Bestandsdatensatz je auf eine gelöschte Kennung zeigen kann. Der Umstieg kostete eine mehrstufige Expand/Contract-Migration (siehe Querschnittliche Konzepte §2), und die Seed-Ids sind seitdem selbst ein Vertrag:ValueListSeedIdswird aus den Demo-Daten und aus knapp dreißig Testdateien referenziert, ein geänderter Wert bricht sie alle. - Verworfene Alternativen:
- Enum behalten und eine Overlay-Tabelle nur für Namen und Fristen führen. Hätte die Compile-Time-Sicherheit gerettet, aber genau die Anforderung verfehlt: Eine neue Ausprägung bliebe ein Quelltext-Release. Für Land und Funktion gibt es zudem gar kein Enum, das man überlagern könnte — es wären zwei verschiedene Mechanismen für vier gleichartige Listen entstanden, plus zwei Wahrheitsquellen je Ausprägung, die auseinanderlaufen können.
- ABP Language Management für die Anzeigenamen. Language Management verwaltet
Ressourcentexte, die ein Entwickler ausliefert und ein Übersetzer nachzieht. Die Namen
hier sind das Gegenteil: Daten, die ein Administrator anlegt und ändert. Jede neue
Ausprägung hätte einen Ressourcenschlüssel gebraucht, den niemand ausgeliefert hat, und der
Name wäre vom Datensatz getrennt an einem zweiten Ort gelandet — mit der Löschung des einen
ohne die des anderen als naheliegendem Folgefehler. Die Spec schließt diesen Weg ausdrücklich
aus; deshalb
NameDe/NameEnam Datensatz (siehe Querschnittliche Konzepte §4).
Lokale Stack-Isolation (CAF-REPO-03)
Persistente Entwicklungsressourcen gehoeren einer App, einem kanonischen Worktree, einem vollstaendigen Branch-Ref und einer Betriebsart. Ein lesbarer Name mit Identitaetshash, ein gemeinsamer Descriptor und Ressourcenlabels verbinden Lifecycle, F5 und Endpunkte. Eigene Run-Stacks isolieren BrowserGates; Testcontainers 4.15.0 mit Ryuk bereinigt SQL-/SMTP-Testfixtures. Persistente Daten werden nicht automatisch bereinigt. Details und Abnahmen: SPEC-CAF-REPO-03.
Diese Trennung benoetigt mehr RAM und Startzeit. Gate und Clean Room begrenzen
die gleichzeitig getesteten Projekte auf hoechstens zwei; der Clean Room kann mit
-MaxParallelProjects 1 seriell laufen. Die fachlichen Parallelitaetstests
bleiben unveraendert. Mehrere Vollpruefungen sollten auf einer Workstation zeitlich
koordiniert werden. Ein gemeinsamer Stack oder eine Bereinigung anhand von Alter
und Namenspraefix wuerde fremde Daten und Nachweise gefaehrden.
RAL-QM-HP-52: Inaktivität im vorhandenen Authentifizierungsmodul
Entscheidung vom 14.09.2026: Die freigegebenen 15 Minuten Inaktivität und acht Stunden absolute Dauer werden durch einen optionalen, prozesslokalen Sitzungszustand im vorhandenen CAF-Authentication-Modul durchgesetzt. ABP-Account/OIDC bleiben der Loginpfad; keine zweite Identitäts- oder Sitzungsdatenbank. Cookie-Sliding allein scheidet aus, weil es automatischen Verkehr als Aktivität behandeln und offene Circuits nicht vor ihrer nächsten Aktion abweisen würde.
Vorteil: HTTP, offene Circuits und mehrere Tabs nutzen denselben Widerrufszustand, ohne neue Infrastruktur. Nachteil: Prozessneustart beendet alle Sitzungen; mehrere Hostinstanzen sind damit nicht freigegeben. Das ist für den vorhandenen einzelnen Interactive-Server-Host bewusst akzeptiert. Institutionsbindung und unmittelbarer Entzug nach Kontomutation liegen im Vertrag von RAL-QM-HP-18; CAF liefert dafür nur den generischen Widerruf nach Subject.
RAL-QM-HP-18: Verwaltungsrolle ohne Fallarbeit, exakter Grant-Abgleich, Widerruf nach Subject
Entscheidung vom 15.09.2026:
- Der Systemadministrator ist eine Verwaltungsrolle. Seine Grant-Komposition enthält keine
Verfahrens- und Freigaberechte mehr; Storno, Versand und Nachversand wandern zum Referenten,
die Nachversand-Freigabe zur Geschäftsführung. Alternative war ein zusätzliches
„Verwaltungsadministrator“-Profil neben einem Vollzugriffs-Administrator; verworfen, weil
Jira (US-04) genau eine Rolle „Systemadministrator“ ohne Fallarbeit verlangt und ein
zweites Vollzugriffsprofil die Vier-Augen-Regel aushöhlen würde. Das ABP-Ersteinrichtungskonto
behält seine technische Rolle
admin(Betriebszugang, App-Leitlinien); die Zusicherung gilt für Konten mit der Produktrolle. - Der Seed gleicht Grants exakt ab. Additive Seeds ließen entfernte Rechte in bestehenden
Datenbanken stehen; deshalb entzieht
HearingPortalDomainRolesDataSeedContributorje Produktrolle alles, was über die Rollen-Provider-Grants hinaus gehalten wird. Nur die vier Produktrollen werden abgeglichen, nie fremde Provider oder die technische Rolle. - Institutionskonten sind eine vierte Produktrolle mit Bindung. Statt eines Kontos „ohne
Rolle“ trägt ein Institutionskonto
RALQMInstitution(nur Portalrecht) und eine eigene Bindungstabelle an Institution und Ansprechpartner. So bleibt „genau eine Rolle je Konto“ invariant, die Kontoart ist aus der Rolle ableitbar (RoleKindMismatchverhindert Wechsel zwischen den Welten), und der Portal-Konsum der Bindung (RAL-QM-HP-30/RAL-QM-HP-31) hat einen Ort. - Kein Löschen, Papierkorb. Konten werden per Soft Delete aus der Sicht genommen und sind wiederherstellbar; der Vertrag kennt keinen Delete-Pfad. Bindung, Verlauf und Verfahrensbezüge bleiben erhalten.
- Sitzungswiderruf nach Principal in CAF, Fachlogik im Produkt.
CAFSessionStore.RevokeSubjectist generisch (welche Sitzungen enden; Schlüssel ist derNameIdentifierdes Cookies, mit ABP Identity die lokale Benutzer-Id); wann er ausgelöst wird (Sperre, Kennungswechsel, Papierkorb) entscheidet der Kontodienst über den Host-PortIAccountSessionRevoker.RevokeUser. Die Sperre wirkt dreifach — Keycloakenabled=falseplus Provider-Logout, Security Stamp, CAF- Sitzung —, weil ein einzelner Mechanismus (nur ABP-Stamp alle fünf Minuten) die geforderte Wirkung „bei der nächsten Aktion“ nicht garantiert. - Einladungszustand ohne eigene Tabelle. Sendezeitpunkt als ExtraProperty des Benutzers, Annahme aus dem Keycloak-Zustand; ein nicht erreichbarer Provider degradiert zu „unbekannt“. Keycloak-Action-Tokens sind nicht widerrufbar — die Lebensdauer von 7 Tagen ist die Grenze (Spec O3).
Details, Akzeptanzkriterien und Nachweise: SPEC-RAL-QM-HP-18.
ADR-08 · Operativer Empfängerstand im Portal und geschützte Erinnerungsunterlagen
Status: angenommen durch Benutzerentscheidung vom 29.09.2026.
Kontext: SPEC-RAL-QM-HP-6 und SPEC-RAL-QM-HP-30 nannten unterschiedliche Anschriftenstände für das Portal. SPEC-RAL-QM-HP-33 verlangte zugeordnete Unterlagen in Erinnerungen, ohne deren Übertragungsform festzulegen.
Entscheidung: Das Portal zeigt den operativen Empfängerstand der Beteiligung. Änderungen der Stammdaten wirken erst nach ausdrücklicher Übernahme; diese Übernahme wird sofort im Portal sichtbar. Jede Aussendung behält ihren eigenen unveränderlichen Empfängerbeleg. Erinnerungen verweisen auf die der Institution zugeordneten Unterlagen über die bestehenden authentifizierten, tokenfreien Portalrouten. Der Download prüft bei jedem Aufruf Bindung, Teilnahme und Grant.
Der lokale Transportnachweis verwendet den bestehenden Mailhog-Stack (vom Benutzer als „Mailhawk“ bezeichnet). Eine spätere Exchange-SMTP-Anbindung und authentifizierte Rückmeldungen für Bounces bleiben im Integrationsumfang von SPEC-RAL-QM-HP-24 offen; SMTP-Annahme ist kein Empfangsnachweis. Es wird kein produktiver Anbieter oder Callback-Vertrag vorweggenommen.
Konsequenz: Portal und neu vorbereitete Nachrichten verwenden denselben operativen Stand; historische Belege ändern sich nicht. Erinnerungslinks verleihen kein Zugriffsrecht und bleiben nach Grantentzug gesperrt. SPEC-RAL-QM-HP-23 AC-4 bleibt hinsichtlich Bounces ausdrücklich teilweise erfüllt.
ADR-09 · Freigabe, Empfänger, Erinnerungen und Übergabe
Status: angenommen durch Quizantworten und Präzisierungen des Benutzers vom 30.09.2026. Umsetzung und Nachweise stehen in den bestehenden Specs zu RAL-QM-HP-68, RAL-QM-HP-69, RAL-QM-HP-70, RAL-QM-HP-71, RAL-QM-HP-72.
- Die Geschäftsführung darf ein noch nicht versandtes Verfahren aus
ApprovednachDraftzurücknehmen, um einen dauerhaft ungültigen Empfänger zu korrigieren. Frühere Entscheidungen und Hashes bleiben erhalten; die aktuelle Freigabe wird entwertet. Erneute Einreichung und Vier-Augen-Freigabe sind Pflicht. Die Rücknahme verlangt keine Wartefrist. - Bei internen Entscheidungsbenachrichtigungen beginnen 72 Stunden mit dem ersten fehlgeschlagenen Empfängerabgleich. Danach pausiert der Auftrag zur fachlichen Klärung, ohne weitere automatische Versuche. Technische SMTP-Fehler behalten ihre bisherigen Retries. Die Geschäftsführung bestätigt eine Fortsetzung an den wieder erreichbaren ursprünglichen oder den ausdrücklich ausgewählten aktuellen Zuständigen. Ein verknüpfter Folgeauftrag trägt Empfänger, Akteur und Vorgangskennung; der ursprüngliche Auftrag bleibt unverändert.
- Automatische Erinnerungen, die erst nach dem wirksamen individuellen UTC-Fristtag ausgeführt werden, enden ohne Nachricht mit „Frist bereits abgelaufen“. Ihre frühere Fälligkeit erlaubt keinen verspäteten Versand. Der geschützte Bericht zeigt die Einreihung sofort, SMTP-Übergaben, Fehlschläge und offene Aufträge getrennt. Eine kurze E-Mail verweist auf ihn nach Abschluss aller Aufträge, spätestens nach 24 Stunden als ausdrücklich unvollständiger Zwischenbericht. Dies ist keine Retry-Grenze. Manuelle Auswahl bleibt über Seiten erhalten, wird vor dem Auftrag bestätigt und für jedes gewählte Ziel erneut am Server geprüft.
- Pro Institution bleibt eine Beteiligung und eine Stellungnahme. Der Standardkontakt wird vorgeschlagen; weitere aktive Kontakte derselben Institution werden ausdrücklich gewählt. Genau ein organisatorischer Primärempfänger bleibt Quelle des operativen Portalstands. Alle Gewählten erhalten alle relevanten Nachrichten. Personenbezogene Kontobindung und Autorisierung bleiben unabhängig davon. Hauptempfänger müssen unterschiedliche Adressen haben. Vertretungskopien gelten je gewähltem Kontakt: keine Kopie an dessen eigene Adresse, aber mögliche Mehrfachkopien für mehrere vertretene Kontakte, auch an andere Hauptempfänger.
- Reguläre Kontodeaktivierung verlangt vorherige vollständige Übergabe offener Zuständigkeiten.
Eine ausdrücklich dringende Kontosperre bleibt möglich. Unerwartet verwaiste Verfahren stehen
in einer separaten Klärungsliste der Geschäftsführung. Deren persönlicher Arbeitsvorrat bleibt
auf
PendingApprovalbegrenzt; weitere Leitungsaufgaben aus RAL-QM-HP-46/RAL-QM-HP-51 sind separat zu entscheiden. Die bestehende Anlageberechtigung und Zuständigkeit des aktiven internen Erstellers bleiben erhalten. Nur das ausdrücklich gewählte Übergabeziel muss aktiver Referent sein; eine aktive Geschäftsführung als Ersteller ist allein wegen ihrer Rolle kein verwaister Zuständiger.
Konsequenzen: Hearings besitzt zusätzliche Empfängerstände, Berichte und fachliche Klärung. Authorization besitzt Kontoeignung und Sperre; beide kommunizieren über schmale Contracts. Historische Empfänger und Aufträge werden weder still neu adressiert noch durch Stammdaten ersetzt. RAL-QM-HP-73, RAL-QM-HP-74, RAL-QM-HP-75 sind technische Korrekturen; der Pager-Behelf entfällt erst nach gemessenem Paketfix.
ADR-10 · Antwortfolge lesend vor dem gemeinsamen Abgabeabschluss vorbereiten
Status: angenommen für den angeforderten Implementierungsstart RAL-QM-HP-40 am 29.09.2026; technischer Teilschnitt, am 30.09.2026 nach Integration von RAL-QM-HP-38 um den unten beschriebenen Schreibwechsel erweitert. Keine Freigabe der offenen Rechtstexte aus RAL-QM-HP-39.
Kontext: Der bestehende Abgabeweg speichert eine Antwort vor deren Anlagen und erlaubt danach Änderungen. RAL-QM-HP-38/RAL-QM-HP-39 müssen Anlagen und versionierte Zustimmung atomar mit dem finalen Abschluss verbinden. Eine vorgezogene Unveränderlichkeit würde den einzigen Uploadweg sperren; eine vorgezogene Indexöffnung ließe alte Schreiber beliebige Zeilen ändern.
Entscheidung: Zuerst positive Sequenz, kompatible Antwortliste und deterministische Auswahl des aktuellen Gesamtstands auf dem bestehenden Aggregat implementieren. Altzeilen erhalten Sequenz 1. Beide Unique-Indizes bleiben auf aktive Zeilen gefiltert, der bisherige Einzelantwortindex bleibt zusätzlich bestehen. Leser liefern alle eigenen Beiträge und verwenden für Kategorieentscheidungen nur den letzten je Teilnahme. Legacy-Schreiber weisen mehrere Antworten bzw. eine alleinige spätere Sequenz ab. Keine wirksame Frist sperrt das Fenster gemäß dem bestehenden Fachvertrag.
Konsequenzen: Bestehende Anlagen bleiben nutzbar; Leser und Regressionen sind vor dem
Schreibwechsel vorbereitet. Bis zum gemeinsamen Abschluss ist genau eine aktive Antwort
persistierbar und weiterhin über den Legacy-Weg änderbar. Zusätzlicher Index und kompatibles
Response-Feld sind Übergangskosten. Ergänzungsendpunkt, Operation-ID/Retry, atomare Sequenzvergabe,
Zustimmung und Persistenzschutz werden gemeinsam nachgeführt; die Story bleibt teilweise offen.
Details und Nachweise: SPEC-RAL-QM-HP-40.
Fortführung nach Integration von RAL-QM-HP-38 (30.09.2026): Der atomare Anlagenabschluss ist jetzt vorhanden. Die aktuelle RAL-QM-HP-38-Spec ordnet Zustimmung und Unveränderlichkeit jeweils RAL-QM-HP-39 bzw. RAL-QM-HP-40 zu. Der angeforderte Ausbau von !155 liefert deshalb den technischen Schreibwechsel: Erstabgabe und explizite Ergänzung mit eigenem Inhalt, serverseitige Sequenz unter Teilnehmerreservierung, akteur- und inhaltsgebundene Auftragswiederholung sowie Festschreibung gegen Änderungen und Löschung. Der Einzelantwortindex wird bei diesem gemeinsamen Wechsel auf Sequenz 1 begrenzt; der alte Änderungsendpunkt weist deterministisch ab. Historische Antworten und Dateien bleiben erhalten. Leser verwenden weiterhin den jüngsten Gesamtstand.
Verbleibende Grenze: RAL-QM-HP-39 besitzt weiterhin Textkatalog, fachliche Freigabe, zwei ausdrückliche Bestätigungen und deren Nachweis pro Abgabe. Das wird weder durch ein automatisches Häkchen noch durch erfundene Texte ersetzt. Die vollständige Zustimmungsaussage von RAL-QM-HP-40 AC-3 bleibt offen; die technische Ergänzung wird getrennt davon nachgewiesen. Die Stufengrenze ist damit eine Liefergrenze und keine Behauptung, die rechtlichen Voraussetzungen seien bereits erfüllt.
ADR-11 · Zustimmungen als eigenes Feature-Modul Consents
Status: angenommen am 01.10.2026 (Product Owner, Festlegungen F2–F4 in SPEC-RAL-QM-HP-39). Die Anforderung selbst ist von RAL nicht bestätigt (F1); Inhalt und Freigabe der Texte bleiben dort.
Kontext: Zwei Kontaktpunkte verlangen eine nachweisbare Bestätigung derselben zwei Texte: die Annahme eines Institutionskontos (Authorization) und jede Abgabe (Hearings). Die Texte brauchen Fassungen mit Gültigkeitsdatum und eine Pflegeoberfläche. Keycloak besitzt Passwort und E-Mail-Bestätigung; seine Required-Action „Terms and Conditions“ kennt weder Fassungen noch zwei getrennte Bestätigungen und speichert den Nachweis nur als Benutzerattribut beim Anbieter.
Entscheidung: Ein sechster fachlicher Slice Features/Consents besitzt Fassungskatalog,
Pflege, Nachweise und den Aktivierungsschritt. Authorization verlangt in seiner einzigen
Zugangsprüfung zusätzlich den Aktivierungsnachweis und bietet für den Zustimmungsschritt den
Aktivierungskandidaten an (alle Bedingungen außer dem Nachweis). Hearings schreibt den
Abgabenachweis über einen In-Process-Port in der umgebenden Unit of Work. Die Zustimmungsseite
liegt im Portal (Hearings Blazor), der gemeinsame Bestätigungsbaustein in Produkt UI.Blazor.
Fassungen und Nachweise sind reine Einfügetabellen; Ändern und Löschen werden abgewiesen.
Konsequenzen: Ein Nachweis ist genau dann vorhanden, wenn Aktivierung bzw. Abgabe gelungen
ist, weil er in derselben Datenbanktransaktion entsteht. Authorization und Hearings erhalten je
eine Kante auf Consents.Contracts; Consents selbst kennt nur Authorization-Contracts. Ohne
veröffentlichte Fassung sind Aktivierung und Abgabe gesperrt, also muss der Betrieb nach dem
Deployment zuerst beide Texte veröffentlichen. Bestandskonten werden beim nächsten Portalaufruf
zur Zustimmungsseite geführt. RAL-QM-HP-31 AC-1 („ohne weiteren Freischaltschritt“) gilt seitdem mit
genau diesem einen Schritt. Löschfristen der Nachweise sind offen (Datenschutzkonzept, RAL-QM-HP-67).
ADR-12 · Bestandsabruf der öffentlichen Anzeige mit Keycloak Client Credentials
Status: angenommen durch Benutzerentscheidung vom 01.10.2026 zu RAL-QM-HP-47 (O1–O3).
Kontext: Die Website soll laufende, freigegebene Anhörungen ohne redaktionelle Pflege zeigen. Der Betreiber und sein Übernahmeweg sind nicht bekannt. Bisher hatte die Anwendung keinen eingehenden Maschinenzugang; Keycloak ist der einzige Aussteller.
Entscheidung:
1. Abgleich als Pull: Die Website ruft den Bestand ab (GET /api/gz/hearings/public), voll
oder ab einem Cursor mit Änderungen und Entfernungen unter der stabilen öffentlichen Kennung.
Ein Push an die Website entfällt, bis ein Betreiber einen Übernahmevertrag nennt.
2. Authentisierung über Keycloak Client Credentials und ein eigenes JWT-Bearer-Schema im
Hearings-Runtime, nie Standardschema; Zulassung über Audience und eine Liste erlaubter Clients.
Kein statischer API-Schlüssel, keine Übernahme eines alten Klartextschlüssels.
3. Projektion: Titel, Gütezeichen, Verfahrensart, Frist sowie Kennung und Änderungszeitpunkt;
keine Institutionen, keine Kurzbeschreibung. Keine Zeitsteuerung: sichtbar, solange gekennzeichnet
und Approved/Dispatched. Der Änderungszeitpunkt berücksichtigt die Änderungszeit der
Werteliste-Einträge, deren Namen geliefert werden; die Namen sind immer de-DE. Der Abruf läuft
hinter der Aufrufbremse hearing-portal (Review !177).
Konsequenzen: Neues Paket Microsoft.AspNetCore.Authentication.JwtBearer im Hearings-Runtime.
Der Keycloak-Client wird im Kundenrealm angelegt, wenn der Betreiber feststeht; bis dahin ist der
Abruf ausgeschaltet. Übernahmequittung, Störungsmeldung und „letzter erfolgreicher Abgleich“ setzen
eine Rückmeldung der Website voraus; sie kamen mit RAL-QM-HP-78
als Quittung zum Pull (ADR-20), samt Seitenbildung des Abrufs.
ADR-13 · Statische Produktfehler ohne Datenbank und Circuit
Kontext: Eine unbekannte Adresse soll mit 404 im Produktlayout antworten, ein technischer Fehler außerhalb von Development mit 500. Die vollständige interaktive Shell lädt Menüs, Rechte, Settings und Übersetzungen aus dem Backend; derselbe Ausfall kann daher auch die Fehlerdarstellung verhindern. Ein erneuter Router-Aufruf würde die fehlgeschlagene Seite wieder öffnen.
Entscheidung (RAL-QM-HP-80, 2026-10-02): Der Host rendert ErrorDocument direkt über
RazorComponentResult, mit ShellErrorView und bestehendem Cohesion-/Portal-Template.
Nur ausgelieferte DE/EN-JSON-Texte, neutrale Links und die serverseitige Vorgangskennung
gehen in diesen Pfad. Die Institutionsrolle wählt ausschließlich die datenfreie Darstellung.
HTTP-Status und no-store bleiben erhalten; Maschinenpfade und Account-MVC sind separat.
Konsequenz: Fehlerseiten funktionieren ohne Circuit und ohne Datenbankzugriff. Dynamisch gepflegte Language-Management-Texte erscheinen dort nicht; die shipped ABP-403/404-Wortlaute werden gegen den komponierten Localizer getestet. Serverseitige Fachautorisierung, Cookie- AccessDeniedPath und Framework-Reconnect-Logik bleiben unverändert. Kriterien und Nachweise: SPEC-RAL-QM-HP-80.
ADR-14 · Empfänger ohne Stammdatenkontakt aus einer Kontaktmeldung
Status: angenommen am 02.10.2026 (Abdurrahman Ates, Entscheidung E1 in SPEC-RAL-QM-HP-41).
Kontext: Empfänger einer Beteiligung war bisher immer ein aktiver Kontakt derselben Institution (SPEC-RAL-QM-HP-6, Fachregel 4). Eine Institution kann im laufenden Verfahren eine andere Kontaktperson melden. Soll diese Person nur dieses eine Verfahren betreuen, wäre ein Stammdatenkontakt falsch: Er gälte für jedes künftige Verfahren und füllte die Stammdaten mit Personen, die dort nicht geführt werden sollen.
Entscheidung: Ein operativer Empfängerstand darf ohne Stammdatenkontakt bestehen, wenn er aus einer übernommenen Kontaktmeldung mit dem Ziel „nur dieses Verfahren“ stammt. Hearings schreibt dann Anredeform, Titel, Name, Funktion (als Anzeigename) und E-Mail der Person in den Stand der Beteiligung und leert den Kontaktbezug. Die Kontaktmeldung ist ein eigener Datensatz neben dem Verfahren, kein Kind des Verfahrensaggregats; sie hält Inhalt, Zustand, Entscheidung und Ziel fest. Die Herkunft des Empfängers wird nicht gespeichert, sondern abgeleitet: Die Beteiligung hat keinen Kontaktbezug, und ihre jüngste übernommene oder ersetzte Meldung hat das Ziel „nur dieses Verfahren“. Der andere Weg bleibt die Übernahme in die Stammdaten: Institutions legt über den schmalen Vertrag „einen Kontakt hinzufügen“ einen Kontakt an, Hearings wechselt den Empfänger über den vorhandenen Empfängerwechsel – beides in einer serialisierbaren Transaktion, alle Prüfungen vor dem ersten Speicherschritt.
Konsequenzen: Für einen solchen Empfänger gibt es keinen Abgleich mit den Stammdaten, keine Standübernahme und keine Vertretungskopie; die Anschrift der Institution bleibt. Zusätzliche Empfänger bleiben wählbar, die frühere Sperre „keine Auswahl ohne Kontaktbezug“ entfällt. Zurück zu einem Stammdatenkontakt führt der vorhandene Empfängerwechsel; danach trägt der Empfänger den Zusatz nicht mehr. Eine Verfahrenskopie nimmt den Standardkontakt. Eine Beteiligung, deren Kontaktbezug schon vorher leer war und die nie eine solche Meldung hatte, gilt weiter als „Kontakt fehlt“. SPEC-RAL-QM-HP-6 bleibt unverändert; die Ausnahme steht hier und in SPEC-RAL-QM-HP-41, Fachregel 7.
ADR-15 · Organisationsanmeldung über Keycloak-Brokering mit portalgeführtem Ausfallweg
Status: angenommen durch Benutzerentscheidung vom 06.10.2026 zu RAL-QM-HP-63 (O1–O3). (ADR-14 ist RAL-QM-HP-41, ADR-16 ist RAL-QM-HP-50.)
Kontext: Interne Mitarbeitende sollen sich mit der Kennung eines vorgeschalteten Organisationsdienstes anmelden; fällt er aus, mit den bei Keycloak verwalteten Zugangsdaten. Das Portal kennt Benutzer nur über das Keycloak-Subject und darf keinen zweiten Aussteller und keine automatische Kontoübernahme bekommen.
Entscheidung:
1. Brokering, anbieterneutral: Keycloak bindet den Dienst als OIDC-Identity-Provider
organisation an (feste Endpunkte, PKCE, Signatur über JWKS). Ein brokered Login endet im
bestehenden Keycloak-Benutzer — dasselbe Subject wie beim Passwortweg, also dieselbe lokale
ABP-Projektion. Nachweis gegen einen zweiten Keycloak-Realm als simulierten Dienst.
2. Kontrollierte Zuordnung: Der First-Broker-Login-Ablauf besteht nur aus „Deny Access“.
Zugang hat allein ein Organisationskonto, dessen Kennung der Systemadministrator am Konto
hinterlegt hat (Keycloak-Federated-Identity, gesetzt über den Provisionierungsclient). Das
Portal verweigert eine Kennung, die bereits einem anderen Konto gehört — Keycloak selbst
ließe sie doppelt zu (gemessen mit 26.7).
3. Ausfallweg im Portal: Ein Hintergrunddienst prüft das Discovery-Dokument (60 s, 3/3
Entprellung); ein globaler Schalter (eigenes Recht, Sicherheitsprotokoll) erzwingt den
Ausfallweg. Beides ändert nur das Angebot der Anmeldeseite; die Passwortanmeldung bei
Keycloak ist immer möglich und unverändert geprüft. Der Organisationsknopf öffnet dieselbe
ABP-Anmeldung mit kc_idp_hint.
4. Nachweis des Wegs: Keycloak-Ereignisse (LOGIN, IDENTITY_PROVIDER_*) und der Claim
identity_provider; das Portal schreibt je validierter Rückkehr einen Eintrag ins
ABP-Sicherheitsprotokoll (Weg, Benutzer, Subject; Zeit und IP von ABP).
Konsequenzen: Keine neue Tabelle; die Zuordnung lebt in Keycloak. Weil Keycloak sie nicht
eindeutig hält, laufen alle Zuordnungs-Schreibvorgänge unter einer SQL-Server-Anwendungssperre
(sp_getapplock, transaktionsgebunden, instanzübergreifend) und danach unter der Kontoreservierung,
die auch der Kennungswechsel nimmt; jede Änderung erhöht die Revision des Kontos (Review !220).
Abschalten deaktiviert einen vorhandenen Provider, statt ihn liegen zu lassen. Alle internen Konten
behalten ihr Einladungs-Passwort; ein Entzug im Organisationsverzeichnis wirkt nicht auf den
Ausfallweg (Deaktivierung im Portal, kein Verzeichnisabgleich). Der Ausfallzustand ist
prozesslokal; mehrere Instanzen prüfen jeweils selbst. Ein eingerichteter zweiter Faktor wird seit
RAL-QM-HP-11 auch nach der Organisationsanmeldung abgefragt (ADR-19, Post-Broker-Login-Ablauf).
ADR-16 · Schadsoftwareprüfung zentral in CAF Documents mit ClamAV
Status: angenommen durch Benutzerentscheidung vom 05.10.2026 zu RAL-QM-HP-50 (O1–O3). (ADR-14 ist RAL-QM-HP-41, ADR-15 ist RAL-QM-HP-63.)
Kontext: Hochgeladene Dateien dürfen erst nach einer erfolgreichen Schadsoftwareprüfung
ausgeliefert werden. Bytes verlassen das System über zwölf Produktwege, darunter Downloads,
ZIP-Export, Mailanhang und Kopien, sowie über den Share-Link. Alle Produktwege laufen über
DocumentContentOperations.OpenAsync in CAF Documents. Betrieb ist ein eigener Docker-Stack
ohne Cloud-Dienst.
Entscheidung:
1. ClamAV (clamd) über INSTREAM auf TCP, ohne Zusatzpaket, als Container in jedem Stack.
2. Durchsetzung in CAF Documents: Der Prüfstand liegt als internes ExtraProperty am
ABP-Deskriptor; gesperrt wird an beiden Lesepunkten, jeweils nach der Fachautorisierung des
Aufrufers. Der dauerhafte Prüfauftrag ist eine CAF-eigene Tabelle CAFDocumentScanJobs neben
ABP File Management, wie die Share-Grants; Metadaten und Inhalt werden nicht dupliziert.
3. Sofortige Prüfung beim Upload mit begrenzter Wartezeit. Bei Befall wird abgewiesen, ohne
Ergebnis gespeichert und gesperrt, der Auftrag prüft nach. Ein fehlender Befund ist nie
unbedenklich, auch nicht im Altbestand.
4. Was das Produkt selbst rendert, gilt als unbedenklich (DocumentContentOrigin.SystemGenerated,
architekturgetestet auf drei Erzeuger); eine Kopie übernimmt den Befund der Quelle.
Konsequenzen:
- Kein Abschalter: Ohne erreichbaren Scanner bleibt alles gesperrt.
- Jeder Stack braucht den Dienst; der Development-Stack bekommt dafür den Port CLAMAV_PORT.
Bestehende Stack-Beschreibungen werden beim nächsten Start nachgerüstet.
- Signaturaktualisierung braucht ausgehenden Zugang zu database.clamav.net.
- Die Produkte lesen den Prüfstand aus DocumentDescriptorDto.ScanState und zeigen ihn an. Eine
gestörte Prüfung oder ein Befall erscheint über ein lokales Ereignis auf der Störungsseite.
ADR-17 · Rückläufer über ein IMAP-Postfach mit signierter Message-ID je Versandversuch
Status: angenommen durch Benutzerentscheidung vom 08.10.2026 zu RAL-QM-HP-76 (Eingangsweg, Zuordnung, Klärung, Testquelle).
Kontext: Unzustellbarkeitsmeldungen des Mailtransports sollen automatisch dem betroffenen
Versandversuch zugeordnet werden. RAL hat Transport und Testquelle nicht benannt; das Portal
versendet über ABPs IEmailSender (SMTP). Eine öffentliche, ungesicherte Rückmeldeschnittstelle und
eine Zuordnung über die E-Mail-Adresse sind ausgeschlossen.
Entscheidung:
1. Eingang über ein eigenes Postfach per IMAP (MailKit), Abruf durch einen Hintergrunddienst;
jede Nachricht in eigener Transaktion, Verschieben erst nach dem Commit. Ausgewertet werden
RFC-3464-Meldungen; nur Action: failed zählt.
2. Signierte Message-ID je Versuch (<ralqm.{Zeile}.{Versuch}.{HMAC}@{Domain}>). Zuordnung nur bei
genau einer Referenz mit gültiger Signatur; zustandslos, nichts wird je Mail gespeichert.
3. Klärungsliste für alles andere (Tabelle RALQMHearingDeliveryReports, eigenes Recht, kein
Meldungstext, Erledigen mit Begründung, keine manuelle Zuordnung).
4. Die Zuordnung nutzt dieselbe Regel wie der interne Erfassungsweg aus RAL-QM-HP-24
(HearingBounceRecorder); Dubletten über die Meldungsreferenz.
Konsequenzen: Neues Paket MailKit (MimeKit) im Hearings-Runtime. Ohne Signierschlüssel bleibt der Versand unverändert und keine Meldung ist zuordenbar; das Abschalten des Postfachs lässt Meldungen beim Transport liegen. Den Schlüssel zu wechseln macht bereits versendete Referenzen unzuordenbar (sie landen in der Klärung). Ein Empfänger kann mit der Message-ID seiner eigenen Mail nur deren Zustellung als gescheitert melden. Development/Local nutzen GreenMail; die Abnahme mit dem realen RAL-Transport ist offen.
ADR-18 · Rundnachrichten als eigener Kontext der Outbox im Hearings-Feature
Status: angenommen durch Benutzerentscheidung vom 09.10.2026 zu RAL-QM-HP-77 (Vorschlag O7 aus RAL-QM-HP-24).
Kontext: Ein Referent soll eine Rundnachricht an alle Institutionen einer Gruppe senden, ohne dass
es ein Verfahren gibt. Die Outbox verlangte bisher je Zeile eine HearingId; der Vorlagenkatalog
kannte nur verfahrensbezogene Zwecke. Ein Dummy-Verfahren oder Guid.Empty ist ausgeschlossen, ebenso
eine vorsorgliche Herauslösung eines CAF-Kommunikationsbausteins.
Entscheidung:
1. Eigenes Aggregat HearingCircular im Hearings-Feature (Tabelle RALQMHearingCirculars): Entwurf
mit Gruppe (nur Id und Name), Wortlaut mit Platzhaltern und Anhängen; genau ein Versand, danach
unveränderlich. Seine Id ist die Vorgangskennung.
2. Kontextart der Outbox: HearingId ist nullable, CircularId neu; ein Check-Constraint
verlangt genau eines von beiden. Schlüssel circular:{Rundnachricht}:{Institution}, Batch = Rundnachricht.
Versand, Wiederholung, Unzustellbarkeit (ADR-17) und Störungen laufen über dieselbe Outbox;
der Verfahrensverlauf entfällt, weil es kein Verfahren gibt.
3. Eigener Vorlagenzweck Circular (90) im Katalog, nur als Nachricht, nur verfahrensfreie
Platzhalter; er gehört zu keinem Vorlagensatz eines Verfahrens (HearingParticipantMessageKinds
bleibt unverändert, HearingTemplatePurposes = Katalog).
4. Gruppen und Kontakte kommen über Institutions.Contracts; die Vertretung löst weiterhin nur der
HearingOutboxManager auf. Anhänge laufen über den CAF-Dokumentport und gehen erst nach
freigegebener Schadsoftwareprüfung hinaus.
Konsequenzen: Code, der Outbox-Zeilen liest, muss eine Zeile ohne Verfahren vertragen (Postausgang, Rückläufer-Verlauf, Störungen). Die Verfahrensseiten sehen Rundnachrichten nicht. Eine korrigierte Neuzustellung (RAL-QM-HP-35) gibt es für Rundnachrichten nicht; „Erneut senden“ im Postausgang wirkt wie bei jeder Zeile.
Referenzen
- Laufendes ADR-Register mit Vor-/Nachteil je einzelner Konvention:
docs/conventions-decisions.md - Gesamtarchitektur inkl. Modulverzeichnis und Abhängigkeitstabelle: Bausteinsicht; Qualitätsnetz: Querschnittliche Konzepte §7
- Nachvollziehbarkeit der Entscheidungsumsetzung je Arbeitsschritt: Git-Historie und Merge Requests.
- Vertiefung Bausteine/Schnitt: Bausteinsicht; Vorgaben für neue Features:
Entwicklungsleitfaden,
conventions/
ADR-19 · Zweiter Faktor über Keycloak-TOTP mit persistentem Rücksetzauftrag
Status: angenommen durch Benutzerentscheidung vom 13.10.2026 zu RAL-QM-HP-11 (O1–O3, Zusammenspiel mit RAL-QM-HP-63). (ADR-18 ist RAL-QM-HP-77.) Die begrenzte Sprachregel in Punkt 5 wurde durch person-001 am 19.10.2026 bestätigt.
Kontext: Interne und Institutionskonten sollen freiwillig einen zweiten Faktor einrichten und selbst entfernen können; bei Verlust setzt ihn ausschließlich ein Systemadministrator zurück. Keycloak ist alleinige Stelle für Passwörter, Faktor-Geheimnisse und Authentifizierung; das Portal darf kein Geheimnis, keinen Code und kein Passwort sehen.
Entscheidung:
1. TOTP über Keycloak-Aktionen (O1): Einrichten über die anwendungsinitiierte Aktion
CONFIGURE_TOTP, Entfernen über delete_credential:{id} mit max_age=0 (frische
Passworteingabe). Der Rundweg folgt dem Passwortwechsel aus RAL-QM-HP-13: Einmal-Token im
OIDC-State, Ergebnis serverseitig im validierten Ticket. Ob sich etwas geändert hat, entscheidet
danach der Credential-Bestand bei Keycloak, nicht der gemeldete Status. TOTP-Parameter
(SHA1, 6 Stellen, 30 s) stehen ausdrücklich in Realm-Import und Abgleich; jede
Authenticator-App genügt, ein Firmengerät ist nicht nötig.
2. Sitzungen bei Selbstbedienung (O3): Nach Einrichten oder Entfernen enden alle anderen
Provider- und CAF-Sitzungen, der Security Stamp wird erneuert; die aktuelle Sitzung bleibt.
3. Persistenter Rücksetzauftrag (O2): Eigenes Recht RALQM.Accounts.ResetSecondFactor, nur
Systemadministrator, nie das eigene Konto. Der Auftrag (RALQMSecondFactorResetOrders, Id =
Operation-ID des Dialogs) bindet die beim Lesen gesehenen OTP-Credential-Ids und läuft in
Schritten mit je eigener Unit of Work: Faktor entfernen → Provider-Sitzungen beenden, Stamp
erneuern, Kontoverlauf (eine Einheit) → CAF-Sitzungen widerrufen → Benachrichtigung. Ein
Teilfehler hinterlässt einen offenen, in der Kontenübersicht sichtbaren Auftrag; derselbe Aufruf
setzt ihn fort, auch nach einem Neustart. Ein gefilterter Unique-Index lässt je Konto nur einen
Auftrag mit offenen Sicherheitsschritten zu ([Step] < 30); ein Auftrag, der nur noch auf die
Benachrichtigung wartet, sperrt den nächsten nicht. Der Concurrency-Stamp verhindert, dass ein
paralleler Versuch einen Schritt doppelt schreibt; die Benachrichtigung wird vor dem Versand am
Auftrag beansprucht (NoticeAttemptedAtUtc, zwei Minuten), sodass parallele Fortsetzungen sie
einmal senden. Sie nennt den Rücksetzzeitpunkt, nicht den Versandzeitpunkt. Die
Identitätsprüfung geschieht außerhalb des Portals und wird im Dialog bestätigt.
4. Organisationsanmeldung (HP-63): Der Organisations-IdP erhält den Post-Broker-Login-Ablauf
ralqm-organisation-post-login-otp (bedingter Unterablauf: „Condition - user configured“ →
„OTP Form“, danach ein Pflichtschritt „Allow access“). Wer einen Faktor eingerichtet hat, wird
auf jedem Weg danach gefragt. Der Pflichtschritt ist nötig, weil Keycloak einen Ablauf ohne
ausgeführten Schritt als gescheiterte Anmeldung wertet.
5. Sprache der Rücksetzbenachrichtigung (Benutzerentscheidung vom 19.10.2026):
HP101/ADR-22 bleibt die einzige Quelle: internes Kontoprofil bzw. gebundener Institutionskontakt,
mit der dortigen getrennten Eigenkonto-Sprachaktion. Für neue administrative Faktor-Resetaufträge
wird die aktuell aktive Empfängerpräferenz festgeschrieben. Fehlende oder inaktive Präferenz
bedeutet für diese Sicherheitsmail Deutsch, auch wenn HP101s globaler Standard anders lautet.
Es entsteht keine zusätzliche Beschränkung auf zwei Kulturen: eine weitere aktive HP101-Kultur
bleibt gültig. Erstbearbeiter, späterer Administrator, Worker, Präferenzwechsel und spätere
Deaktivierung einer Sprache ändern den Snapshot nicht. Bestehende Aufträge ohne Snapshot
verwenden Deutsch. Die Lokalisierung von Betreff/Text und die Darstellung des ursprünglichen
UTC-Rücksetzzeitpunkts folgen diesem Snapshot und HP101s Formatter (E26); Empfängeradresse und
Anzeigename werden weiterhin beim Versand aus dem Konto gelesen. Die Mail als Ganzes ist
kein Snapshot. Alle übrigen Mail-/Kontakt-/Fallbackregeln aus HP101
und ADR-22 bleiben unverändert.
Konsequenzen: Eine neue Tabelle mit Migration. Fehlversuche beim Code zählen auf die bestehende Brute-Force-Sperre von Keycloak (AC-4), es gibt keinen Portalzähler. Ist Keycloak direkt nach dem Rundweg nicht lesbar, meldet das Portal „nicht bestätigt“, verbraucht den Vorgang nicht und bietet „Erneut prüfen“ an, solange das Einmal-Token gilt (15 Minuten); erst die Prüfung wendet die Sitzungsfolgen an. Recovery-Codes, E-Mail-OTP und ein zweiter Genehmiger sind nicht beauftragt.
ADR-20 · Website-Abgleich mit Quittung, Seitenbildung und Fristüberwachung
Status: angenommen durch Benutzerentscheidung vom 14.10.2026 zu RAL-QM-HP-78 (O1–O4).
Kontext: ADR-12 liefert den Bestand als Pull, sieht aber nicht, ob die Website ihn übernimmt. Der Betreiber steht weiter nicht fest. Der Abruf hatte weder Seitenbildung noch Obergrenze (Review !177, H9).
Entscheidung:
1. Pull mit Quittung (O1): Die Website ruft wie bisher ab. Danach meldet sie mit
POST /api/gz/hearings/public/receipts je Kennung den übernommenen Änderungszeitpunkt zurück;
eine Entfernung meldet sie mit removed. Es gelten derselbe Client, dieselbe Policy und dieselbe
Aufrufbremse wie beim Abruf. Das Portal hält je Kennung den zuletzt bestätigten Stand fest
(RALQMHearingPublicationConfirmations, Id = öffentliche Kennung). Der Stand bewegt sich nur
vorwärts. Angenommen wird nur ein Stand, den der Abruf geliefert hat oder liefert: nicht neuer
als der aktuelle und zum gleichen Zeitpunkt von gleicher Art. Zwei gleichzeitige Quittungen für
eine Kennung: Eine gewinnt, die andere erhält 409 und sendet erneut. Jede Quittung, auch eine
leere, ist eine Zeile in RALQMHearingPublicationReceipts; die jüngste ist der letzte
erfolgreiche Abgleich. Ein Abruf allein zählt nicht.
2. Testgegenstelle (O2): Der Website-Client entsteht im Kundenrealm durch
reconcile-website-client.sh, nur wenn KEYCLOAK_WEBSITE_CLIENT_SECRET gesetzt ist. Er ist ein
reiner Maschinenclient ohne Rollen, mit der Audience ral-qualitymarks-publication-feed.
Nachgewiesen wird mit einem echten Keycloak-Token. Die Abnahme mit dem realen Betreiber steht aus.
3. Frist (O3): Hearings:PublicationSync:StaleAfter, Vorgabe 60 Minuten. Der Abgleich ist
überfällig, wenn eine öffentliche Änderung oder Entfernung länger unbestätigt bleibt, und
stumm, wenn die Website so lange keine Quittung sendet. Der HearingPublicationSyncWorker
prüft im Takt CheckInterval (fünf Minuten) und meldet das als Störung der Quelle
PublicationSync, final, also mit einer Betriebsbenachrichtigung je Ausfall. Mit dem nächsten
gesunden Lauf ist die Störung aufgelöst. Jeder Ausfall ist eine eigene Störung; ihre Id leitet
sich aus der Zahl der früheren ab, damit zwei Instanzen dieselbe nennen. Offene, letzte und
Anzahl stammen aus einer einzigen Abfrage (Review !262). Ein Rückfall innerhalb
einer Frist nach der Auflösung öffnet dieselbe Störung wieder, ohne neue Benachrichtigung. Beide
Fristen laufen frühestens ab dem Start der Anwendung mit eingeschaltetem Abruf. Ist der Abruf
ausgeschaltet, wird nichts geprüft.
4. Seitenbildung (O4): Der Abruf liefert höchstens 500 Einträge je Seite (pageSize, Vorgabe
und Obergrenze). Die Fortsetzung continuation setzt nach der letzten öffentlichen Kennung in
der Sortierung der Datenbank fort (Keyset, nicht Offset). Alle Seiten eines Abrufs tragen den
Cursor der ersten. IsComplete ist nur auf der letzten Seite eines vollständigen Abrufs wahr;
erst dann entfernt die Website, was ihr fehlt. Eine Quittung trägt höchstens 500 Einträge.
Ein vollständiger Abruf liefert zusätzlich die Entfernungen, deren Quittung noch aussteht, mit
ihrer Änderungszeit (Review !262). Eine Website, die sich nach einer Unterbrechung mit einem
vollständigen Abruf neu verbindet, kann sie so bestätigen.
5. Vertrag der Quittung: Die Website quittiert nach jedem Abruf, mindestens alle 15 Minuten,
auch ohne Einträge, und gibt die Änderungszeit genau so zurück, wie sie geliefert wurde. Eine
bestätigte, aber nicht mehr aktuelle Kennung nennt die Antwort unter outdated. Das gilt auch
für Entfernungen: Eine verspätete Quittung einer früheren Entfernung schließt eine spätere nicht
(Review !262).
6. Abgleich im Deploy (Review !262): Der Website-Client gehört zum Client-Scope.
reconcile-client.sh bindet reconcile-website-client.sh selbst ein, damit auch der
Deploy-Einstieg, der nur den Client-Scope ausführt, ihn anlegt.
Konsequenzen:
- Zwei neue Tabellen (Migration AddHearingPublicationSync), eine neue Störungsquelle und ein
neuer Worker.
- Die Störungsseite zeigt den letzten erfolgreichen Abgleich und die offenen Bestätigungen.
- Quittungen älter als ReceiptRetention (30 Tage) werden gelöscht, die jüngste bleibt.
- Bisherige Aufrufer erhalten höchstens 500 Einträge und eine Fortsetzung; IsComplete gilt
erst für die letzte Seite.
- Die Website muss nach jedem Abruf quittieren, auch wenn sie nichts übernimmt; sonst gilt der
Abgleich nach der Frist als stumm.
RAL-QM-HP-31: Feste Institutionsbindung ersetzt Gast und Claim (17.09.2026)
Entschieden durch Annahme der Spec: Authorization besitzt Zuordnung, Kontoeignung und Bindungswiderruf/-rücknahme; Hearings konsumiert nur den prozessinternen Reader und besitzt Teilnahme, Fristen und Grants. Mehrere Konten teilen die Beteiligungen ihrer Institution. Permission allein, E-Mail, Providergruppe, URL und historische Teilnahmebindung reichen nie. Jede Operation liest aktuelle Zustände. Schreibzugriff und Widerruf sind serialisiert; Bindungsaktionen nehmen vor dem Lesen eine eigene Zeilenschreibsperre und prüfen Stempel, Operation-ID und Akteur. Wiederherstellung verändert weder Kontosperre noch Teilnahmeentzug. Die vorhandenen Unique-Indizes und ExtraProperties genügen; keine Schemaänderung.
Gast-/Claim-Fachdienste, Kontexttransport und UI entfallen vollständig. Historische Zeilen bleiben erhalten. Alte Einstiege führen datenfrei zum Login, alte Downloads liefern 404. CAF-Bearer-Shares sind nur im HearingPortal-Host deaktiviert (O2); CAF bleibt unverändert. Bindungswiderruf lässt Konto-Selbstbedienung zu (O1). RAL-QM-HP-52-Sitzungswerte bleiben 15 Minuten Inaktivität und acht Stunden absolut. Die integrierte Kopfzeile verwendet den bestehenden OwnAccount-Vertrag; es entsteht kein zweites Profilformular. Browserabnahmen bleiben optional und ungeprüft, bis ein entsprechender Lauf angefordert und bestanden ist.
Ergänzung RAL-QM-HP-5 (18.09.2026): Neben Kontosperre und Bindungswiderruf (beide in
Authorization) tritt der gezielte Zugangsentzug je Beteiligung als dritter, eigenständiger
Mechanismus in Hearings (HearingParticipant.AccessRevokedAtUtc, AC-10). Er ändert weder Konto
noch Bindung: Die Bindung bleibt bestehen, die Institution bleibt beteiligt, nur dieses eine
Verfahren ist für alle Konten der Institution im Portal unerreichbar, und die Wiederfreigabe
braucht weder eine neue Einladung noch eine Aussendung. Wie die anderen Zustände wird er bei
jedem Portalaufruf gelesen, nie in der Sitzung gehalten (AC-9).
ADR-21 · Produktweiter Bestands- und Recovery-Schutz über Prozessverträge
Datum: 15.10.2026 · Status: entschieden, Umsetzung und aktuelle Nachweise in RAL-QM-HP-65.
Kontext: Der bestätigte Wiederanlaufschutz aus AC-14 muss Ablage- und Verfahrensdateien vor weiteren Schreib- oder Löschzugriffen sperren. Ein Restore verändert auch ausschließlich produktseitige Dokumentreferenzen. Ein Hook allein am CAF-Inhaltsport erreicht diesen Weg nicht; ein SaveChanges-Hook wäre für nicht transaktionale Datei-I/O zu spät. Die bisherige vollständig einseitige Runtime-Contracts-Kante aus RAL-QM-HP-16 genügt deshalb für diesen neuen Umfang nicht.
Entscheidung: Filing besitzt die zentrale Fristpolicy, Bestandsprüfung und externe
Recoverygeneration. Hearings.Runtime konsumiert die schmalen prozesslokalen Verträge
IFilingStorageMutationGate, die Löschbefundprüfung und IFilingRetentionExecutionPolicy
aus Filing.Contracts. Diese Verträge erzeugen oder committen keine Unit of Work. Der Aufrufer
tritt nach Beginn seiner vorhandenen transaktionalen ABP-Unit-of-Work ein; die externe
Mutationslease bleibt bis zu deren Dispose nach Commit/Rollback erhalten. Ein Revisionsmarker
gehört in dieselbe Transaktion. Verschachtelte Aufrufe teilen den gehaltenen Lease, jede eigene
Transaktion zeichnet ihren Stand auf. CAF-Upload-/Ablage-/Share-Verträge werden nur in dieser
Produktkomposition über native ABP-Interception eingebunden. CAF besitzt keine RAL-Policy.
Die zentrale Policyzeile serialisiert Änderungen und den tatsächlichen automatischen Vollzug. Der besitzende Fachbaustein behält Objektregeln, Reservierung, dauerhaften Auftrag und Historie. Systemursache wird ohne erfundenes Benutzerkonto gespeichert; manuelles Vorziehen ist eine zusätzliche menschliche Anforderung und ersetzt den ursprünglichen Auslöser nicht.
Grenzen: Kein Runtimezyklus, keine fremden Entities/Repositories/Tabellen, kein allgemeiner Usage-Provider und keine zweite Uploadpipeline. Filing.Contracts bleibt frei von Hearings- und CAF-Runtimeabhängigkeiten. Die bisherige Ablage-Verfahrensintegration und ihr Verwendungsnachweis bleiben Filing-orchestriert. Eine eigene Querschnittsplattform wird nicht eingeführt.
Betrieb: Recovery ist standardmäßig aus. Aktiviert ohne gültige externe Generation und eindeutigen produktiven Prüfer bleibt die Komposition geschlossen. Vor dem Datenbank-Restore rotiert der Betrieb die außerhalb des Backups geführte Generation nach Drain der Mutationen. Erst ein vollständiger unveränderter Prüflauf genau dieser Generation und eine ausdrückliche separat berechtigte Freigabe heben die Sperre auf. Eine Datenbankwiederherstellung ohne diesen Betriebsschritt wird damit nicht automatisch erkannt. Normale Mutationen nach Freigabe machen laufende Beobachtungen veraltet; sie erzwingen keine erneute Generationfreigabe nach jedem Upload.
Verworfen: Ein neuer generischer UoW-/Repositorywrapper, ein Host-SaveChanges-Mechanismus für alle Dateizugriffe und eine präventive neue Crosscutting-Projektfamilie. Die bestehende ABP-UoW und schmale bestehende Modulgrenzen tragen die benötigte Verantwortung.
Nachweise: Die Graph-Gegenfälle erlauben Hearings.Runtime → Filing.Contracts und verweigern
Hearings.Runtime → Filing.Runtime. FilingStorageMutationGateTests prüfen reale ABP-UoW-Lebenszyklen;
Datei-/SQL-/Gegenproben und die endgültige Abnahme werden in der Spec von RAL-QM-HP-65 geführt.
ADR-22 · Kommunikationssprache als Eigenschaft des Empfängers, aufgelöst je Postausgangszeile
Status: angenommen durch Benutzerentscheidung vom 14.10.2026 (person-004) zu RAL-QM-HP-101, fachliche Bestätigung durch person-001 im MR-Review.
Kontext: Verfahrensnachrichten gingen in der Sprache des Bearbeiters bzw. fest auf Deutsch hinaus; Katalogvorlagen kannten genau Deutsch und Englisch unter eigenen Kennungen. Institutionen mit nicht deutschsprachigen Ansprechpartnern sollen ihre Nachrichten in ihrer Sprache erhalten, ohne dass die Anwendung auf zwei Sprachen festgelegt bleibt oder Empfänger selbst etwas pflegen.
Entscheidung:
1. Sprachen aus der Sprachverwaltung. Aktive Sprachen und Standardsprache sind die der ABP
Language Management (ILanguageProvider, Abp.Localization.DefaultLanguage); Hearings rechnet
Kulturnamen nicht um. Katalogvorlagen tragen je aktiver Sprache einen Text, der Text der
Standardsprache ist Pflicht. Die Altkennungen de/en stellt der Migrator einmalig und
wiederholbar auf die Kulturnamen um und meldet strukturiert. Wortgleiche Kopien des
Standardtexts unter weiteren Sprachen entfernt er in jeder Vorlage und meldet jede (E11).
2. Sprache am Kontakt, wirksam beim Einreihen. Die Kommunikationssprache steht am
Institutionskontakt (Pflege mit RALQM.Institutions.Update); leer, unbekannt oder inaktiv heißt
Standardsprache; eine gespeicherte, später deaktivierte Sprache bleibt stehen, blockiert kein
Speichern und gilt bis zur Änderung als Standardsprache (E12). Jede Postausgangszeile friert die wirksame Sprache ihres Empfängers im Moment
des Einreihens ein; die Vertretungskopie ist identisch. Spätere Änderungen erreichen nur spätere
Zeilen.
3. Auflösung im Renderer, nicht im Sendeweg. Kein Sendeweg nennt eine Sprache. Der Renderer
kennt den geladenen Beteiligten und den gewählten Zusatzempfänger und löst die Sprache dort auf,
wo er auch Anrede und Stand einfriert; der Postausgangsmanager schreibt die gemeldete Sprache auf
die Zeile. Ein Renderer, der für eine solche Anforderung keine Sprache nennt, ist ein
Programmierfehler, kein stiller Standard. Interne Mails gehen je Empfänger in dessen
Kommunikationssprache hinaus (ergänzt am 16.10.2026, E26, E27).
4. Sprachstände je Zweck und Sprache. Der Kommunikationsschritt ist eindeutig je Verfahren,
Zweck und Sprache; bearbeitet wird wie in der Textvorlagenverwaltung – „Anpassen pro Sprache“ öffnet
die Bezugssprache lesend neben der bearbeitbaren Zielsprache –, nur in den Sprachen der Empfänger. Ein Speichern sperrt andere Sprachen nicht, es weist auf sie
hin. Der Ausgabestempel umfasst alle Sprachstände. Nach der Browserprüfung (Entscheidungen vom
16.10.2026, E15, E16, E19–E21, Vereinfachung vom selben Tag): die Empfängerliste nennt alle Institutionen
mit ihrer Sprache, Abweichung und Endfassung folgen der Sprache der gewählten Institution, die
Zielsprachenwahl nennt die Empfänger je Sprache, Bezugs- und Zielsprache sind nie dieselbe, Nachfrage vor
dem Verwerfen beim Wechsel von Sprache, Institution oder Zweck, ein gesperrter Sprachstand vergleicht nur
mit deaktivierten Feldern; englische Datumswerte sind ausgeschrieben (E22).
5. Rückfall statt Abweisung, aber gekennzeichnet. Fehlt eine Sprachfassung im gebundenen Satz
oder als Sprachstand, antwortet der aktuelle Text der Standardsprache; Nachsehen friert nichts
ein, ohne eigenen Text spiegelt die Sprache den Standardtext, erst ein eigener Text macht den
Sprachstand eigenständig (E13). Der Rückfall steht am Sprachstand (IsFallback,
SourceCultureName) und an der Zeile (ContentCultureName) und wird in Vorschau, Zustellstatus
und Postausgang gezeigt. Eine weitere Stufe gibt es nicht.
6. Rohdaten im Modell, Format im Renderer. Datumswerte reisen als yyyy-MM-dd, der Renderer
schreibt das Kurzdatum der Zeilensprache; der Antwortabsatz der Bescheidung wird aus Erwiderung
und Votum in der Zeilensprache zusammengesetzt. Freie Texte (Begründungen, Erwiderungen) werden
nicht übersetzt. Ressourcentexte der Nachrichten und des Begleitschreibens kommen je
Zeilensprache; der Dateiname des Begleitschreibens bleibt als technischer Bezeichner deutsch (E14).
Konsequenzen: Eine Migration (AddCommunicationLanguage: CommunicationLanguage am Kontakt; IsFallback
und eindeutiger Index der Sprachstände; ContentCultureName an der Postausgangszeile, CultureName am
Auftrag der Eingangsbestätigung).
Die Eingangsbestätigung friert die Sprache beim Speichern ihres Auftrags ein. Das Modell einer Welle
ist für alle Empfänger dasselbe; nur der Text je Zeile unterscheidet sich.
Ergänzung vom 16.10.2026 (person-004, Auftrag vom 12.10.2026):
7. Konten folgen dem Kontakt, der Anmeldedienst wird zuerst gefragt. Ein Empfänger mit Portalkonto
ändert die Sprache seines eigenen Kontakts am eigenen Konto; Mitarbeitende tragen eine eigene Sprache
am Konto (Anlage optional, Verwaltung und Selbstbedienung). Jede Sprachänderung setzt zuerst das
locale-Attribut des Anmeldedienstes; nimmt er sie nicht an, wird die ganze Änderung abgewiesen und
nichts gespeichert (E23). Institutions meldet geänderte Kontaktsprachen vor dem Speichern über einen
Synchronisationsvertrag, den Authorization implementiert; die Selbstbedienung schreibt den gebundenen
Kontakt über einen Schreibvertrag von Institutions. Kontomails des Anmeldedienstes und der Anwendung
folgen der Kontosprache; der Kontoverlauf hält jede Änderung fest (E24).
8. Interne Mails je Empfänger; Rundnachricht je Sprache. Interne Mails nennen die Sprache jedes
Empfängers, Zeitpunkte wie in den Empfängernachrichten (E26); Berichtsdokumente bleiben in der
Standardsprache (E27). Die Rundnachricht trägt einen Text je Empfängersprache (Standardsprache
Pflicht, weitere ganz oder gar nicht, E34) und geht je Institution in der Sprache ihres Standardkontakts
hinaus, ohne eigenen Text mit dem gekennzeichneten Standardtext (E28, E29). Die Story-Migration wurde
dafür neu erzeugt (E31).
ADR-23 · RAL-Keycloak-Kundentheme mit anwendungseigener Erweiterung
Datum: 19.10.2026 · Status: entschieden auf Benutzerauftrag zu RAL-QM-HP-102, D1–D3 bestätigt; Implementierung und aktuelle Abnahme werden in der Spec nachgewiesen. ADR-22 beschreibt die inzwischen integrierte Kommunikationssprache RAL-QM-HP-101.
Kontext: Die RAL-Anmeldung soll das vorhandene Kundendesign aufnehmen. Der HearingPortal-Client
verwendet bereits das app-eigene ralqm-legal mit Rechtsfooter und Korrekturen der nativen
Label-/Control-Zuordnung. Die reale Abnahme zeigt: Ein abgelaufener nativer Einladungslink
verliert vor der Tokenvalidierung seinen Clientkontext und damit ein ausschließlich am Client
gewähltes Theme. Das kundenweite Basistheme muss deshalb auch den Realm-Rückfall abdecken;
app-eigene Rechtsziele dürfen ohne Clientkontext nicht geraten werden. TOTP und Kontenaktionen
sind vorhandene Keycloak-Funktionen und bleiben beim Provider.
Entscheidung:
- Das kundenweite Basistheme
ral-v1liegt unterapplications/RAL/etc/docker/shared/keycloak/themes/ral-v1und erbtkeycloak.v2. Das bestehende RAL-/HearingPortal-Produktdesign liefert Farb- und Layoutreferenz. Die Themequellen setzen diese in lokalem CSS um. Für dieses Theme stehen im Repository keine freigegebenen RAL-Logo- oder DIN-Pro-Dateien bereit; verwendet werden Systemschrift (system-ui,Segoe UI, Sans-Serif) und die native Realmbezeichnung. Neue Logo-/Fontdateien werden damit nicht als geliefert behauptet. Es gibt keine neuen Font-/CDN-/Trackinganfragen und keine Abhängigkeit auf CAF- oder HearingPortal-Laufzeitprojekte. - Das app-eigene
ralqm-legalerbtral-v1und behält Rechtsfooter, DE/EN-Meldungen sowie die bestehenden Korrekturen intemplate.ftlundlogin-config-totp.ftl. Rechtsziele entstehen weiterhin ausschließlich aus der Client-BaseUrl, mitno-referrer. Formaktionen, Schutzparameter, native Fehler und vorhandene TOTP-Abläufe bleiben erhalten. - Die erste Aktivierung betrifft den bestehenden RAL-Realm
ral. Sein Standard istral-v1, der HearingPortal-Client behält den Overrideralqm-legal. Clientlose Ablauf-/Fehlerseiten und Clients ohne eigenen Override erhalten dadurch nur die Kundenbasis, ohne HP-Rechtsfooter oder erfundene Rückkehradresse. Dies präzisiert D2 nach dem realen Ablaufbefund vom 19.10.2026; native Mail-Links bleiben unverändert. Der geteilte Reconciler wähltral-v1ausschließlich fürral; andere Realms einschließlichral-logolicensebehaltenkeycloak.v2. Admin-/Account-Console, fremde Organisations-IdPs, Mailthemes und fachliche Authentisierungsregeln werden nicht umgebaut. Deren Anmeldung innerhalbralerbt gegebenenfalls die Kundenbasis. - Hell/Dunkel folgt der Betriebssystempräferenz mit Light als neutralem Default. Es gibt keinen neuen Präferenzspeicher und keine Übertragung des Portal-localStorage über Origins.
- Beide Themeverzeichnisse werden gemeinsam über die bestehenden Container-/Fixture-/CI-Wege
ausgeliefert und gegen das gepinnte Keycloak-Image geprüft. Der Rückfall stellt die vorherige
versionierte
ralqm-legal-Fassung mit direktemparent=keycloak.v2wieder her. Rechtsfooter und bestehende A11y-Korrekturen bleiben dabei erhalten. Zusätzlich wird nur der Realm-Default vonralauf den vorherigen Wertkeycloak.v2zurückgestellt; der Clientoverride bleibt erhalten. Der frühere Reconciler-/Importstand gehört deshalb zum Rückfall. Ein Kunden-Deployment ist nicht Bestandteil dieses Auftrags.
Konsequenzen: Die gemeinsame Kundenmarke und die app-eigene Rechtsnavigation behalten getrennte Ownership. Die zusätzliche Parentstufe verlangt einen realen Nachweis, dass Styles, lokale Assets, DE/EN-Meldungen und die vorhandenen App-Overrides zusammen auf allen erreichbaren Providerseiten funktionieren. Bei Keycloak-Upgrades werden die gepinnten App-Templates und die Themevererbung abgeglichen. Keine neue UI-Fassade, Authentifizierungsplattform oder Laufzeitabhängigkeit entsteht. Die Entscheidung bestätigt weder erfüllte ACs noch einen erfolgreichen Rollout; Nachweise bleiben in der Spec von RAL-QM-HP-102.
10. Qualitätsanforderungen
Dieses Kapitel benennt, welche Qualitätsmerkmale für das RAL Gütezeichen Anhörungsportal verbindlich sind, und macht sie an konkreten, prüfbaren Szenarien fest. Architekturentscheidungen in Bausteinsicht und Querschnittliche Konzepte werden gegen genau diese Anforderungen getroffen; Risiken und technische Schulden benennt, wo sie aktuell nur teilweise erfüllt sind.
10.1 Qualitätsbaum
Der ausschlaggebende Werttreiber ist ein rechtssicherer, nachvollziehbarer Anhörungsprozess auf einer Plattform, die als modularer Monolith langfristig ohne Umbau der Kernarchitektur weiterentwickelbar bleibt (vgl. Einführung und Ziele). Daraus leiten sich fünf gleichrangige Qualitätsäste ab, die im Projekt jeweils durch Architektur und durchsetzende Tests abgesichert sind statt nur dokumentiert zu werden (CLAUDE.md):
Qualität RAL-Gütezeichen-Anhörungsportal
├─ Wartbarkeit
│ ├─ No-Layer-Modulgrenzen (Contracts vs. Runtime vs. Blazor)
│ ├─ Compile-Time durchgesetzte Abhängigkeitsrichtung
│ └─ Proportionalität (keine vorsorglichen Abstraktionen ohne Consumer)
├─ Sicherheit
│ ├─ OIDC-Authentifizierung über Keycloak, lokale ABP-Autorisierung
│ ├─ Objektberechtigung je Zugriffsweg (intern, Institutionskonto, Direktfreigabe; übergangsweise Gast)
│ └─ Least-Privilege-Infrastruktur (DB-Principal, Keycloak-Provisioning-Client)
├─ Barrierefreiheit
│ ├─ WCAG 2.1 AA als Mindestziel
│ ├─ Cohesion als einzige Fach-UI-Bibliothek
│ └─ automatisierte axe-Prüfung im BrowserGate
├─ Testbarkeit und Verlässlichkeit
│ ├─ Nachweismatrix je Änderungsart (Unit/Integration/SQL/Browser)
│ ├─ Quality Gate je Push (Git-Hooks)
│ └─ zuverlässige Nebenwirkungen (Outbox, Idempotenz, Retry)
└─ Datenerhalt
├─ Data-preserving Migrationen bei Renames
├─ optimistische Concurrency auf mutablen Aggregaten
└─ kein Hard Delete fachlicher Prozessdaten
10.2 Qualitätsszenarien
Jedes Szenario folgt dem Muster Stimulus → Reaktion → Nachweis. Die ID-Präfixe entsprechen den Ästen aus 10.1.
Wartbarkeit (WB)
| ID | Szenario | Erwartete Reaktion | Nachweis |
|---|---|---|---|
| WB-01 | Ein Entwickler ergänzt in CAF.Applications.RAL.QualityMarks.HearingPortal.Hearings einen ProjectReference auf die Institutions-Runtime statt auf Institutions.Contracts. |
Der Build schlägt architektonisch fehl; die verbotene Kante GZ-Runtime → fremde GZ-Runtime ist untersagt (siehe Bausteinsicht §5.2.6). |
Architekturtests auf Projekt-/Paketkanten, Teil des Quality Gate |
| WB-02 | Ein Framework-Baustein (CAF.Modules.*) referenziert versehentlich einen CAF.Applications.RAL.QualityMarks.HearingPortal.*-Namespace oder ein GZ-Fachwort. |
Referenz wird als Verstoß gegen die Framework-Neutralität erkannt und blockiert. | Architekturtests (Namespace-/Kantenscan), Vertragsdatei VERTRAG.md je Baustein |
| WB-03 | Ein neues Feld wird an Hearing ergänzt, obwohl UI/Consumer es nicht benötigen. |
Contract-DTO bleibt unverändert; Änderung erfolgt zuerst am Aggregate mit benannter Operation (DEVELOPMENT-GUIDE.md §14). | Code-Review anhand der Nachweismatrix, EF-Mapping- und Migrationstest |
| WB-04 | Ein neues Modul wird mit dem Namen Common oder Utils angelegt. |
Ablehnung im Review; Ownership-Frage aus dem Entscheidungsbaum ist nicht beantwortet. | Konvention in DEVELOPMENT-GUIDE.md §2 |
| WB-05 | Ein Paket-/API-Element wird als „nicht mehr benötigt“ entfernt. | Entfernung gilt erst nach Restore-/Publish-/Endpoint-Scan als vollständig; reine Quelltextlöschung genügt nicht. | Nachweismatrix „Paket-/API-Entfernung“ (DEVELOPMENT-GUIDE.md §15.1) |
Sicherheit (SI)
| ID | Szenario | Erwartete Reaktion | Nachweis |
|---|---|---|---|
| SI-01 | Ein Benutzer ruft eine geschützte Anhörungsseite ohne gültige Keycloak-Session auf. | OIDC Authorization Code mit PKCE erzwingt Anmeldung; ohne gültige Session kein Zugriff auf die Server-UI. | Authentifizierungstests in CAF.Modules.Authentication, BrowserGate-Login/Abmeldung |
| SI-02 | Ein angemeldeter Referent versucht eine Aktion, für die seine Rolle keine Permission besitzt (z. B. Verfahrensabbruch, den nur Administrator/Geschäftsführung dürfen). | Application Service lehnt serverseitig ab; ein ausgeblendeter Button gilt explizit nicht als Autorisierung. | Permission-Definition-/-Vergabe-/-Ablehnungstests, Architekturtest „jeder Endpunkt prüft Permission“ |
| SI-03 | Ein angemeldeter Nutzer eines Institutionskontos versucht, ein Dokument eines anderen Teilnehmers über eine erratene DocumentId abzurufen. |
Zugriff wird verweigert; jeder Aufruf revalidiert feste Institutionsbindung, Hearing-Status, aktiven Teilnehmer und konkreten Dokumentgrant neu – eine ID/URL allein verleiht nie Zugriff (siehe Laufzeitsicht §6.4). | Autorisierungsmatrix-Tests (positiv/negativ), Leakage-Scan, HTTP-Tests gegen den realen Hostpfad |
| SI-04 | Zwei gleichzeitige Einlösungen derselben Einladung (Konto-Übernahme; übergangsweise Gasteinladung) treffen in getrennten Transaktionen ein. | Jede Transaktion prüft Einladung und Objektzustand erneut; nur optimistische Schreibkonflikte werden begrenzt wiederholt, ein zwischenzeitlicher Widerruf bleibt wirksam. | Concurrency-/Parallelsitzungstests, BrowserGate-Parallelfall |
| SI-09 | Ein Benutzerkonto einer Institution ruft Meine Teilnahmen ab, während dieselbe Institution weitere Benutzerkonten besitzt. | Jedes Konto sieht ausschließlich die eigene Institution und die eigenen Teilnahmen (US-22c); ein Entzug des Kontos wirkt sofort und ohne Rückfallweg (US-22). | Autorisierungsmatrix-/Portaltests je Konto, Browserpfad Institutionsportal |
| SI-05 | Die Anwendungsdatenbank wird kompromittiert oder ein Entwicklungsrechner verbindet sich versehentlich mit dem SA-Zugang. | Der Host verwendet im Regelbetrieb ausschließlich den dedizierten, nicht privilegierten ralqm-Principal statt eines SA-/Admin-Logins; SA- und Keycloak-Admin-Zugang bleiben beim Setup/Reconciler (Verteilungssicht §3, HearingPortal-Betrieb, Getting Started §6). |
doctor.cmd-Kategorienprüfung, Migrations-Fast-Path-Principal-Check |
| SI-06 | Die kontrollierte Kontoprovisionierung ruft Keycloak für eine mehrdeutige Identität auf. | Der Admin-Port scheitert geschlossen (fail-closed) und vergibt keine Fachrolle automatisch; der Keycloak-Provisioning-Client besitzt ausschließlich die Rolle manage-users, keine weitere Realm-Administration. |
Adapter-, Mehrdeutigkeits- und Berechtigungstests, Test-KeycloakProvisioningClient.ps1 |
| SI-07 | Ein Client verbindet sich außerhalb der Entwicklungsumgebung unverschlüsselt. | HSTS und HTTPS-Redirect laufen vor Routing/Authentifizierung; Health-Endpunkte sind bewusst nicht ausgenommen. | Quelltext-Sentinel TransportSecurityPipelineTests |
| SI-08 | Ein direkter CAF-Dokument-Share-Link wird mehrfach erraten oder nach Ablauf verwendet. | Secret ist nur gehasht gespeichert, rate-limitiert, läuft ab und ist einzeln widerrufbar. | Sicherheits-/Delegations-/HTTP-Tests von CAF Documents |
Barrierefreiheit (BF)
| ID | Szenario | Erwartete Reaktion | Nachweis |
|---|---|---|---|
| BF-01 | Eine Fachseite (z. B. Verfahrensliste, Freigabe, Postausgang) wird gegen WCAG-2.1-AA-Kriterien geprüft. | Keine serious/critical axe-Verstöße (Kontrast, Alternativtexte, Rollen) außerhalb einer versionierten, begründeten Ausnahmeliste. |
axe-Läufe im BrowserGate über alle Fach- und Portalseiten, tests/.../BrowserGate/a11y-ausnahmen.json |
| BF-02 | Eine Tabelle mit sortierbaren Spalten (Institutionenliste, Anhörungsliste) wird ausschließlich per Tastatur bedient. | Spaltenköpfe sind fokussierbar, aria-sort wird gesetzt und per Screenreader angesagt. |
Tastatur-/Fokus-Komponententests (bUnit), BrowserGate-Tastaturpfad |
| BF-03 | Ein Statuswert (z. B. Freigabe abgelehnt, Frist überschritten) wird dargestellt. | Status ist nicht ausschließlich farblich codiert, sondern zusätzlich textuell/symbolisch erkennbar. | UI-Review anhand Querschnittliche Konzepte §5, bUnit-Rendertests |
| BF-04 | Eine datengebundene Seite befindet sich im Zustand „Laden“, „Leer“, „Fehler“, „Verboten“, „Validierung“, „Speichern“ oder „veralteter Concurrency-Stand“. | Jeder dieser Zustände ist sichtbar und bedienbar abgebildet, kein stiller Fehlzustand. | bUnit-Zustandstests je Seite, BrowserGate-Fehler-/Retry-Pfade |
| BF-05 | Fachcode versucht, eine MudBlazor-, Syncfusion- oder Blazorise-Komponente direkt zu rendern statt Cohesion zu verwenden. | Verstoß wird erkannt; ausgenommen sind allein die MVC-/Account/**-Seiten. Blazor-seitig gibt es keine Ausnahme und kein Vendor-UI-Paket mehr. |
Architektur-/Quelltextprüfung auf UI-Bibliotheksnutzung |
| BF-06 | Ein Besucher öffnet die Erklärung zur Barrierefreiheit ohne Anmeldung oder aus dem Portal. | Dieselbe anonyme Route zeigt tatsächlichen Konformitätsstand, datierte bekannte Barrieren, Zeitplan und konfigurierten E-Mail-Rückmeldeweg. Fehlende Produktionsangaben verhindern den Start. | RAL-QM-HP-79; Authentication-Options-/Renderingtests und BrowserGate customer-accessibility einschließlich Portal-Rechtsseiten |
Testbarkeit und Verlässlichkeit (TV)
| ID | Szenario | Erwartete Reaktion | Nachweis |
|---|---|---|---|
| TV-01 | Ein Entwickler pusht einen Arbeitszweig. | Der pre-push-Hook bestimmt betroffene Apps über alle Ref-Diffs und den alten/neuen Projektgraphen. Serverseitige Tests und übrige Pflichtschritte laufen; alle vier Browsergruppen sind standardmäßig aus. Reine Doku prüft Reports. Rote oder fehlende angeforderte Schritte sowie ein falscher Tipp blockieren den Push. | tools/git-hooks, Invoke-QualityGate.ps1, Git-Note refs/notes/quality-gate |
| TV-02 | Ein Pflichttest wird versehentlich übersprungen (Skip-Attribut) statt zu bestehen. |
Das gilt als Fehlschlag des Gates; es gibt keine Ausnahmeliste. | QualityGateAutomationTests (Skip-Attribut-Verbot in Testquellen) |
| TV-03 | Ein sichtbarer End-to-End-Prozess (Login, Freigabe, Portalzugang) wird geändert. | Vor Übergabe/Merge laufen die Pflichtschritte des lokalen Gates. Browserstrecke, axe, Tastatur/Fokus und Browser-Berechtigungsprüfungen bleiben optional; nur angeforderte Gruppen müssen bestehen. Der Clean Room baut BrowserGate, startet es aber nicht. Serverseitige Berechtigungstests bleiben Pflicht. | tools/scripts/Invoke-QualityGate.ps1 -App ral/qualitymarks/hearingportal; optionale Schalter im Entwicklungsleitfaden |
| TV-04 | Der Postausgang versucht, eine E-Mail zuzustellen, und der SMTP-Provider ist vorübergehend nicht erreichbar oder antwortet nicht. | Der Sendeversuch wird über die persistente Hearing-Outbox erneut versucht. Lokal entstehen dabei keine Duplikate: Der eindeutige Idempotency-Key verhindert einen zweiten Auftrag, derselbe Versuch wird nie parallel ein zweites Mal gesendet, und ein verspätetes Ergebnis überschreibt keinen neueren Versuch. Über die SMTP-Grenze gilt mindestens einmal (at-least-once): Bricht der Prozess nach der Annahme durch den Provider vor der lokalen Speicherung ab oder wird ein tatsächlich angenommener Versuch nach dem Zeitlimit aufgegeben, kann die Nachricht ein zweites Mal zugestellt werden. Diese Grenze ist angenommen (person-001, 11.10.2026; Risiken). | Retry-/Idempotenz-/Restart-Tests (HearingOutboxDispatchTests, für die Eingangsbestätigung HearingResponseReceiptSqlServerTests), Kennzahlen „Sendeversuche nach Fehlercode“ |
| TV-05 | Eine EF-Migration wird gegen eine leere Datenbank ausgeführt und anschließend dotnet ef migrations has-pending-model-changes geprüft. |
Migration läuft vollständig „from-empty“ durch; das Modell hat keine ausstehenden Änderungen. | SQL-Server-Integrationstests, Pending-Model-Check im Gate |
| TV-06 | Eine neue Fachregel/Statusübergang wird implementiert. | Positive und negative Tests decken alle relevanten Statuszellen ab, nicht nur den Erfolgspfad. | Nachweismatrix „Domainregel/Transition“ (DEVELOPMENT-GUIDE.md §15.1) |
Datenerhalt (DE)
| ID | Szenario | Erwartete Reaktion | Nachweis |
|---|---|---|---|
| DE-01 | Ein Rename benannter Identifikatoren (z. B. das RALQM-Präfix-Rework) wird auf eine Datenbank mit vorhandenen Anhörungs- und Institutionsdaten angewendet. | Die Migration ist data-preserving: bestehende Zeilen, Foreign Keys und Werte bleiben erhalten, nur Bezeichner ändern sich; historische EF-Migrationen behalten ihre alten Identifiers. | HearingPortalDbMigrationServiceTests, SQL-Server-Round-Trip-Tests, DocumentsMigrationBaselineSqlServerTests |
| DE-02 | Zwei Benutzer bearbeiten dieselbe Anhörung gleichzeitig und speichern nacheinander. | Optimistische Concurrency verhindert einen stillen Teil-Overwrite; der zweite Schreibversuch scheitert nachvollziehbar am veralteten Stand. | Concurrency-Tests gegen den realen Persistenzpfad (DEVELOPMENT-GUIDE.md §15.1) |
| DE-03 | Eine Institution soll gelöscht werden, obwohl sie noch in Teilnehmer-Snapshots oder Portal-Kontobindungen referenziert wird. | Löschung wird über den Usage-Provider verweigert; die UI erklärt den Deaktivieren-Hinweis statt eines harten Fehlers. | Kontakt-/Institutions-Löschguard-Tests |
| DE-04 | Ein laufendes Verfahren wird abgebrochen statt hart gelöscht. | Der Zustand wechselt in einen benannten Endzustand (Aborted), Einladungen/Grants/Due Actions werden widerrufen, die fachliche Historie bleibt lesbar. |
Fach-, Berechtigungs- und Historientests „Verfahrensabbruch“ |
| DE-05 | Zeitstempel werden über verschiedene Server-Instanzen hinweg verglichen (z. B. Fristberechnung). | Alle Zeitpunkte werden konsistent in UTC über ABP-Clock-Abstraktionen verarbeitet, keine lokale Serverzeit. | Zeitgrenzen-/Fristvorschlagstests |
10.3 Nicht angestrebte Qualitätsmerkmale
Entsprechend den bewusst nicht vorhandenen Nachbarn in Kontextabgrenzung §3.4 werden horizontale Skalierung über Microservices, eine zweite Datenbank, generische Workflow-/DMS-Fähigkeiten und Multi-Tenancy bewusst nicht als Qualitätsziele verfolgt. Das schont Komplexitätsbudget zugunsten der oben genannten fünf Äste; ein neuer Bedarf verlangt zuerst einen konkreten, getesteten Anwendungsfall, keine vorsorgliche Infrastruktur.
Siehe auch
- Bausteinsicht – wo die Modulgrenzen aus 10.1 technisch verankert sind
- Querschnittliche Konzepte – Sicherheits- und UI-Mechanismen im Detail
- Risiken und technische Schulden – aktuell noch offene Nachweise (z. B. integrierter BrowserGate-Lauf)
- DEVELOPMENT-GUIDE.md §15 – vollständige Nachweismatrix und Gate-Mechanik
- GETTING-STARTED.md – lokale Ausführung von Gate und BrowserGate
- conventions/security.md, conventions/testing.md – repo-weite Konventionsbaseline
- Risiken und technische Schulden – Status und Nachweistiefe je offener Fachfunktion
11. Risiken und technische Schulden
Dieses Kapitel listet bekannte Risiken und technische Schulden des aktuellen Standes. Es ersetzt
keine laufende Nachverfolgung; verbindliche Quelle für den jeweils aktuellen Stand bleiben
Git-Historie und Merge Requests. Den Plan des Monorepo-Umbaus samt der damals offenen
Vor-Push-Schritte führt
docs/history/VOR-ERSTEM-PUSH.md — abgeschlossene
Umbau-Historie, kein gültiger Statusbericht.
Übergreifender Kontext: Monorepo-Umbau vollzogen, Repository angebunden
Der Umbau zum eigenständigen Repository caf ist durchgeführt: Dieses Repository trägt eine neue
Historie ohne den alten Verlauf (ein Initialcommit chore: initialize CAF monorepo) und besitzt
die Branches main und development.
Die Remote-Anbindung ist hergestellt: origin zeigt auf
https://gitlab.com/development174835/caf, main und development sind gepusht, und die
CI-Pipeline läuft (.gitlab-ci.yml mit den Stages test, secret-detection, app-build,
app-image, deploy). Änderungen erreichen main über Merge Requests; jeder Release trägt
entsprechend einen Merge-Commit an der Spitze (05cccb5 Merge branch 'development' into
'main'). Nicht nachweisbar ist aus dem Repository heraus, ob GitLab diesen Weg serverseitig
erzwingt — dazu die Zeile „Serverseitiger main-Schutz nicht nachgewiesen" unten.
Mehrere der unten aufgeführten Risiken sind Folgen dieses Umbaus (RALQM-Umbenennung, offene
Nachweise). Den damaligen Erledigt-/Offen-Stand führt
docs/history/VOR-ERSTEM-PUSH.md; dieses Dokument liegt
zusammen mit dem ursprünglichen
Übergabeprotokoll des Quellrepositorys als
abgeschlossene Umbau-Historie unter docs/history/.
Risiko- und Schuldenübersicht
| Thema | Beschreibung | Auswirkung | Gegenmaßnahme |
|---|---|---|---|
| RAL-QM-HP-52 Stufe B | Institutionsbindung, Kontomutations-Widerruf, Einladungen und externe Profile benötigen RAL-QM-HP-18. | Stand 2026-09-18: Stufe A und B1 sind geliefert; offen bleiben B2–B4 (Spec-Status „Teilweise implementiert"). Die frühere Formulierung „Stufe A ist kein Abschluss von RAL-QM-HP-52" unterschätzt den Fortschritt. | Offene Kriterien und Cohesion-Upstream UP-708-01 in der Spec weiterführen. |
| Prozesslokale Sitzungen | Hostneustart verwirft aktive Sitzungen; mehrere Instanzen teilen keinen Zustand. | Neue Anmeldung nach Neustart; kein Scale-out-Vertrag. | Einzelhostbetrieb; verteilten Betrieb erst nach eigener Entscheidung und Tests freigeben. |
| Kontenermittlung über das Zeitverhalten der Anmeldung (RAL-QM-HP-91 E2) | Anmeldeseite und Passwortprüfung liegen in Keycloak; die Anwendung sieht keinen Fehlversuch. Die Meldung ist für unbekannte Kennung, falsches Passwort und deaktiviertes Konto gleich (RAL-QM-HP-52 AC-5). Ob die Antwortzeiten sich unterscheiden, ist nicht gemessen. | Ein Angreifer könnte über Antwortzeiten auf vorhandene Kennungen schließen. Das Restrisiko liegt bei Keycloak; im Anwendungscode ist es nicht behebbar. | Angenommen, Entscheidung von person-001 am 11.10.2026 (RAL-QM-HP-91, AC-5 entfallen). Brute-Force-Schutz des Realms aktiv (ral-realm.json: failureFactor 10, quickLoginCheckMilliSeconds 1000, minimumQuickLoginWaitSeconds 60, maxFailureWaitSeconds 900, keine Dauersperre). Keine Messung in der Anwendung: Sie wäre hardwareabhängig und instabil. Bei Keycloak-Updates die Herstellerhinweise zu Enumeration und Zeitverhalten prüfen. |
| Doppelzustellung über die SMTP-Grenze (at-least-once) | Der Postausgang (Hearing-Outbox) und die Benachrichtigungsaufträge der Eingangsbestätigung (RAL-QM-HP-35) speichern den Versanderfolg erst nach der Annahme durch den SMTP-Provider. Zwei Fenster führen zu einem zweiten Versand derselben Nachricht: (1) Der Prozess endet nach der SMTP-Annahme, aber vor der lokalen Speicherung des Erfolgs; nach dem Wiederanlauf wird der Auftrag als unterbrochen übernommen und erneut gesendet. (2) Ein Versand antwortet weder innerhalb der Wartezeit T (StuckAttemptTimeout) noch einer weiteren Beobachtungsfrist; der Versuch wird aufgegeben und neu gesendet, obwohl der Provider die erste Nachricht tatsächlich angenommen hatte. Lokal entstehen keine Duplikate: ein eindeutiger Auftrag je Nachricht, kein paralleler Zweitversand desselben Versuchs, und verspätete Ergebnisse überschreiben keinen neueren Versuch. |
Ein Empfänger kann eine Eingangsbestätigung, einen Hinweis an den zuständigen Referenten oder eine Nachricht des Postausgangs (etwa Einladung, Erinnerung oder Bescheid) zweimal erhalten. Inhalt und fachlicher Zustand bleiben richtig; es entsteht weder ein zweiter Auftrag noch eine zweite Abgabe. Belegt durch HearingOutboxDispatchTests.HungTransport_IsReleasedAfterGracePeriod_AndRetriedExactlyOnce (zwei Sendeaufrufe) und HearingResponseReceiptSqlServerTests.A_transport_without_any_answer_is_observed_once_more_then_given_up_and_the_order_is_taken_over (zwei Zustellversuche). |
Angenommen, Entscheidung von person-001 am 11.10.2026 (RAL-QM-HP-35 O6, RAL-QM-HP-37, Abschnitt Umsetzung); Szenario TV-04 in den Qualitätsanforderungen ist entsprechend korrigiert. Schließen ließe sich die Lücke nur mit einem Idempotenzschlüssel beim Provider oder einem Deduplizierungs-Header, den der Empfangsweg auswertet; beides ist nicht geplant. |
BrowserGate: hearing-workflow-Schritt create-form — erledigt am 2026-09-18 |
Der End-to-End-BrowserGate lief bis tief in die Fachworkflows grün, brach aber im Schritt create-form des Hearing-Workflows (UI-Interaktion „Anhörung anlegen") mit einem Timeout ab. Kein Rename-Rest, sondern ein eigenständiges UI-Thema. |
Der volle Quality-Gate-Lauf war für diesen einen Schritt nicht grün; die Anhörungs-Erstellung war über den BrowserGate nicht automatisiert nachgewiesen. | Nicht mehr reproduzierbar. Im vollständigen Lauf vom 2026-09-18 (41 von 41 Stufen, 1449 s, Browser gate PASSED, Cohesion 3.6.3-alpha.0.12) ist hearing-workflow in 8 s grün, ebenso in zwei vorangegangenen Läufen. Damit war es ein Lastbefund, wie der Eintrag selbst als erste Erklärung vorsah — siehe die Startprüfung in Getting Started. Die mitgeführte Frage nach der Circuit-Familie ist getrennt beantwortet und nur halb erledigt: die U16-Signatur (cohesion.resizer.detach, CohesionTextAreaInput.DisposeAsync) tritt im ganzen Lauf nicht mehr auf, und die Browserkonsole meldet über 44 geprüfte Seiten null Fehler. Die N6-Hälfte reproduziert weiterhin, 20-mal, im Hostprotokoll: TaskCanceledException aus JSRuntime.InvokeAsync über SfBaseUtils.InvokeMethod aus SfSwitch<T>.ComponentDispose (12×), SfCheckBox<T>.ComponentDispose (4×) und SfStepper.ComponentDispose (4×), jeweils als „Unhandled exception in circuit". Sie erreicht die Konsole nicht und rötet kein Gate, bleibt aber als Vendor-Lifecycle-Punkt offen (N6 → U16 im Stufe-6-Register). |
| Lokaler Keycloak-Port 8080 kollidiert — erledigt am 2026-09-18 | Der lokale Entwicklungsstack bindet Keycloak per Default auf Port 8080. Auf mindestens einer Entwicklungsumgebung belegt ein unabhängiger guacamole-Container denselben Port, wodurch Keycloak nicht binden kann und der BrowserGate-Lauf umgebungsblockiert abbricht. |
Kein Projektfehler, aber ein reproduzierbarer lokaler Blocker für Setup/BrowserGate auf betroffenen Workstations. | Gegenstandslos seit der Stackisolation (CAF-REPO-03). Der Standardport ist 18080 (etc/docker/{development,local}/.env.example), und tools/_stack_context.py vergibt KEYCLOAK_PORT je Stack dynamisch aus dem ephemeren Bereich gegen die Sperrliste in tools/stack-ports.json. Ein Fremdcontainer auf 8080 kann den Stack nicht mehr blockieren. |
| Secret-Rotation der alten Remote-URL | Das origin-Remote des Quellrepositorys enthielt einen Zugriffstoken in der URL und wurde beim Umbau entfernt; das heutige origin (https://gitlab.com/development174835/caf) enthält keines. Falls dieser Token noch nicht widerrufen/rotiert wurde, ist das eine offene externe Sicherheitslücke außerhalb des Repository-Inhalts. |
Ein potenziell noch gültiges Secret außerhalb der Kontrolle des Repositorys. | Rotation/Widerruf des Tokens außerhalb des Repositorys durchführen (GitLab-Zugriffstoken-Verwaltung); im Repository selbst ist kein Secret mehr enthalten und nichts weiter zu tun. |
| Immutabilität historischer Migrationen | Historische EF-Migrationen behalten bewusst ihre alten Bezeichner (Caf*, QualityMarks*, Gz*), auch nachdem Live-Code und -Typen auf CAF*/RALQM umbenannt wurden. Tests wie DocumentsMigrationBaselineSqlServerTests erwarten explizit die alte Migrations-Id/-Quelle (AddCafDocumentShareGrants/CafDocumentShareGrants). |
Bewusster, dauerhafter Bruch zwischen aktueller Namenskonvention und historischem Migrationsverlauf; erschwert oberflächliches „alles muss RALQM/CAF heißen"-Refactoring und verlangt Disziplin bei neuen Migrationen. | Kein Nacheditieren bestehender Migrationen. Neue Umbenennungen erfolgen ausschließlich über zusätzliche, datenbewahrende Rename-Migrationen (siehe 20260825174437_RenamePersistedIdentifiersToRALQM); Tests, die historische Bezeichner erwarten, bleiben bestehen. |
| RALQM-Datenmigration gegen reale Upgrade-Pfade unvalidiert | Die manuelle SQL-Migration 20260825174604_MigrateApplicationIdentifiersToRALQM (Permissions, Grants, Settings, Text Templates, Lokalisierung, Rollen) war laut Übergabeprotokoll noch nicht vollständig gegen einen echten SQL-Server-Upgradepfad geprüft; zwischenzeitlich wurde sie gegen eine migrierte Dev-Datenbank verifiziert (Git-Historie, Arbeitsschritte R8/R5), ein vollständiger Produktions-Upgradepfad-Nachweis steht aber weiterhin aus. |
Restrisiko bei einem realen Upgrade eines bestehenden Produktivbestands auf das RALQM-Schema. | Vor jedem produktionsnahen Einsatz erneut gegen eine repräsentative Kopie eines bestehenden Bestands migrieren und die in Qualitätsanforderungen beschriebenen SQL-Integrationstests plus Pending-Model-Check ausführen. |
| Institutionszugang: verbleibende Integration | RAL-QM-HP-31 ersetzt Gast-/Claim-Pfade durch feste Kontobindung; historische Daten vermitteln kein Recht. | Teilweise erledigt (2026-09-18): Der Browsernachweis ist mit Korrektur-MR !109 geliefert; die Spec SPEC-RAL-QM-HP-31-konto-an-institution-binden.md steht auf „Vollständig umgesetzt". Die Aussage „Browserstrecke ungeprüft (NOT_REQUESTED)" gilt nicht mehr. |
Ausführbare Service-/SQL-/Hostnachweise der RAL-QM-HP-31-Spec verwenden; verbleibende RAL-QM-HP-52-/RAL-QM-HP-13-/RAL-QM-HP-30-Abnahmen getrennt führen. |
| Verschlüsselter Portal-Link bleibt in nicht versandten Postausgangszeilen | Zeilen berechtigungstragender Nachrichtenarten tragen den umkehrbar verschlüsselten Portal-Link (HearingOutboxMessage.ProtectedPayload), bis MarkSent ihn leert. Scheitert der Versand endgültig oder wird die Zeile aufgegeben, bleibt der Link unbegrenzt gespeichert. Seit RAL-QM-HP-9 legt jede Aussendung an einen Vertretenen eine zweite Zeile mit demselben Link an, sodass sich solche Zeilen verdoppeln können. |
Abweichung von der Regel, dass die umkehrbare Zwischenablage zeitlich begrenzt ist und nach Verwendung geleert wird (Entwicklungsleitfaden §10); ein Datenbankzugriff legt die Links fehlgeschlagener Zeilen offen. | Eigene Sicherheitsfrage, nicht Teil von RAL-QM-HP-9: Payload fehlgeschlagener oder aufgegebener Zeilen nach einer Frist leeren. Zu klären ist, dass eine manuelle Wiederholung dann eine neu ausgestellte Einladung braucht (RequeueForRetry mit {{Link}} ohne Payload lässt sonst den ganzen Batch scheitern). |
| Vollständige Verifikationskette nach Umbau offen | Root- und App-Build, vollständige Architekturtests, dotnet test CAF.slnx, Pending-Model-Check, SQL-Integrationstests und das komplette Quality Gate inklusive BrowserGate/Clean Room müssen nach den letzten Änderungen noch einmal vollständig und am Stück laufen, bevor der Umbau als abgeschlossen gilt (Punkt 1 der Umbau-Historie in docs/history/VOR-ERSTEM-PUSH.md). |
Ohne diesen Gesamtlauf ist „grün" nur stückweise für Teilmengen nachgewiesen, nicht als Gesamtsystemzustand. | Teilweise erledigt (2026-09-18) — die Browserhälfte ist geliefert, die Kette nicht. Der BrowserGate ist erstmals vollständig grün gelaufen: 41 von 41 Stufen in 1449 s, console-verdict und accessibility-verdict eingeschlossen, 44 Seiten von axe geprüft, 0 Befunde (Branch fix/browsergate-ablehnungsroute auf development, Cohesion 3.6.3-alpha.0.12). Damit ist die Aussage „Browserstrecke ungeprüft (NOT_REQUESTED)" aus !121 !119 !116 !108 !101 !90 !88 gegenstandslos. Offen bleibt der Rest des Eintrags: Build, vollständige Architekturtests, dotnet test CAF.slnx, Pending-Model-Check, SQL-Integrationstests und Clean Room sind damit nicht belegt — sie liefen an diesem Tag nur stückweise und nicht am Stück, was dieser Eintrag ausdrücklich verlangt. Weiterhin gilt: vor jedem Merge/Release den vollständigen Quality Gate gemäß Entwicklungsleitfaden laufen lassen; Ergebnis nicht aus Einzelläufen extrapolieren — auch nicht aus diesem. |
Serverseitiger main-Schutz nicht nachgewiesen — belegt am 2026-09-18 |
Remote und Merge-Request-Weg sind aktiv: origin zeigt auf https://gitlab.com/development174835/caf, main und development sind gepusht, jeder Release erreicht main als Merge-Commit. Ob GitLab Direct-/Force-Push auf main blockiert und die Review-Pflicht erzwingt, ist im Repository nicht feststellbar; die Randbedingungen beschreiben den Schutz als gesetzt. |
Ohne die serverseitige Einstellung ist die dokumentierte Git-Randbedingung eine Absicht, keine Kontrolle: ein Direct-Push auf main bliebe möglich. |
Nachgewiesen, damit entfällt diese Zeile wie im Eintrag vorgesehen. Abfrage der GitLab-API (projects/.../protected_branches): main und development sind geschützt, Push und Merge jeweils nur Maintainers, allow_force_push=false. Die Randbedingung aus conventions/git.md ist damit serverseitig belegt, nicht nur beabsichtigt. |
| Ein Cohesion-Publish kann den Build röten, ohne Änderung hier | Cohesion wird mitentwickelt und deshalb bewusst nicht gepinnt, sondern über die Floating-Version 3.*-* aus dem GitLab-Gruppen-Feed bezogen (Directory.Packages.props) — höchste verfügbare 3.x inklusive Prereleases. Zwei Restores desselben Commits können unterschiedliche Versionen auflösen. |
Angenommener Trade, keine Schuld: dieser Build ist damit ein fortlaufender Integrationstest gegen Cohesion — Regressionen fallen früh auf statt beim nächsten bewussten Upgrade. Preis: ein CI-Lauf ist nicht allein durch den Commit bestimmt, und ein roter Build kann eine fremde Ursache haben. | Nicht sperren (ein Lockfile verschöbe die Entdeckung), sondern sichtbar machen: aufgelöste Cohesion-Version in start.cmd/doctor.cmd und im CI-Log ausgeben. Bei unerwartet rotem Build zuerst die Version prüfen, dann eigenen Code. Siehe UI-Rework-Plan, Stage 0. |
| Stellungnahme mit Anlagen: Blockaden beim gleichzeitigen Speichern (RAL-QM-HP-38) | Die Speicherphase einer Abgabe (Laufzeitsicht §6.4) hält drei Sperren, an denen sich zwei gleichzeitige Abgaben blockieren können: die Lesephase unter Serializable hält Bereichssperren auf RALQMHearingParticipants über die eigenen Zeilen hinaus; jede gespeicherte Datei ändert dieselbe Containerzeile des Datenbank-BLOB-Providers (AbpBlobContainers, betrifft auch Ablage und Unterlagen); jede Abgabe schreibt die Verfahrenszeile. Gemessen am 25. und 28.09.2026 gegen SQL Server ohne Wiederholung: zwei Abgaben mit je zehn Anlagen – zwei Institutionen desselben Verfahrens, zwei Konten derselben Teilnahme oder zwei Verfahren – in sieben bis zehn von zehn Versuchen ein Deadlock, bei fünf wie bei 5.000 Teilnehmerzeilen; zwei gleichzeitige Uploads allein über die Containerzeile in zehn von zehn. Die frühere Existenzprüfung vor dem Einfügen war eine vierte Ursache (60 von 60) und ist entfernt. |
Ohne Gegenmaßnahme erhielte eine von zwei gleichzeitigen Abgaben eine wiederholbare Meldung; Daten gehen nicht verloren (vollständiger Rollback, HearingResponseSubmissionSqlServerTests). Anlagen sind nur auf dem Datenbank-BLOB-Provider zulässig (Festlegung RAL-QM-HP-38). Die Datei einer gescheiterten Speicherung entfernt auf dem Dateisystem-Provider seit RAL-QM-HP-51 der Documents-Baustein (Zeile unten); was ein Prozessabbruch dazwischen zurücklässt, seit RAL-QM-HP-81 der Abgleichslauf. Die Dateien einer Abgabe liegen während des Aufrufs vollständig im Arbeitsspeicher – bei der Höchstzahl 10 und 25 MiB je Datei bis 250 MiB je gleichzeitiger Abgabe. |
Die Speicherphase wird als Deadlock-Opfer bis zu zweimal mit den gelesenen Dateien wiederholt (HearingResponseStorageRetry, Pause 100 ms mal Versuch); erst danach die wiederholbare Meldung, Eingaben und Dateien bleiben im Formular. Die Ursachen selbst sind nicht Teil von RAL-QM-HP-38: Jira-Vorgang „Blockaden beim gleichzeitigen Speichern klären“ (Bereichssperren der Lesephase, Containerzeile, Verfahrenszeile); das einzelne Speichern der Dateien lohnt, sobald Documents löschen kann. Höchstzahl und Größe je Datei bleiben Konfiguration; die Höchstzahl je Stellungnahme ist die Hearings-Einstellung ResponseAttachmentMaxCount. |
| Dateiinhalt bei Prozessabbruch und Begleitbrief des Idempotenz-Verlierers (RAL-QM-HP-51, RAL-QM-HP-24) | Seit RAL-QM-HP-51 entfernt der Documents-Baustein mit dem Dateisystem-Provider den Inhalt jeder Erstellung über IDocumentContentPort.CreateAsync, deren Unit of Work scheitert – Rollback, Fehler beim Speichern oder beim Commit selbst (Querschnitt, Documents-Vertrag); das betrifft Abschlussbericht, Begleitbriefe und Anlagen einer Stellungnahme. Seit RAL-QM-HP-81 (Umsetzung 12.10.2026) ist die prozesslokale Bereinigung nicht mehr die einzige: Ein wiederkehrender Abgleichslauf entfernt jede Datei ohne committeten Deskriptor, die älter als die Mindestzeit ist (Standard 24 Stunden) – auch nach einem Prozessende zwischen Schreiben und Bereinigung oder einer Bereinigung, die die Datenbank nicht erreichte. Der Begleitbrief eines Versandauftrags, der das Rennen um seinen Idempotenzschlüssel verliert, wird in dessen Unit of Work wieder gelöscht (vorher Altbestand RAL-QM-HP-24). Verbleibend: Bis zum nächsten Lauf nach Ablauf der Mindestzeit liegt ein Rest im Dateispeicher; ein Mandant ganz ohne Deskriptor wird nicht abgeglichen; ein Löschen, das scheitert, hinterlässt einen echten Rest (als Fehler mit Inhalts-Id und Fehlerklasse gemeldet). |
Seltene unreferenzierte Dateien im Dateispeicher, nach Ablauf der Mindestzeit beim nächsten Lauf entfernt: über Verfahren und Portal nicht erreichbar, bis dahin ein Speicher- und Datenschutzrest außerhalb jeder fachlichen Sicht. | Standardbetrieb mit dem Datenbank-BLOB-Provider. Abgleichslauf und Verlierer-Löschung RAL-QM-HP-81 (Documents-Vertrag); Fehler-Logeinträge des Documents-Bausteins sind echte Reste und betrieblich zu bearbeiten. Die Fehlerzweige von Abschluss und Upload (Löschen über IDocumentFilingPort) bleiben als zusätzliche Absicherung bestehen; sie sind neben der Bereinigung redundant (wirksam nur bei einer Abweisung vor dem Speichern, bei Speicher- oder Commitfehler scheitern sie und protokollieren eine Warnung) und durch Bestandstests abgesichert. |
| Feed-Zugang ist neue Voraussetzung für jeden Checkout | Cohesion liegt nicht mehr als .nupkg im Repository. Ohne Zugangsdaten für die Quelle cohesion schlägt bereits dotnet restore fehl. |
Ein frischer Checkout ist ohne Gruppen-Deploy-Token (lokal) bzw. Job-Token-Allowlist (CI) nicht baubar; Offline-Builds sind nicht mehr möglich. | Onboarding-Schritt in Getting Started und doctor.cmd-Prüfung (SET/MISSING); start.cmd bricht mit dem exakten Konfigurationsbefehl ab statt mit einem NuGet-401. |
Bewusst nicht als Schulden geführt
Die folgenden Punkte sind laut Qualitätsanforderungen §10.3 und Kontextabgrenzung §3.4 bewusste Auslassungen, keine offenen Risiken: kein lokaler OpenIddict-Server, keine Microservices, keine zweite GZ-Datenbank, kein PostgreSQL/Redis/RabbitMQ/Kafka/Elsa/GraphQL/Kubernetes, kein externes DMS, keine Dokumentbearbeitung/OCR/Volltextsuche/Legal-Archiv/generische Dateibrowser-UI. Ein neuer Bedarf in diese Richtung erfordert zuerst einen konkreten, getesteten Anwendungsfall, keine vorsorgliche Abstraktion.
Verwandte Kapitel
- Qualitätsanforderungen — Testarten und Gate-Aufbau, gegen die die hier gelisteten Lücken laufen.
- Bausteinsicht — Modulgrenzen und Paketierung, insbesondere zum Cohesion-Pin.
- Entwurfsentscheidungen — Begründung der RALQM-/CAF-Präfixregel und der datenbewahrenden Migrationsstrategie.
- Entwicklungsleitfaden und Getting Started — operative Schritte für lokale Infrastruktur und Quality Gate.
12. Glossar
Dieses Kapitel bündelt die verbindlichen Begriffe der Lösung. Fachbegriffe stammen aus dem
RAL-Gütezeichen-Anhörungsprozess, technische Begriffe aus der No-Layer-/ABP-Architektur des
Monorepos. Details zu den referenzierten Bausteinen stehen in der Bausteinsicht,
Randbedingungen und Namenskonventionen in den Randbedingungen; das
normative Regelwerk bleibt DEVELOPMENT-GUIDE.md und
conventions/.
Fachliche Begriffe
| Begriff | Definition |
|---|---|
| Anhörung (Hearing) | Das zentrale Verfahren: eine Institution wird zu einer geplanten Gütezeichen-Entscheidung angehört. Durchläuft die benannte Statuskette Draft → PendingApproval → Approved → Dispatched → Adjudication → Completed mit definierten Rücksprüngen/Abbruch. Eigenes Aggregat im Modul Hearings, Tabellen RALQMHearings/RALQMHearing*. |
| Ansprechpartner | Ein Kontakt einer Institution (RALQMInstitutionContacts). Seine Funktion ist seit RAL-QM-HP-4 kein Freitext mehr, sondern eine optionale Referenz (FunctionId) auf eine Ausprägung der Werteliste „Funktion eines Ansprechpartners“; ohne Angabe bleibt der Kontakt ohne Funktion. Der Bestand dieser Liste entstand vollständig aus den vorhandenen Positionstexten — sie hat, anders als die drei übrigen Listen, keinen ausgelieferten Grundbestand. Wird ein Ansprechpartner einem Verfahren hinzugefügt, heißt er dort Teilnehmer. Seit RAL-QM-HP-9 trägt ein Kontakt zusätzlich eine optionale Telefonnummer, das Kennzeichen Standardansprechpartner und wahlweise eine Vertretung (je eigener Eintrag). |
| Standardansprechpartner (RAL-QM-HP-9) | Der eine Kontakt je Institution, der das Kennzeichen IsDefault trägt: höchstens einer, und er ist immer aktiv. Hat eine Institution keinen Standard, wird der erste erfasste oder aktivierte aktive Kontakt selbsttätig Standard (A3) — beim Anlegen, im CSV-Import und im Demo-Seed über dieselbe Aggregatoperation. Der Wechsel ist eine Operation des Aggregats (Institution.SetDefaultContact) und wird in einer Transaktion als zwei Speicherschritte gespeichert (alten Standard entfernen, speichern, neuen setzen, speichern), weil der gefilterte eindeutige Index IX_RALQMInstitutionContacts_DefaultPerInstitution je Statement prüft und EF die beiden Zeilen in Schlüsselreihenfolge schreibt; für andere Verbindungen gibt es keinen Zustand ohne Standard. Der Standard kann weder deaktiviert noch entfernt werden, solange kein anderer aktiver Kontakt das Kennzeichen übernommen hat; das Pflichtpartner-Kennzeichen setzt einen aktiven Standard voraus (RAL-QM-HP-10 AC-11). Gelesen wird das Kennzeichen vom Pflichtpartner-Port und von Hearings bei der automatischen Einbindung von Pflichtpartnern sowie als Ersatz beim Kopieren eines Verfahrens; dort bleibt der zuvor gewählte aktive Kontakt vorn (E10). |
| Vertretung (RAL-QM-HP-9) | Verweis am Kontakt (DeputyContactId, DeputyFromUtc, DeputyUntilUtc) auf einen anderen aktiven Ansprechpartner derselben Institution mit Beginn und wahlweise Ende als UTC-Kalenderdatum, beide Ränder eingeschlossen (A10). Höchstens eine Vertretung je Kontakt; eine Person darf mehrere vertreten; keine Selbstvertretung, keine Ketten (die Vertretung der Vertretung erhält nichts). Wirksam, solange die Vertretung aktiv ist und der heutige Tag im Zeitraum liegt (Institution.FindEffectiveDeputy); die Deaktivierung des Vertretenen beendet sie nicht (A11). Ein als Vertretung eingetragener Kontakt kann nicht entfernt werden. Wirkung: eine unveränderte Kopie jeder Aussendung an den Vertretenen an die E-Mail-Adresse der Vertretung — als eigene Postausgangszeile, die HearingOutboxManager beim Einstellen jeder Nachrichtenart in derselben Transaktion und Batch-ID anlegt (Schlüsselsuffix :dep, derselbe verschlüsselte Link; keine Kopie bei gleicher Adresse, E12), sichtbar als weitere Zeile im Zustellstatus (nach der Hauptzeile) und in der Postausgangsverwaltung (Details). |
| Antragsteller | Die Institution oder Person, deren Gütezeichen-/Zulassungsantrag Gegenstand der Anhörung ist. Wird bei Anlage der Anhörung über eine InstitutionId referenziert, nicht dupliziert, und muss zu diesem Zeitpunkt eine aktive Institution sein (RAL-QM-HP-10, AC-9). |
| Frist | Zeitliche Grenze im Anhörungsprozess: erste und zweite Rückmeldefrist und die Frist bis zur Abschlusserinnerung, dazu die daraus abgeleiteten fälligen Aktionen (Due Actions). Beide Rückmeldefristen werden kumulativ ab demselben Befragungsbeginn gemessen — die zweite ist die Gesamtdauer, kein Zuschlag auf die erste, und muss größer als diese sein (Auslieferungswerte 56/84 Tage). Die Vorbelegung eines neuen Verfahrens kommt aus den Standardfristen seiner Verfahrensart, sonst aus den systemweiten Einstellungen, sonst aus den Auslieferungswerten; sie erreicht die Fachkraft als überschreibbarer Formularvorschlag. Ein Versand wird abgewiesen, wenn eine der beiden Rückmeldefristen bereits abgelaufen ist. Die zweite Frist bleibt im laufenden Verfahren in beide Richtungen änderbar (solange in der Zukunft und nach der ersten) — deshalb heißt die Karte „Zweite Frist ändern“ und nicht mehr „Frist verlängern“ —, bis eine Erinnerung sie genannt hat: ab deren Versand ist sie festgeschrieben (RAL-QM-HP-29 AC-7, SecondResponseDeadlineFixedAtUtc). Fristüberwachung läuft über persistente Due Actions und ABP Background Worker, nicht über Timer im Request. |
| Gütezeichen (Quality Mark) | Das RAL-Gütezeichen, dessen Verleihung/Verlängerung/Entzug den fachlichen Anlass für eine Anhörung bildet. Gibt der Anwendung ihren Domänennamen (QualityMarks) und den Kürzel RALQM. |
| Institution | Der fachliche Träger von Kontakten, Anhörungen und Pflichtpartnerbeziehungen. Eigenes Aggregat im Modul Institutions mit Anschrift, Kreis (Fachkreis oder Verkehrskreis), Pflichtpartner-Kennzeichen (seit RAL-QM-HP-10 ein eigenes Ja/Nein-Merkmal, kein dritter Kreis), interner Notiz (nur für interne Benutzer sichtbar, RAL-QM-HP-10) und mehreren Kontakten. Tabellen RALQMInstitutions/RALQMInstitutionContacts. |
| Dublette (Institution) (RAL-QM-HP-10) | Zwei Institutionsnamen gelten als gleich, wenn sie nach Entfernen aller Leerzeichen ohne Beachtung der Groß-/Kleinschreibung übereinstimmen (InstitutionNameDuplicateRule, eine Stelle in der Institutions-Runtime). Anlage und Umbenennung warnen mit Trefferliste, sperren aber nicht; kein Unique-Index. Der CSV-Import vergleicht bis RAL-QM-HP-49 weiterhin nur ohne Groß-/Kleinschreibung. |
| Laufendes Verfahren (Deaktivierungswarnung) (RAL-QM-HP-10) | Für die Zählung vor der Deaktivierung einer Institution gilt eine Anhörung als laufend, solange sie weder abgeschlossen (Completed) noch abgebrochen (Cancelled) ist; Entwürfe zählen mit. Je Verfahren zählt die Institution einmal, wenn sie Antragsteller oder nicht zurückgezogener Teilnehmer ist (SPEC-RAL-QM-HP-10 A4). Bewusst enger als der Löschschutz, der jede jemals vorhandene Teilnehmer-Referenz zählt. |
| Institutionsgruppe (RAL-QM-HP-3) | Ein verfahrensübergreifend wiederverwendbarer, benannter Beteiligtenkreis aus mehreren Institutionen, gemeinsames Stammdatum aller internen Konten. Aggregat InstitutionGroup mit den Tabellen RALQMInstitutionGroups und RALQMInstitutionGroupMembers; Name eindeutig nach der Dublettenregel, Auflösen löscht die Gruppe weich und ihre Mitgliedschaften hart. Als Ganzes in ein Verfahren im Entwurf einbindbar seit RAL-QM-HP-5 (US-13, Gruppenzuordnung: Vorschau, dann ein Speichervorgang für alle zuordenbaren Mitglieder; Übersprungene werden mit Grund genannt); für Rundnachrichten adressierbar (US-41) ist sie noch nicht. Siehe Bausteinsicht §5.2.2 und §5.2.3. |
| Mitgliedschaft (Institutionsgruppe) (RAL-QM-HP-3) | Die Zuordnung genau einer Institution zu genau einer Gruppe (InstitutionGroupMember, eindeutig je Gruppe und Institution). Sie trägt außer den beiden Verweisen keinen Inhalt und wird beim Entfernen hart gelöscht; ihr vollständiger Stand bleibt in der Entity History. Eine deaktivierte Institution bleibt Mitglied, eine gelöschte fällt still aus Liste und Zählung. |
| Kennzeichnungsart | Die Art der RAL-Kennzeichnung, um die es im Verfahren geht — ausgeliefert werden Gütezeichen, Registrierungen, Definierte Herkunft von Lebensmitteln und Made in Germany. Pflichtangabe je Verfahren, referenziert über MarkTypeId auf RALQMHearings. Bis RAL-QM-HP-4 ein C#-Enum mit Localization-Schlüsseln, seitdem eine Werteliste. |
| Referent | Produktrolle RALQMCaseOfficer: bearbeitet Anhörungen operativ (anlegen, einreichen, Teilnehmer/Dokumente pflegen, Postausgang, Vorlagen), pflegt die Institutionsstammdaten (anlegen, ändern, deaktivieren; kein Löschen, RAL-QM-HP-10), übermittelt die Bescheidungen und schließt das Verfahren ab, direkt wie einstufig (Adjudicate, Complete; RAL-QM-HP-46 Regel 1/O1, RAL-QM-HP-51 O2). Erfassen, Übermitteln und Abschließen liegen damit bewusst in einer Rolle; das Vier-Augen-Prinzip betrifft Einreichung und Freigabe. Er darf aber z. B. nicht die von ihm eingereichte Freigabe selbst erteilen (Vier-Augen-Prinzip) und besitzt kein Abbruchrecht für laufende Verfahren. |
| Zuständiger Referent (RAL-QM-HP-8) | Die benannte Person, die für ein Verfahren verantwortlich ist: Feld ResponsibleUserId des Hearing-Aggregats (lokale ABP-Benutzer-Id, kein Fremdschlüssel in die Identitätstabellen), bei der Anlage der anlegende Benutzer, danach über „Zuständigkeit übertragen“ (eigenes Recht RALQM.Hearings.TransferResponsibility, Referent und Geschäftsführung) auf ein aktives, Keycloak-gebundenes Konto mit Rolle Referent verschiebbar, solange das Verfahren nicht abgeschlossen oder abgebrochen ist. Jede Übertragung ist ein Verlaufseintrag (ResponsibilityTransferred) mit bisheriger und neuer Person. Altbestand ohne Ersteller trägt null und liest sich als „nicht zugewiesen“ — kein Sentinel, der eine Person vortäuscht. Namen werden über den schmalen Lesevertrag IStaffAccountReferenceReader des Authorization-Moduls aufgelöst; das Adressfeld für künftige interne Benachrichtigungen (RAL-QM-HP-35, RAL-QM-HP-43). |
| Rolle | Produktweite GZ-Rolle, die Grants aus den Permissions der Feature-Contracts komponiert. Drei Rollen: RALQMAdministrator, RALQMCaseOfficer (Referent), RALQMManagement (Geschäftsführung). Rollen- und Grant-Komposition liegt ausschließlich im Modul Authorization. |
| Geschäftsführung (Management) | Produktrolle RALQMManagement: erteilt u. a. die Freigabe (andere Person als die Einreichung) und die Nachversand-Freigabe und darf laufende Verfahren abbrechen; besitzt kein Referentenrecht auf Abbruch. Bescheidungsübermittlung und Abschluss gehören seit RAL-QM-HP-51 nicht mehr zu ihren Rechten (RAL-QM-HP-46 O1, RAL-QM-HP-51 O2). |
| Teilnehmer (Participant) | Ein zur Anhörung hinzugefügter Kontakt einer Institution samt Snapshot der Kontaktdaten zum Versandzeitpunkt. Kann im Entwurf zurückgezogen und wiederaufgenommen werden, ohne die Historie zu verlieren; nach dem Versand bleibt die Institution beteiligt, und der Referent kann stattdessen ihren Zugang entziehen (seit RAL-QM-HP-5). Trägt seit RAL-QM-HP-5 einen Beteiligungsgrund und seit RAL-QM-HP-6 den operativen Empfängerstand (Institution mit Anschrift, Kontakt mit Anrede, Titel, Name, Funktion, E-Mail), den jede neue Aussendung verwendet und den nur ein ausdrücklicher Befehl des Referenten ändert. |
| Kommunikationsschritt | Der bearbeitbare Wortlaut einer Aussendung je Verfahren und Zweck (RAL-QM-HP-24): einmalige Kopie des gebundenen Vorlagentexts, mit Institutionsabweichungen, gesperrt für das erste Anschreiben ab der Einreichung und für jeden Zweck ab der ersten Postausgangszeile. |
| Begleitdokument | Das PDF-Anschreiben einer Teilnehmeraussendung (RAL-QM-HP-24): Briefkopf mit dem Organisationsabsender des Erzeugungsmoments, Anschrift aus dem Empfängerstand, Ansprechperson, Datum, Betreff, Wortlaut, Zeichnung; über CAF Documents abgelegt, als Anhang an die Nachricht derselben Beteiligung gehängt, von der Vertretungskopie geteilt. Gilt für jede Nachrichtenart außer der Endfassungsbenachrichtigung (FinalVersionDelivery, 70): Sie trägt seit RAL-QM-HP-51 (E4) kein Begleitdokument und keinen Anhang (zentrale Regel HearingCoverLetterRule); die Endfassung selbst wird nie angehängt, sondern im Portal abgerufen. |
| Endfassung | Die Ansicht des Briefs und der Nachricht eines ausdrücklich gewählten Empfängers, wie die Aussendung sie erzeugen würde – eine reine Lesung mit OutputStamp, den der Erstversand zurückverlangt (RAL-QM-HP-24 AC-4). Nicht zu verwechseln mit der Endfassung des Verfahrens (RAL-QM-HP-51): den aktiven, nicht ersetzten Abschlussanlagen (Zweck ClosingAttachment), die der Abschluss den Endfassungsempfängern nach Regel 4 über Grants im Portal freigibt. |
| Rückmeldungsübersicht (Abschlussbericht) (RAL-QM-HP-51) | Das interne PDF, das der Abschluss genau einmal je Verfahren erzeugt: Kopf mit Nummer, Titel, beiden Fristen und Erstellungszeit, danach je Beteiligung – auch stille und zurückgezogene – Status und Einträge in Eingangsreihenfolge (Eingangszeit, Art, Verspätung, Text, wirksame Bescheidung). Verfahrensdokument mit Zweck ClosureReport und Herkunft Generated, ohne Grants, nie Pflichtdokument, für keine Institution freigegeben (HearingPortalRules.IsDocumentReleased). Dateiname Rueckmeldungsuebersicht_<Nummer>.pdf, bei belegtem Namen mit deterministischem Suffix _2, _3 … |
| Empfängerstand | Die Adressierungswerte einer Beteiligung (RAL-QM-HP-6). Der operative Stand liegt auf der Beteiligung und bestimmt neue Aussendungen; eine Stammdatenänderung ist nur eine Abweichung, bis der Referent sie übernimmt, den Empfänger wechselt oder die Adresse korrigiert. Der Versandstand ist der auf der Postausgangszeile eingefrorene Stand einer Aussendung und wird nie umgeschrieben. |
| Kontaktmeldung (RAL-QM-HP-41) | Die Meldung einer anderen Kontaktperson durch eine Institution im laufenden Verfahren, je Beteiligung (HearingContactReport, Tabelle RALQMHearingContactReports). Sie ist offen, bis die Institution sie zurückzieht oder der Referent sie übernimmt (in die Stammdaten, als vorhandenen Kontakt oder nur für dieses Verfahren), durch eine andere Person ersetzt oder verwirft; je Beteiligung ist höchstens eine offen. Sie vergibt keinen Zugang und ändert kein Konto. Ein Empfänger „aus Kontaktmeldung, nur dieses Verfahren“ trägt keinen Stammdatenkontakt (ADR-14). |
| Beteiligungsgrund (RAL-QM-HP-5) | Warum eine Institution an einem Verfahren beteiligt ist: Pflichtpartner oder manuell (HearingParticipationReason, Pflichtspalte ParticipationReason auf RALQMHearingParticipants, Werte 10 und 20, die 0 bleibt unbelegt). Entschieden im Moment der Zuordnung aus dem Pflichtpartner-Kennzeichen der Institution, auf jedem Weg – automatische Einbindung, Einzelzuordnung, Gruppenzuordnung, Kopiervorlage, Nachbeteiligung – und danach unveränderlich, auch wenn sich das Kennzeichen ändert (E2). Eine wiederaufgenommene Beteiligung behält ihn. Die Beteiligtenliste zeigt ihn als Text. |
| Sammelzuordnung (RAL-QM-HP-20) | Ein bestätigter Auftrag des Referenten, der eine Unterlage allen im Moment des Speicherns aktiven Beteiligten zuordnet: je Beteiligung ohne aktiven Grant entsteht einer, bestehende bleiben, zurückgezogene werden übersprungen, ein wiederholter Auftrag erzeugt nichts. Die Unterlage merkt sich den Zeitpunkt (GrantedToAllParticipantsAtUtc); danach hinzugefügte Beteiligte erhalten sie nicht automatisch – anders als bei einer Pflichtunterlage –, sondern werden in der Verfahrensakte als nachzupflegen benannt. |
| Pflichtpartner (RAL-QM-HP-10, RAL-QM-HP-5) | Kennzeichen einer Institution, unabhängig von Kreis und Verfahrensart, nur mit aktivem Standardansprechpartner setzbar. Jeder neue Entwurf bindet die gekennzeichneten, aktiven Institutionen selbsttätig ein; ihre Beteiligung trägt den Beteiligungsgrund Pflichtpartner. Das Zurückziehen einer solchen Beteiligung im Entwurf ist das „Ausnehmen“ eines Pflichtpartners – kein eigener Befehl, kein eigenes Recht, aber ein eigener Verlaufseintrag. |
| Abbruch (laufendes Verfahren) (RAL-QM-HP-42) | Beendigung eines Verfahrens in Dispatched oder Adjudication durch die Geschäftsführung mit amtlicher Begründung (Hearing.Abort, Recht RALQM.Hearings.Abort): Endzustand Cancelled, IsCancellationReasonOfficial = true, Widerruf aller laufenden Zugänge, genau eine Abbruchmitteilung je angeschriebener Beteiligung (aktive einschließlich Zugangsentzug, zurückgezogene nur mit früherer Postausgangszeile) mit Begründung ({{Begruendung}}) und tokenfreiem Portallink. Abzugrenzen von der Stornierung vor dem Versand (Cancel, Draft/PendingApproval, ohne Nachricht, Grund intern) und vom Zurückziehen einer Beteiligung. Kein Rücksprung, kein neuer Bearbeitungszeitraum; Archivkennzeichen folgt mit RAL-QM-HP-44. |
| Archivkennzeichen (RAL-QM-HP-44) | Eigenständiges Merkmal Hearing.IsArchived (mit ArchivedAtUtc, ArchivedByUserId) eines beendeten Verfahrens (Completed, Cancelled): entfernt es aus Verfahrensübersicht, Arbeitsvorrat und Export und macht es in der Archivansicht auffindbar; ändert weder Status noch Schreibschutz noch Zugänge. Setzen und Zurückholen (mit Pflichtbegründung, nur im Audit-Log als Zusatzeigenschaft ArchiveRestoreReason) unter dem Recht RALQM.Hearings.Archive (Referent, Geschäftsführung), je ein Verlaufseintrag. Nicht die „Ablage“ (Filing) und nicht die externe Archivreferenz des Abschlusses. |
| Eingangsbestätigung (RAL-QM-HP-35) | Nachricht an die operative Kontaktadresse einer Beteiligung nach jeder im Portal gespeicherten Abgabe oder Ergänzung: Verfahren, Kategorie, Abgabezeit in UTC, Dateinamen mit SHA-256 der übernommenen Bytes und ein tokenfreier Portalverweis – nie der Stellungnahmetext. Parallel erhält der zuständige Referent einen Eingangshinweis mit Prüflink. Beide sind dauerhafte Aufträge mit Wiederholung und Störung; sie belegen die gespeicherte Abgabe, nicht den Postfacheingang. |
| Öffentliche Anzeige (RAL-QM-HP-47) | Kennzeichen Hearing.IsPublished eines freigegebenen oder versendeten Verfahrens, gesetzt und zurückgenommen von Referent oder Geschäftsführung (RALQM.Hearings.Publish). Sichtbar ist ein Verfahren nur, solange Kennzeichen und Status Approved/Dispatched zusammen gelten; Bescheidung, Abschluss oder Abbruch beenden die Anzeige von selbst, die Freigaberücknahme nimmt zusätzlich das Kennzeichen zurück. Gezeigt werden nur Titel, Gütezeichen, Verfahrensart und Frist – anonym auf /anhoerungen/oeffentlich und für die Website über den Bestandsabruf. |
| Öffentliche Kennung (RAL-QM-HP-47) | Hearing.PublicId: beim ersten Kennzeichnen vergebene, danach unveränderliche Kennung, unter der Website und Bestandsabruf ein Verfahren führen – über Rücknahme, erneute Anzeige und Entfernung hinweg. Weder Aktenzeichen noch Verfahrens-Id. |
| Bestandsabruf (RAL-QM-HP-47) | Der authentisierte JSON-Abruf GET /api/gz/hearings/public eines zugelassenen Keycloak-Integrationsclients: ohne Cursor der vollständige sichtbare Bestand, mit changedSinceUtc die seitdem geänderten sichtbaren Verfahren und die Entfernungen (nur Kennung und Zeitpunkt). Abgleich je Kennung nach Änderungszeitpunkt. |
| Zugang entzogen (RAL-QM-HP-5) | Zustand einer aktiven Beteiligung in einem laufenden Verfahren (Dispatched, Adjudication): Der Referent hat den Portalzugang der Institution zu diesem einen Verfahren entzogen (HearingParticipant.AccessRevokedAtUtc). Die Institution bleibt beteiligt – Status, Empfänger, Unterlagenzuordnungen, Fristen und die feste Kontobindung bleiben –, aber kein Konto der Institution erreicht das Verfahren im Portal, und solange der Zustand besteht, gehen keine fristgesteuerten Nachrichten an sie und lässt sich auch von Hand keine Einladung ausstellen oder erneuern. Ohne Begründung, ohne Nachricht an die Institution, mit Verlaufseintrag; „Zugang wieder freigeben“ hebt ihn ohne neue Einladung auf. Nach Abschluss oder Abbruch bleibt er bestehen und ist nicht mehr änderbar. Kein Zurückziehen (das nimmt die Institution aus dem Verfahren) und keine Kontosperre. |
| Verfahrensart | Die Art des Anhörungsverfahrens — ausgeliefert werden neues Gütezeichen, Revision, Anerkennungsverfahren, Erweiterung und Satzungsänderung. Pflichtangabe je Verfahren (ProcedureTypeId). Die einzige Werteliste, die zusätzlich Daten trägt: je Ausprägung optional drei Standardfristen (erste und zweite Rückmeldefrist, Abschlusserinnerung), entweder vollständig hinterlegt oder gar nicht, die neue Verfahren als überschreibbare Vorbelegung übernehmen. Eine spätere Änderung der Standardfristen wirkt nur auf danach angelegte Verfahren. Nach Verfahrensart lassen sich die Verfahrenslisten seit dem Umbau nicht mehr serverseitig sortieren (siehe ADR-07). |
| Vier-Augen-Freigabe | Fachregel: Einreichung und Freigabe einer Anhörung müssen von unterschiedlichen Personen (Akteurstrennung) erfolgen; die geprüfte Zusammensetzung wird über eine Kompositionsprüfsumme gesperrt. |
| Werteliste (Value List) | Eine über die Oberfläche gepflegte Katalogtabelle mit den zulässigen Ausprägungen eines Feldes. Es gibt vier: Kennzeichnungsart, Verfahrensart, Land und Funktion eines Ansprechpartners. Jede Ausprägung trägt eine unveränderliche Guid-Kennung (das Einzige, was andere Module speichern), einen stabilen technischen Code, Anzeigenamen je Kultur (NameDe Pflicht, NameEn optional, Rückfall auf Deutsch), ein Aktivkennzeichen und eine Sortierung. Ausprägungen werden nie gelöscht, nur deaktiviert: An bestehenden Datensätzen bleiben sie sichtbar, für neue werden sie nicht mehr angeboten. Änderungen wirken ohne Neustart, weil die Listen nicht zwischengespeichert werden. Gepflegt wird unter /administration/wertelisten, ausschließlich durch RALQMAdministrator. Eigener Feature-Slice ValueLists mit den Tabellen RALQMMarkTypes, RALQMProcedureTypes, RALQMCountries und RALQMContactFunctions; siehe Bausteinsicht §5.2.4 und ADR-07. |
| Abschlussvariante (US-33) | Je Verfahren gewählt: zweistufig durchläuft Bescheidung als eigenen Status vor dem Abschluss; einstufig versendet Bescheidung und Endfassung in einem Vorgang und überspringt den Adjudication-Status. Siehe Einführung und Ziele. |
| Bescheidung (Adjudication) | Prozessphase nach den Rückmeldungen: Endfassungen werden in einem begrenzten, additiven Fenster zusammengestellt und individualisiert an aktive Teilnehmer versendet; das Fenster schließt mit dem ersten Bescheidungsversand. Entfällt als eigener Status bei einstufiger Abschlussvariante (siehe Abschlussvariante). |
| Stellungnahme (Response) | Die fachliche Rückmeldung eines Teilnehmers im Portal über sein Benutzerkonto (übergangsweise noch Gastportal), ggf. mit Anhängen; kann innerhalb der Frist mit dem zuletzt gelesenen Concurrency-Stand geändert werden. |
| Verfahrensverlauf (RAL-QM-HP-7) | Die append-only Zeitleiste eines Verfahrens (RALQMHearingHistoryEntries): je verfahrensrelevantem Ereignis genau ein Eintrag mit Ereignisart aus dem geschlossenen Katalog HearingHistoryEventType, Zeitpunkt aus IClock, Aktor (interne Person, Teilnehmer, gebundenes Konto) und betroffenem Kindobjekt. Der Urheber wird beim Lesen aufgelöst: die Person namentlich, „System“ für die zeitgesteuerte Verarbeitung (Erinnerung, Fristablauf), bei institutionsbezogenen Ereignissen die Institution mit Namen. Einträge sind unveränderlich — der Persistenzpfad weist Update und Delete ab (HistoryEntryImmutable). Die Zeitleiste ist nach Ereignisart, Institution und Zeitraum einschränkbar und bei abgeschlossenen und abgebrochenen Verfahren unverändert einsehbar. |
| Datenänderung (RAL-QM-HP-7) | Ein Eintrag der Zeitleiste, der ein protokollpflichtiges Feld des Verfahrens mit altem und neuem Wert nennt (Titel, Beschreibung, Kennzeichnungsart, Verfahrensart, antragstellende Stelle, Fristen, Abschlussvariante, Zuständiger, Archivreferenz, Abschlussnotiz, Begründung). Quelle ist die ABP Entity History des Verfahrens (RALQMHearingsEntityHistory), nicht die Verlaufstabelle (die PII-frei bleibt); Kennungen werden zu Namen aufgelöst. Gehört der Feld-Diff zum Ereignis derselben Operation (z. B. Titel zu „Titel geändert“), hängt er an diesem Eintrag, sonst steht er als eigener Eintrag „Datenänderung“. Institutionen, Vorlagen und Fristvorgaben führen ihren Feld-Diff in der Entity History des Audit-Protokolls. |
| Verwendungszweck (RAL-QM-HP-21) | Der Verfahrensschritt, dem eine Verfahrensunterlage dient — genau einer je Unterlage: Anhörungsunterlage (erstes Anschreiben; nur im Entwurf anhäng-, änder- und entfernbar, ab der Einreichung zur Freigabe eingefroren, nach Rückzug oder Ablehnung wieder frei), Bescheidungsanlage (Bescheidungsschritt bis zum Bescheidversand) und Abschlussanlage (ab dem Anhörungsversand bis zum Abschluss). Feld Purpose des HearingDocument (HearingDocumentPurpose), entscheidet das Fenster für Anhängen, Anzeigeangaben, Zweckwechsel, Zuordnung und Entfernen (Hearing.IsDocumentWindowOpen) und die Bereitstellung im Portal je Schritt (HearingPortalRules.IsDocumentReleased). Hat das frühere Kennzeichen „Bescheidungs-Endfassung“ (IsAdjudicationFinal) aufgenommen; die Dokumentrolle (Anschreiben, Gegenstand, Nachweis, Anlage) bleibt die Art der Unterlage. |
| Herkunft (RAL-QM-HP-21) | Woher eine Verfahrensunterlage stammt — Feld Origin des HearingDocument mit vier persistierten Werten (HearingDocumentOrigin): Upload (Arbeitsplatz-Upload), Generated (erzeugtes Schreiben), Submitted (eingereichte Anlage) und Archive, im Deutschen „Ablage“. Erzeugte Schreiben und eingereichte Anlagen sind nie entfernbar. Der Wert Archive entstand mit RAL-QM-HP-21 zusammen mit den drei anderen, blieb dort aber ohne Erzeuger; seinen ersten und bis heute einzigen Erzeuger hat er mit der Übernahme aus RAL-QM-HP-16 bekommen. Identifier und Anzeigetext sind also nicht dasselbe: Archive ist der Code, „Ablage“ der deutsche Text. |
| Gestört (RAL-QM-HP-21) | Kennzeichen einer Verfahrensunterlage in der Dateiübersicht, deren Inhalt der Dokumentenspeicher nicht mehr beschreibt (kein Descriptor zur DocumentId). Serverseitig je Liste über den berechtigungsfreien Port IDocumentContentPort.DescribeManyAsync ermittelt. |
| Ablage (RAL-QM-HP-19) | Der verfahrensunabhängige Dateibereich des Produkts: Ordner und Dateien, die keinem Verfahren gehören. Gegliedert in Ablagebereiche, Ordner bis 16 Ebenen tief, Namen bis 200 Zeichen, dahinter der zweistufige Papierkorb. Eigener Feature-Slice Filing mit RALQMFilingAreas, RALQMFilingEntries, RALQMFilingHistory und RALQMFilingHearingUsages; Dateimetadaten und Inhalte bleiben bei ABP File Management hinter dem neutralen IDocumentFilingPort — Filing speichert Bereichseigentum, Elementzuordnung, Papierkorbzustand und Fachhistorie. Bedient unter /filing; nutzbar nur durch aktive interne Konten mit genau einer Produktrolle Referent oder Administrator. Institutionskonten haben keine Ablage. Siehe Bausteinsicht §5.2.5. |
| Ablagebereich (RAL-QM-HP-19) | Die Wurzel einer Ablage (FilingAreaKind): der gemeinsame Bereich, den alle berechtigten internen Konten zusammen nutzen, und je Konto ein persönlicher Bereich. Ein fremder persönlicher Bereich bleibt bei jeder Operation verborgen — auch für Administratoren und auch im Verwendungsnachweis. Jeder Bereich trägt eine Revision, die als Sperre jeder Mutation zuerst geschrieben wird. Der persönliche Bereich eines deaktivierten internen Kontos wird unter /administration/ablage-uebertragen von einem aktuellen Produktadministrator an einen aktiven Referenten übertragen; die Übertragung konsumiert nur Konten- und Bereichsprojektionen und vermittelt keinen Inhaltszugriff. |
| Papierkorb (Ablage) (RAL-QM-HP-19) | Der zweistufige Löschweg der Ablage (FilingEntryState). „Entfernen“ setzt den Unterbaum auf Trashed und erhält die Bytes; das ausdrücklich bestätigte „Endgültig entfernen“ reserviert zuerst alle Datei-Descriptoren und persistiert Purging, danach entfernt ein ABP Background Worker nach erneuter Rechte- und Eigentumsprüfung die Inhalte und schreibt Purged fest. Aktive CAF-Freigaben und Verfahrensreferenzen auf denselben Descriptor blockieren den Auftrag (PurgeProtected); eine Übernahme blockiert ihn nicht, weil das Verfahren eine eigene Fassung besitzt. Die Ansicht /filing/trash führt Ablage- und Verfahrenszeilen zusammen — entfernte Verfahrensdateien liefert der Hearings-Port zu, ihre Wiederherstellung und ihr Löschauftrag bleiben bei Hearings. Das Leeren des Papierkorbs und eine automatische Aufbewahrungsfrist sind eigene Stories (RAL-QM-HP-64, RAL-QM-HP-65). |
| Übernahme (Ablagedatei ins Verfahren) (RAL-QM-HP-16) | Das Einbringen einer aktiven Ablagedatei in ein Verfahren als eigenständige Verfahrensfassung: eigene DocumentId, eigener Descriptor, eigene Bytes, Herkunft Archive und der Übernahmezeitpunkt als Anlagezeitpunkt dieser Fassung. Es bleibt kein Verweis auf das Ablageoriginal: Umbenennen, Verschieben, Ersetzen, Papierkorb und endgültiges Entfernen der Quelle lassen Inhalt, Anzeigename und Berechtigungen der Verfahrensfassung unverändert. Zulässig nur aus dem gemeinsamen oder dem eigenen persönlichen Ablagebereich, nur für Dateien (nie Ordner) und nur bei offenem Fenster des gewählten Verwendungszwecks; ein abgeschlossenes (Completed) oder abgebrochenes (Cancelled) Verfahren nimmt nichts mehr auf. Ein Aufruf je Datei mit eigener Operation-ID — eine fachlich abgewiesene Datei stoppt die übrigen nicht. Bedienung über „Aus der Ablage übernehmen“ im Reiter „Dokumente“ der Verfahrensakte; Ablauf in Laufzeitsicht §6.6. Nicht zu verwechseln mit der Gegenrichtung aus RAL-QM-HP-19, der „Kopie in Ablage wiederherstellen“ einer zurückgezogenen Verfahrensunterlage. |
| Verwendungsnachweis (RAL-QM-HP-16) | Die Auskunft, in welche Verfahren eine Ablagedatei übernommen wurde: je Übernahme das Verfahren mit Referenznummer, Bezeichnung, Status, Übernahmezeitpunkt, dem abgeleiteten Merkmal archiviert (Completed oder Cancelled) und der Angabe, ob die Verfahrensfassung dort noch vorhanden ist. Persistiert als Aggregat FilingHearingUsage (RALQMFilingHearingUsages) mit Quell-Element, gelesener Quellfassung, Verfahren, Verfahrensdokument, Zeitpunkt, Actor und Operation-ID; Zeilen werden nie gelöscht, der Nachweis bleibt deshalb auch nach endgültigem Entfernen der Quellbytes auflösbar. Er lässt Verfahren ohne Leserecht des Aufrufers und Elemente fremder persönlicher Bereiche weg, statt zu scheitern, und zeigt für eine Datei ohne Übernahme einen erläuternden Hinweis statt einer leeren Liste. Er ist zugleich die Datenquelle des Warnhinweises vor dem Entfernen und dem endgültigen Entfernen — ein Hinweis, keine Sperre. |
| Überfällig (RAL-QM-HP-2, RAL-QM-HP-1) | Kennzeichen eines Verfahrens in der Verfahrensübersicht und Ordnungsmerkmal des Arbeitsvorrats: versandt, die maßgebliche Rückmeldefrist (zweite, sonst erste) ist nach der Kalendertagsregel des Antwortfensters abgelaufen (der Fristtag selbst zählt noch nicht), und mindestens ein aktiver Teilnehmer hat noch nicht geantwortet. Eine abgelaufene Frist allein ist nicht „überfällig“ — sind alle Stellungnahmen da oder läuft schon die Bescheidung, gibt es nichts mehr zu erwarten. Die maßgebliche Regel steht an einer Stelle (HearingOverdueRule im Hearings-Contract) und wird serverseitig ins Listen-DTO geschrieben (IsOverdue); Liste, CSV-Export und Oberfläche leiten es nie selbst ab. Seit RAL-QM-HP-1 gibt es sie in einer zweiten Fassung als Datenbankabfrage (HearingOverdueQuery in der Hearings-Runtime), weil der Arbeitsvorrat des Referenten seine überfälligen Verfahren nach vorn stellt und erst danach blättert, was eine Entscheidung je geladener Zeile nicht kann; ausgewählt wird nach ihr nicht mehr, der Referent sieht nur eigene Verfahren. HearingWorkQueueSqlServerTests hält beide Fassungen auf echtem SQL Server zusammen, auch an der Tagesgrenze. Nicht zu verwechseln mit der Ampel des Dashboards, die am Zeitstempel der Frist schaltet. |
| Arbeitsvorrat (RAL-QM-HP-1) | Die persönliche Aufstellung offener Aufgaben auf der Startseite. Für den Referenten genau seine laufenden Verfahren — laufend heißt hier weder abgeschlossen noch storniert (SPEC-RAL-QM-HP-1 E8), enger als der Sichtbereich „Laufende“ der Verfahrensübersicht unten, der stornierte Verfahren bis zur Archivierung zeigt; überfällige eigene sind gekennzeichnet und stehen vorn (E9, E10). Für die Geschäftsführung genau die zur Freigabe eingereichten Verfahren, eigene Einreichungen eingeschlossen. Fremde und nicht zugewiesene Verfahren erscheinen in keinem Arbeitsvorrat des Referenten. |
| Sichtbereich (Verfahrensliste) (RAL-QM-HP-2) | Welche Verfahren eine Listenabfrage überhaupt betrachtet (HearingListScope): Laufende (Standard der Verfahrensübersicht: alles außer abgeschlossen; abgebrochene bleiben sichtbar, bis ein Archiv-Zustand aus RAL-QM-HP-44 sie ausblendet), Alle (Kopiervorlagen beim Anlegen, Eintrag „Alle Status“ im Statusfilter) und Abgeschlossene (das Archiv: abgeschlossen oder abgebrochen). Ein explizit gewählter Status hat Vorrang vor dem Sichtbereich — so holt „Abgeschlossen“ im Statusfilter die ausgeblendeten Verfahren ohne zweites Bedienelement zurück. |
| Institutionskonto | Das Zugangs-Modell für externe Teilnehmer: RAL legt je Institution dedizierte Benutzerkonten an — mehrere pro Institution, je Kontakt eines (Keycloak-Konto, über den stabilen sub gebunden); keine Selbstregistrierung, Entzug wirkt sofort und ohne Rückfallweg. Einstieg ist eine Seite mit zwei Routen: /portal/zugang-uebernehmen („Zugang übernehmen“) und /portal/teilnahme-beanspruchen („Teilnahme beanspruchen“, die derzeit einzige in der Anwendung verlinkte); jedes Konto sieht nur die eigene Institution und die eigenen Teilnahmen (US-22 ff.). |
| Kontogebundene Teilnahme | Die konkrete Bindung einer Verfahrens-Einladung an ein Benutzerkonto des Institutionskontos (sub-korreliert); technische Grundlage des Portalzugangs. |
| Gastzugang (stillgelegt) | Ehemaliger anonymer Einladungszugang. Seit RAL-QM-HP-31 ohne Zugriffsrecht; historische Daten bleiben erhalten, alte Einstiege führen neutral zum Login. |
Technische Begriffe
| Begriff | Definition |
|---|---|
| RALQM | Verbindlicher Präfix für alle anwendungsspezifisch persistierten Identifikatoren der HearingPortal-Anwendung: Tabellen (RALQMHearings, RALQMInstitutions, …), Error-Code-Namespace (RALQM.<Feature>:), Permission-Gruppe RALQM und Rollen RALQMAdministrator/RALQMCaseOfficer/RALQMManagement. Technische, lowercase Slugs (z. B. ral-qualitymarks) bleiben davon unabhängig. Siehe Randbedingungen. |
| CAF | Präfix der wiederverwendbaren, anwendungsneutralen Framework-Bausteine (CAF.Modules.Authentication, CAF.Modules.Documents[.Contracts], CAF.Modules.UI.Blazor). Kein CAF.*-Projekt darf ein HearingPortal.*-Projekt oder GZ-Fachwissen referenzieren. |
| No-Layer (app-nolayers) | Architekturstil dieses Monorepos: Domain, Application und Persistence bleiben logische Schichten, werden aber pro Modul in einer kompakten Runtime-Assembly gebündelt statt in sieben ABP-Standardprojekten. Eine weitere Assembly (z. B. eigenes .Blazor-Projekt) entsteht erst bei echtem Bedarf (unabhängige Paketierung, austauschbarer Provider, gemessene Build-Isolation). Siehe Bausteinsicht. |
| ABP (ABP Framework) | Das zugrunde liegende .NET-Applikationsframework (Module, Application Services, dynamische Proxies für Authorization/Unit-of-Work/Audit/Validation, Identity, Permission-, Setting-, Audit-, Text-Template- und File-Management-Module). Der Host lädt ABP-Module als Composition Root; Fachcode nutzt vorhandene ABP-Bordmittel, bevor neue Infrastruktur entsteht. |
| Cohesion | Die verbindliche Syncfusion-basierte UI-Komponentenbibliothek für alle eigenen CAF-/GZ-Fachseiten (aus dem GitLab-Gruppen-Feed, zentrale Floating-Version 3.*-*). MudBlazor/Syncfusion/Blazorise dürfen von Fachcode nicht direkt gerendert werden; ausgenommen sind allein die MVC-Razor-Pages unter /Account/**. Registrierung, Lizenzprüfung und Assets liegen in CAF.Modules.UI.Blazor. |
| Feature-Slice | Die Standardform eines Fachmoduls: ein schmales .Contracts-Projekt (DTOs, AppService-Interfaces, IDs, Permissions, Localization) plus eine Runtime (Domain, Application, EF Core) und optional eine .Blazor-Razor-Class-Library für Feature-Seiten. Vertikal nach Capability geschnitten (Authorization, Institutions, Hearings), nicht horizontal nach technischer Schicht. |
| Modulgrenze | Die durch Architekturtests erzwungene Compile-Time-Grenze zwischen Modulen: Consumer verwenden nur Contracts, nie eine fremde Runtime, Entity, Tabelle oder Repository; CAF.Modules.* → HearingPortal.* und Cross-Module-EF-Navigation/-Foreign-Keys sind verboten. Über Modulgrenzen werden ausschließlich IDs referenziert. Siehe Bausteinsicht, Querschnittliche Konzepte. |
| VERTRAG.md | Die verbindliche, deutschsprachige Vertragsdatei je CAF.Modules-Baustein (Wurzelverzeichnis des Projekts, z. B. modules/Authentication/src/VERTRAG.md). Benennt zugesicherte öffentliche Fläche, ausdrückliche Nicht-Zusicherungen, Versionierungsregel und Feed-Voraussetzungen. Ein Quelltext-Vertrag, kein Paket-Readme: die Bausteine sind bewusst nicht packbar. FrameworkPackagingTests verlangt Existenz, nicht-leeren Inhalt und beide Pflichtabschnitte. Jede Änderung an der zugesicherten Fläche aktualisiert VERTRAG.md im selben Änderungssatz. |
| Seed | Der initiale/aktualisierende Datenbestand, der beim Migrations-/Startvorgang eingespielt wird (z. B. Rollen-Grants nach neuen Feature-Permissions). Läuft über HearingPortalDbMigrationService im Host; erfordert nach Rechteänderungen einen erneuten Seed-Lauf, aber keine Schemamigration. |
| Data-preserving Migration | Eine EF-Core-Migration, die Strukturänderungen (z. B. Umbenennung von Tabellen/Spalten beim RALQM-Rename) ohne Datenverlust umsetzt, typischerweise über RenameTable/RenameColumn statt Drop/Create. Historische Migrationen behalten dabei ihre alten Identifiers; nur neue Migrationen verwenden die aktuelle Namenskonvention. Pflichtnachweis: realer Round-Trip auf leerer SQL-Server-Datenbank plus has-pending-model-changes grün. |
| Aggregate | Ein fachliches Objekt, das seine Invarianten selbst über benannte Operationen (z. B. Submit, Approve, Cancel) schützt, keine öffentlichen Setter auf invarianten-relevanten Properties besitzt und optimistische Concurrency trägt. Beispiel: die Anhörung mit Teilnehmern, Dokumenten und Freigaben. |
| Application Service | Der Einstiegspunkt eines Anwendungsfalls: prüft Permission und Objektzugriff, lädt das Aggregate, ruft eine benannte Domänenoperation auf und persistiert innerhalb der ABP Unit of Work. Wird nicht sealed, damit ABP die nötige dynamische Proxy-Interception anwenden kann. |
| Contracts | Das schmale, öffentliche Projekt eines Moduls: DTOs, AppService-Interfaces, stabile IDs, Permission-Definitionen und DE/EN-Localization. Enthält keine EF-Typen, Entities, Repositories oder Implementierungen. |
| Host (Composition Root) | Das einzige startbare Projekt (HearingPortal/Host), das Module lädt, Middleware/Routing verkabelt, den gemeinsamen HearingPortalDbContext besitzt und Migrationen erzeugt/ausführt. Enthält bewusst keine neue Fachlogik oder Fachentities. |
| Interactive Server | Der von der Blazor-Web-App gewählte Render-Modus (kein WebAssembly-Client). Feature-Komponenten bleiben render-mode-neutral und setzen kein @rendermode; der Host entscheidet zentral. |
| BrowserGate | Der separate, exklusive End-to-End-Nachweis über einen echten Browser (Login, Hauptprozesse, Permission-Denial, Assets, Responsive-Verhalten, axe/WCAG). Läuft als Konsolenprogramm ohne Test-SDK, ist Teil der Solution, aber nicht Teil des normalen dotnet test-Laufs. |
| Quality Gate | Zentraler Selektor tools/scripts/Invoke-QualityGate.ps1: bestimmt aus vollständigen Ref-Diffs und dem alten/neuen Projektgraphen betroffene Apps. Jede ausgewählte ausführbare App durchläuft ihre Pflichtschritte; Browserstrecke, axe, Tastatur/Fokus und Browser-Berechtigungsprüfungen sind optional und standardmäßig aus. Reine Doku prüft Links und Reporting; -All wählt CAF und alle Apps ohne optionale Gruppen einzuschalten. Fehlende/übersprungene Pflichtschritte und Nachweise für einen anderen Tipp blockieren den Push. Details im Entwicklungsleitfaden. |