Ausgangslage
Umgesetzt ist nur die Definition der Vertikale ConMeet.Core/Features/ConMeetInstances/: vertical.json,
die drei Entitäten ohne Mapping und die Exceptions. Der Aufwand liegt in zwei Querschnitts-Vorleistungen,
die es noch nicht gibt (Berechtigungen aus Produktrollen, Erweiterungspunkt der Replik), in der
Verschlüsselung und in der Vertikale selbst samt Oberfläche. Die Vertikale wird mit validdata-vertical-generator
in dessen Stufen gebaut (S4, S6–S9); Querschnitt nach validdata-backend-patterns.
Grundlage ist der Arbeitsstand vom 2026-10-29 mit dem uncommitteten Umzug nach Crosscutting/. R90–R100
(Prüfkonto) sind nach der letzten Prüfung entstanden und nicht erneut geprüft.
Pfadkürzel: srv/ = source/conmeet-server/, web/ = source/conmeet-webapp/,
CI/ = srv/ConMeet.Core/Features/ConMeetInstances/.
Bestand je Anforderung
| Anforderung | Stand | Fundstelle | Schritt |
|---|---|---|---|
| R1 | fehlt | — | S4, S6 |
| R2 | fehlt | — | S4, S6 |
| R3 | fehlt | — | S6 |
| R4 | fehlt | — | S4 |
| R5 | teilweise | srv/ConMeet.Core/Crosscutting/Persistence/Interceptors/PersistenceInterceptors.cs:62 — Stempel des Mandanten; Benutzerprüfung fehlt |
S7, S8 |
| R7 | fehlt | srv/ConMeet.Core/Crosscutting/Licensing/ProductRoles.cs:7 — Katalog leer |
S1 |
| R8 | fehlt | srv/ConMeet.Service/Features/AuthenticationFeature.cs:105 — nur Standard-Policy |
S1, S9 |
| R9 | fehlt | srv/ConMeet.Core/Crosscutting/Users/Api/UserQueries.cs:23 — Me ohne permissions |
S1, S10 |
| R11 | fehlt | — | S6 |
| R13 | fehlt | — | S6 |
| R14 | fehlt | — | S6, S10 |
| R15 | fehlt | — | S6 |
| R18 | fehlt | — | S10 |
| R19 | fehlt | — | S10 |
| R20 | erfüllt (Regel) | AGENTS.md (Persistenz, Ausnahme für lesende Aufrufe) |
S5 |
| R22 | fehlt | — | S7 |
| R23 | fehlt | — | S7 |
| R24 | fehlt | — | S7, S10 |
| R25 | fehlt | — | S7, S10 |
| R26 | fehlt | — | S7 |
| R27 | fehlt | — | S7 |
| R29 | fehlt | — | S8, S11 |
| R30 | fehlt | — | S8 |
| R37 | fehlt | — | S8, S11 |
| R38 | fehlt | — | S8, S9 |
| R39 | fehlt | — | S8 |
| R40 | fehlt | keine AES-GCM-Hilfe im Backend; nur web/src/lib/server/auth.ts:39 |
S2, S8 |
| R41 | fehlt | — | S9 |
| R42 | fehlt | srv/ConMeet.Service/Features/PersistenceFeature.cs:21 — Blacklist kennt nur OutboxMessage |
S4, S5 |
| R43 | fehlt | — | S10, S11 |
| R44 | fehlt | CI/Exceptions/ConMeetUserAlreadyLinkedException.cs |
S8 |
| R46 | teilweise | srv/ConMeet.Core/Crosscutting/Persistence/TenantDbContext.cs:36 — Mandantenfilter |
S9 |
| R47 | fehlt | web/src/lib/components/ui/sheet/ vorhanden, Bestätigungsdialog fehlt |
S10, S11 |
| R48 | fehlt | — | S10 |
| R49 | fehlt | — | S8, S9 |
| R50 | fehlt | — | S8 |
| R51 | fehlt | — | S7, S10 |
| R52 | fehlt | — | S5 |
| R53 | fehlt | — | S6 |
| R54 | fehlt | — | S8 |
| R57 | fehlt | — | S8 |
| R60 | fehlt | — | S11 |
| R61 | fehlt | — | S8, S11 |
| R62 | fehlt | — | S11 |
| R63 | fehlt | — | S5 |
| R64 | fehlt | — | S5, S10, S11 |
| R65 | fehlt | — | S8 |
| R66 | fehlt | Codes nur in den Doc-Kommentaren von CI/Exceptions/ |
S9 |
| R67 | fehlt | — | S6, S9 |
| R68 | fehlt | — | S4, S8 |
| R69 | fehlt | srv/ConMeet.Core/Crosscutting/Suite/Replication/SuiteReplica.cs:93 — Umzug läuft über RemoveUserAsync |
S3, S7 |
| R70 | fehlt | — | S7 |
| R71 | fehlt | — | S11 |
| R72 | fehlt | — | S2 |
| R73 | fehlt | srv/ConMeet.Core/Crosscutting/Persistence/EntityModelConfiguration.cs:14 — Zeilenversion xmin vorhanden |
S6, S9 |
| R74 | teilweise | CI/Entity/ConMeetInstance.cs, CI/Entity/AccountLink.cs — Konstanten ohne Mapping und Prüfung |
S4, S6 |
| R75 | fehlt | — | S6 |
| R76 | fehlt | — | S10, S11 |
| R77 | fehlt | — | S10 |
| R78 | fehlt | web/src/lib/components/layout/app-sidebar.svelte:39 — nur „Übersicht“ |
S10, S11 |
| R79 | fehlt | — | S8 |
| R80 | fehlt | — | S8 |
| R81 | teilweise | CI/Entity/AccountLink.cs — Konstante ohne Prüfung |
S4, S8 |
| R82 | fehlt | CI/Exceptions/InvalidInputException.cs |
S6, S8, S9 |
| R83 | fehlt | — | S9, S10, S11 |
| R86 | fehlt | SuiteReplica.cs:138 — RemoveUserAsync löscht nur Lizenzen und Benutzer |
S3, S7 |
| R87 | fehlt | kein Erweiterungspunkt in srv/ConMeet.Core/Crosscutting/Suite/ |
S3, S7 |
| R88 | fehlt | — | S2 |
| R89 | fehlt | — | S8, S9 |
| R90 | fehlt | CI/Entity/AccountLink.cs — IsAdmin ohne Index |
S4, S6 |
| R91 | fehlt | — | S6 |
| R92 | fehlt | — | S6 |
| R93 | fehlt | — | S6 |
| R94 | fehlt | — | S6 |
| R95 | fehlt | — | S5, S6, S8 |
| R96 | fehlt | — | S8 |
| R97 | fehlt | CI/Exceptions/AdminLinkRequiredException.cs |
S8 |
| R98 | fehlt | — | S6 |
| R99 | fehlt | — | S6 |
| R100 | fehlt | — | S9, S10 |
Schritte
S1 — Berechtigungen aus Produktrollen
Erfüllt: R7, R8 (Policy), R9 (Backend)
Abhängig von: — · parallel zu S2, S3, S4
Dateien: srv/ConMeet.Core/Crosscutting/Licensing/ProductRoles.cs, srv/ConMeet.Core/Crosscutting/Users/CurrentAccess.cs,
srv/ConMeet.Core/Crosscutting/Users/Api/UserQueries.cs, srv/ConMeet.Service/Features/AuthenticationFeature.cs,
srv/ConMeet.CoreSimulator/core-simulator.seed.json, web/src/lib/features/users/me.graphql, Tests unter
srv/ConMeet.Core.Tests/Crosscutting/Suite/AuthorizationPolicyTests.cs und .../Users/MeQueryTests.cs
Zu tun:
- Katalog um
conmeet-admin→ManageInstancesergänzen; Berechtigungsnamen als Konstanten neben dem Katalog. CurrentAccessleitet die Berechtigungen ausUser.Rolesüber den Katalog ab.- Je Berechtigung eine Policy in
ConfigureAuthorizationOptions(AuthenticationFeature.cs:89), dieREADYund die Berechtigung verlangt; kein Schema in der Policy (docs/backend-development.md). Meumpermissionserweitern;me.graphqlund generierten Code im BFF nachziehen.- Seed: Rolle
conmeet-adminim Produktconmeet-suiteanlegen und Anna zuweisen (core-simulator.seed.json:16,:70). - Integrationsplan: Prüfzeile „Zugriff: Rollenkatalog“ und Hinweis zu WP5 auf den neuen Stand bringen.
Fertig, wenn: Tests zeigen: mit Rolle
permissions = [ManageInstances]und Policy erfüllt; ohne Rolle leer und Policy verweigert; fremde Rolle gewährt nichts. Anna sieht lokalManageInstancesinme.
S2 — Verschlüsselung des persönlichen Schlüssels in der Vertikale
Erfüllt: R40 (Mechanismus), R72, R88
Abhängig von: — · parallel zu S1, S3, S4; registriert wird sie in S6
Dateien: CI/ (eine Klasse zum Ver- und Entschlüsseln, ohne eigene Abstraktion), srv/ConMeet.AppHost/AppHost.cs,
docs/vds-suite/deployment-handover.md, Tests unter srv/ConMeet.Core.Tests/Features/ConMeetInstances/
Zu tun:
- Verschlüsseln und Entschlüsseln direkt in der Vertikale mit AES-256-GCM, Associated Data aus Mandant, Zweck
conmeet-personal-keyund Zeilen-ID; Aufbau Nonce | Tag | Daten wieweb/src/lib/server/auth.ts:47. Kein eigener Querschnitt, kein Interface. - Schlüssel aus
Secrets:EncryptionKeymit Prüfung beim Start (64 Hex-Zeichen), MusterSuiteRegistry.cs:35undSuiteOptions.cs:49. - AppHost setzt lokal einen Schlüssel aus einem Parameter (User Secrets), nichts eingecheckt.
- Übergabe: Pflichtwert
Secrets:EncryptionKeymit Format eintragen. Fertig, wenn: Tests: Rundlauf gelingt; anderer Mandant, Zweck oder Zeilen-ID lässt das Entschlüsseln scheitern; fehlender oder falsch formatierter Schlüssel verhindert den Start.
S3 — Erweiterungspunkt der Replik für Benutzerdaten
Erfüllt: R86, R69, R87 (Querschnitt)
Abhängig von: — · parallel zu S1, S2, S4
Dateien: srv/ConMeet.Core/Crosscutting/Suite/Replication/SuiteReplica.cs, Registrierung in
srv/ConMeet.Core/Crosscutting/Suite/SuiteRegistry.cs, Tests in srv/ConMeet.Core.Tests/Crosscutting/Suite/SuiteReplicationTests.cs
Zu tun:
- Erweiterungspunkt in
Crosscutting/Suite/anlegen, den Vertikalen registrieren; Aufruf inRemoveUserAsync(SuiteReplica.cs:138) vor dem Löschen des Benutzers, im selben Kontext und derselben Transaktion. RemoveUserAsyncdeckt Entfernen (SuiteMessageHandlers.cs:104), Ersetzen/Umzug (SuiteReplica.cs:93,:95) und Backfill (SuiteBackfill.cs:66,:110) ab; keinen zweiten Aufrufpfad anlegen.backend-development.md, Abschnitt Replik, um den Erweiterungspunkt ergänzen. Fertig, wenn: Ein im Test registrierter Teilnehmer wird beiUserDeleted, Backfill-Entfernung und Umzug je einmal aufgerufen; scheitert er, wird die Nachricht wiederholt und nichts ist gelöscht.LayerDirectionTestsgrün.
S4 — Persistenz der Vertikale (Generator-Stufe 2)
Erfüllt: R1, R2, R4, R68, R74, R81, R90 (Datenbank), R42 (Audit)
Abhängig von: — · parallel zu S1–S3
Dateien: CI/Entity/*ModelConfiguration.cs (neu), srv/ConMeet.Core/Crosscutting/Persistence/ConMeetContext.cs:20,
srv/ConMeet.Service/Features/PersistenceFeature.cs:21, neue Migration in srv/ConMeet.Service/Persistence/Migrations/,
srv/ConMeet.Core.Tests/Crosscutting/Persistence/EntityModelTests.cs:21, Persistenztests unter srv/ConMeet.Core.Tests/Features/ConMeetInstances/
Zu tun:
- Je Entität
EntityModelConfiguration<T>mitIsTenantOwned(); Längen aus denConstraints. - Eindeutige Indizes, jeweils mit
TenantIdvorn: Name ohne Groß-/Kleinschreibung (R1), normalisierteBaseUrl(R2, gespeichert in normalisierter Form),(ConMeetInstanceId, UserId)für Grant und Link (R4),(ConMeetInstanceId, lower(ConMeetUserName))(R68), partiell(ConMeetInstanceId) WHERE is_admin(R90). - Fremdschlüssel der Kinder auf
ConMeetInstance; Löschen erfolgt ausdrücklich (R15), nicht über Kaskade. DbSet-Zeilen, MigrationConMeetInstances(Entwickler vorher informieren), Audit-Blacklist fürAccountLink.PersonalKey.- Neue Entitäten in
EntityModelTestsklassifizieren. Fertig, wenn: Persistenztests gegen PostgreSQL: jeder Index weist das Doppel ab (auchLive/live,https://X/gegenhttps://x), zweite admin-Verknüpfung scheitert, fremder Mandant sieht keine Zeile;EntityModelTestsgrün; die Audit-Zeile nenntPersonalKeynicht.
S5 — Client für die ConMeet Public API
Erfüllt: R20, R52, R63, R64 (Backend), R95 (Aufruf), R42 (Logs)
Abhängig von: — · parallel zu S1–S4
Dateien: CI/ (Client-Klasse, Ablage nach references/structure.md des Generators), Tests unter srv/ConMeet.Core.Tests/Features/ConMeetInstances/
Zu tun:
- Typisierter Client nach dem Muster
BootstrapClient.cs:30:GET {BaseUrl}/api/public/v1/customers?limit=1mitAuthorization: Bearer, ohne Cookies. - Ergebnis mit Zustand nach R63, Statuscode, Antworttext (nicht bei
CONNECTED, sonst auf 2000 Zeichen gekürzt) oder Fehlerart ohne Antwort. - Zeitlimit 10 Sekunden je Aufruf und keine Wiederholungen: Standard-Resilience aus
srv/ConMeet.ServiceDefaults/Extensions.cs:23für diesen Client ersetzen. - Header
Authorizationin Logs und Traces schwärzen. Fertig, wenn: Tests mit einem gestellten HTTP-Handler ergeben je Antwort (200, 401, 403, 402, 429, 500, 404, Zeitüberschreitung, TLS-Fehler) den Zustand aus R63; der Text bei 200 fehlt, bei 404 ist er gekürzt; kein Log enthält den Schlüssel.
S6 — Registry, Service: Instanzen verbinden, ändern, trennen, Prüfkonto (Generator-Stufe 3)
Erfüllt: R1, R2, R3, R11, R13, R14 (Zählung), R15, R53, R67 (Ergebnis), R73, R74, R75, R82 (Instanz), R90, R91, R92, R93, R94, R95, R98, R99
Abhängig von: S2, S4, S5
Dateien: CI/ConMeetInstancesRegistry.cs, CI/ConMeetInstancesService.cs, neu srv/ConMeet.Service/Features/VerticalFeatures.cs
(analog CrosscuttingFeature.cs:11, ruft AddConMeetInstancesFeature()), srv/ConMeet.Service/Program.cs:10 (nach dem Querschnitt),
Tests unter srv/ConMeet.Core.Tests/Features/ConMeetInstances/
Zu tun:
- Registry mit Schalter
Features:ConMeetInstances:Enabledund Abhängigkeitsprüfung wieUsersRegistry.cs:15; registriert Service, Client und Verschlüsselung aus S2. - Verbinden: Pflichtfelder und Längen (
InvalidInputException),httpsaußer inDevelopment, Normalisierung der Adresse samt Pfad und Port, Eindeutigkeit von Name und Adresse; Prüfkonto mit verschlüsseltem Schlüssel,IsAdminundInstanceGrantdes Verbindenden in einer Transaktion; Eindeutigkeit des Benutzernamens vor der Prüfung; Prüfung nach dem Speichern, Ergebnis zurückgeben, Fehlschlag ist kein Fehler. - Ändern: Name, Kommentar, Adresse; Berechtigungen und Verknüpfungen bleiben; Konflikt der Zeilenversion →
InstanceChangedException; danach prüfen. - Trennen: Zahl aller Verknüpfungen für den Dialog liefern; Instanz, Grants, Links mit
ExecuteDeleteohne Soft-Delete-Filter und je Zeile eine Audit-Zeile, in einer Transaktion (MusterSuiteReplica.cs:222). - Prüfung der Instanz mit dem Schlüssel des Prüfkontos, auch ruhend; ohne Prüfkonto
NO_ADMIN_LINK. - Übernahme: eigene, nicht ruhende Verknüpfung erhält
IsAdmin, die bisherige verliert es, in einer Transaktion; ohne eigeneAccountNotLinkedException. Fertig, wenn: Servicetests gegen PostgreSQL decken Beispiel-Schritte 1, 2 und 8 der Spezifikation ab, dazu:httpaußerhalbDevelopmentabgewiesen, Adresse mit anderem Pfad erlaubt, gleichzeitiges Ändern →INSTANCE_CHANGED, Übernahme verschiebtIsAdmin, ohne PrüfkontoNO_ADMIN_LINK. Abgeschaltete Vertikale registriert nichts.
S7 — Berechtigen und Aufräumen beim Entfernen eines Benutzers
Erfüllt: R5 (Grant), R22, R23, R24, R25 (Speicherung), R26, R27, R51 (Daten), R69, R70, R86, R87 (Vertikale)
Abhängig von: S3, S6
Dateien: CI/ConMeetInstancesService.cs, CI/ConMeetInstancesRegistry.cs, Tests unter srv/ConMeet.Core.Tests/Features/ConMeetInstances/
Zu tun:
- „Alle“ setzen und entfernen; Einzelberechtigung nur für Benutzer des Mandanten mit gültiger Lizenz für
conmeet-base(Lizenzlogik ausUserAccessResolver.EntitledFeatureCodesAsync); Entzug löscht das Grant physisch. - Berechtigungsprüfung als eine Stelle im Service:
GrantedToAlloder Grant; ruhende Verknüpfung = Verknüpfung ohne Berechtigung, nichts wird gelöscht. - Personenliste: lizenzierte Benutzer (bei „Alle“ alle lizenzierten des Mandanten) mit Verknüpfungsstand, ruhende ausgeblendet, Prüfkonto gekennzeichnet.
- Teilnehmer am Erweiterungspunkt aus S3 registrieren: löscht Grants und Links des Benutzers physisch mit Audit-Zeilen; ein entfallendes Prüfkonto hinterlässt die Instanz ohne
IsAdmin. Fertig, wenn: Tests decken Beispiel-Schritte 3 und 7 ab, dazu: unlizenzierter Benutzer nicht berechtigbar, „Alle“ blendet Einzelberechtigungen aus und stellt sie beim Entfernen wieder her,UserDeleteddes Prüfkonto-Inhabers → Instanz liefertNO_ADMIN_LINK.
S8 — Konto verknüpfen, ersetzen, lösen
Erfüllt: R5 (Link), R29 (Daten), R30, R37, R38, R39, R40 (Anwendung), R44, R49, R50, R54, R57, R61, R65, R68, R79, R80, R81, R82 (Link), R89, R95 (Link), R96, R97
Abhängig von: S7
Dateien: CI/ConMeetInstancesService.cs, Tests unter srv/ConMeet.Core.Tests/Features/ConMeetInstances/
Zu tun:
- Alle Operationen wirken nur auf den Link des angemeldeten Benutzers; keine Benutzer-ID als Eingabe.
- Verknüpfen und Ersetzen: Berechtigung prüfen, Benutzername trimmen und Länge prüfen, Eindeutigkeit ohne Groß-/Kleinschreibung über alle Links der Instanz, dann Prüfung mit dem eingegebenen Schlüssel; nur bei
CONNECTEDverschlüsselt speichern, sonstConMeetCheckFailedExceptionmit Statuscode und Antworttext. - Lösen: ohne Berechtigung
InstanceNotGrantedException; Prüfkonto →AdminLinkRequiredException; ohne Link ohne Wirkung; sonst physisch löschen. - Eigene Prüfung: ohne Berechtigung
InstanceNotGrantedException, ohne LinkAccountNotLinkedException. - Liste „meine Instanzen“: berechtigte Instanzen mit eigenem Link (Benutzername,
IsAdmin). - Kein Code greift im Namen einer Person auf einen anderen Schlüssel als ihren eigenen zurück.
Fertig, wenn: Tests decken Beispiel-Schritte 4–6 ab, dazu:
Clara.Schmidtgegenclara.schmidtabgewiesen ohne Aufruf an ConMeet, ruhender Name bleibt belegt,KEY_REJECTEDspeichert nichts, Prüfkonto nicht lösbar, fremde Instanz →INSTANCE_NOT_GRANTED.
S9 — GraphQL-Port (Generator-Stufe 4)
Erfüllt: R8, R38, R41, R46, R49, R66, R67, R73 (Code), R82 (Code), R83 (Codes), R89, R100 (API)
Abhängig von: S1, S8
Dateien: CI/Api/ (Queries, Mutations, Typen, Fehlerfilter), CI/ConMeetInstancesRegistry.cs,
Schema-Snapshot-Test unter srv/ConMeet.Core.Tests/Features/ConMeetInstances/, Bruno-Collection api/ (neu, nach references/bruno.md des Generators), web/schema.graphql
Zu tun:
- Operationen aus Abschnitt 7 der Spezifikation als
[ExtendObjectType]-Erweiterungen (MusterUserQueries.cs:8,QuickAccessMutations.cs:9); Verwaltung unter der PolicyManageInstances, persönliche unter der Standard-Policy. - Typen ohne Schlüsselfelder; Instanz mit Inhaber und Benutzername des Prüfkontos; Basis über
GraphQLHelpers.cs:10. - Fehlerfilter der Vertikale, registriert in ihrer Registry: jede Exception der Vertikale auf ihren Code in
extensions.code(so liest der BFF Codes,web/src/lib/server/graphql/client.ts:32),CONMEET_CHECK_FAILEDmit Statuscode und Antworttext,INVALID_INPUTmit Feldname; gilt für Queries und Mutations. Keine[Error<T>]-Typen der Mutation-Konventionen. - Schema exportieren (
pnpm codegen:schema), ersten Schema-Snapshot-Test des Projekts anlegen, erste Bruno-Collection unterapi/mit Anfragen je Operation. Fertig, wenn:AuthorizationPolicyTests.cs:47grün mit den neuen Feldern; HTTP-Tests: Mitarbeitende erhalten bei Verwaltungsoperationen „nicht autorisiert“, Instanz eines anderen Mandanten →INSTANCE_NOT_FOUND, Schema enthält kein Schlüsselfeld; Snapshot steht.
S10 — Oberfläche: Verwaltung der Instanzen
Erfüllt: R9 (UI), R14 (Dialog), R18, R19, R24 (Auswahl), R25 (Anzeige), R43, R47, R48, R51 (Anzeige), R64 (Anzeige), R76, R77, R78, R83 (Anzeige), R100
Abhängig von: S9 · parallel zu S11
Dateien: web/src/routes/(authenticated)/admin/conmeet-instances/ (neu, Liste und [id]), Remote Functions und
.graphql-Dokumente unter web/src/lib/features/conmeet-instances/ (neu), web/src/lib/components/layout/app-sidebar.svelte:39,
fehlende shadcn-Komponenten (Bestätigungsdialog, Tabelle, Label, Textarea, Schalter) per CLI, Tests nach web/src/lib/features/*/*.spec.ts und web/src/routes/access.e2e.ts
Zu tun:
- Navigationseintrag „ConMeet-Instanzen“ nur bei
ManageInstancesausme.permissions. - Liste sofort anzeigen, je Zeile „Wird geprüft …“, höchstens fünf Prüfungen gleichzeitig, „Erneut prüfen“; Status mit Code und aufklappbarem Text; Empty State mit „Instanz verbinden“.
- Sheet zum Verbinden (inkl. Benutzername und Schlüssel des Prüfkontos, Feld
passwordohne Autovervollständigung) und Bearbeiten; Meldungen je Code am Feld oder als Hinweis. - Detailseite: Freigabe „Alle“, durchsuchbare Auswahl lizenzierter Personen (bei „Alle“ ausgeblendet), Personenliste mit Verknüpfungsstand und „Prüfkonto“, „Prüfkonto übernehmen“, „Trennen“ im Bestätigungsdialog mit Zahl der Verknüpfungen.
- Muster nach
validdata-frontend-patterns, Gestaltung nachvaliddata-styleguide. Fertig, wenn: Als Anna lokal: Instanz verbinden, Status erscheint ohne Klick, Trennen nennt die Zahl; als Tom erscheint der Eintrag nicht und die Adresse liefert keine Daten. Unit-Tests für die Begrenzung auf fünf Prüfungen.
S11 — Oberfläche: Meine ConMeet-Verbindungen
Erfüllt: R29, R37 (Dialog), R43, R47, R60, R61 (UI), R62, R64 (Anzeige), R71, R76, R78, R83 (Anzeige)
Abhängig von: S9 · parallel zu S10
Dateien: web/src/routes/(authenticated)/conmeet-connections/ (neu), web/src/lib/features/conmeet-instances/,
web/src/lib/components/layout/app-sidebar.svelte:39, Tests wie S10
Zu tun:
- Navigationseintrag „Meine ConMeet-Verbindungen“ für jede Person mit
READY. - Liste berechtigter Instanzen mit Name, Kommentar und Status nach R71; Text bei leerer Liste nach R29.
- Prüfung verknüpfter Instanzen beim Öffnen, höchstens fünf gleichzeitig, Status mit Code und Text.
- Sheet „Verknüpfen“/„Schlüssel ersetzen“ mit Benutzername, Schlüssel (
password) und Anleitung; „Verknüpfung lösen“ im Bestätigungsdialog;ADMIN_LINK_REQUIREDals Meldung. Fertig, wenn: Lokal mit zwei Personen sind Beispiel-Schritte 4–6 gegen die ConMeet-Testumgebung (https://dev.conmeet.io) durchspielbar; ein e2e-Test deckt Verknüpfen mit abgelehntem Schlüssel gegen die Testumgebung ab. Keine gestellte Gegenstelle.
Reihenfolge
S1 ─────────────────────────────┐
S2 ──┐ │
S4 ──┼──► S6 ──► S7 ──► S8 ──► S9 ──► S10
S5 ──┘ ▲ └──► S11
S3 ──────────────┘
S1–S5 sind voneinander unabhängig und können parallel laufen. S10 und S11 sind nach S9 unabhängig.
Entschieden
Entscheidungen von Martin Linkwitz am 2026-10-29, Grundlage der Schritte:
- Verschlüsselung: direkt in der Vertikale, ohne eigenen Querschnitt (S2).
- Registrierung fachlicher Vertikalen:
srv/ConMeet.Service/Features/VerticalFeatures.cs(S6). - Fehlercodes: Fehlerfilter der Vertikale setzt
extensions.code, für Queries und Mutations (S9). - Tests gegen ConMeet: gegen die vorhandene Testumgebung, keine gestellte Gegenstelle (S11).
- Format der
vertical.json: eine Entität, Beziehungen der Kinder alsInstanceGrant.UserIdundAccountLink.UserId. - Bruno und Schema-Snapshot: S9 legt die erste Collection und den ersten Snapshot an.
- Mandantenwechsel ohne Neuanlage:
SuiteReplica.cs:74verweigert ihn und protokolliert nur; R69 greift dann nicht. Bleibt so, 001 verlangt es nicht.
Offene Entscheidungen
- Offen in der Spezifikation: Rollencode
conmeet-adminnoch nicht von Core bestätigt (R7); Wortlaut der Anleitung zum Schlüssel (R62) — S11 setzt einen Platzhaltertext.
Nicht im Plan
- Fachliche Aufrufe an ConMeet im Namen einer Person (Anrufinformation) — R30 legt nur fest, welcher Schlüssel gilt; eigene Spezifikationen.
- Contracts für andere Vertikalen (
vertical.json: keine) — folgen mit der Anrufinformation. - Schlüsselwechsel für
Secrets:EncryptionKey— nach R72 nicht vorgesehen. - Umbau des Mandantenwechsels in
SuiteReplica— siehe Entschieden.