Verifikation unabhaengig nachgemessen: 651/651 API-Tests, 233/233 Web-Tests,
beide Typpruefungen sauber.
Der Sicherheitsfund T-Q3-01 wurde nicht nur gruen getestet, sondern
falsifiziert: der Verifizierer hat die neue Besitzpruefung testweise
zurueckgebaut, woraufhin der Test fehlschlug und die fremde Adresse
tatsaechlich in prisma.user.update() landete. Danach sauber zurueckgesetzt.
Ebenso gegengeprueft: beide Anlege-Wege (Sync und Einzelimport) nutzen
denselben Kollisionsentscheider, im ausgelieferten Code stehen keine
kundenspezifischen Namen oder Adressen, rohe ORM-Texte erreichen die
Oberflaeche nicht mehr, und die Gruppensuche unter internem wie AD-Namen
(#6c) ist per Regressionstest gesichert.
Eine Abweichung des Ausfuehrenden ist dokumentiert und bestaetigt: die im
Plan vorgesehene Testvorlage war wegen Kurzschlussauswertung schon gegen den
unveraenderten Code gruen; mit einem zweiten, nicht passenden Konto
reproduziert sie den Absturz nun wirklich.
Status human_needed: die fuenf Browser-Pruefungen brauchen einen Neubau und
sind Sache des Users. WINDOWS #14 und #15 bleiben bis dahin offen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
WINDOWS #14 (Suche leert die jeweils andere Achse der Freigaben-Matrix) und
WINDOWS #15 (roher Prisma-/englischer Techniktext im AD-Sync, vier Konten
wegen geteilter E-Mail-Adresse nie importiert) als drei getrennte Tasks.
Gesperrte Nutzerentscheidung vom 2026-09-09: kollidierende Konten werden
angelegt, nur ohne Adresse. Dafuer wird User.email optional — Migration wird
geschrieben, nicht ausgefuehrt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
Abnahme im Browser auf alpha gegen den echten Exchange owa.ctl.de, nachdem die
Container mit --force-recreate getauscht waren. Der blosse pull genuegte nicht:
die neue Route fehlte im laufenden Container und war im gezogenen Image
vorhanden — hart belegt statt vermutet.
Alle vier Punkte bestanden:
- gespeicherte Konfiguration mit LEEREM Passwortfeld meldet "Verbindung
erfolgreich" — belegt zugleich den Rueckgriff auf die gespeicherten
verschluesselten Zugangsdaten
- absichtlich falscher Server meldet "Verbindung fehlgeschlagen: getaddrinfo
ENOTFOUND owa-gibtsnicht.ctl.de"
- keine Zugangsdaten im API-Protokoll (die Treffer einer Mustersuche waren
Routennamen wie /auth/reset-password)
- der Test schreibt nichts; die gespeicherte Konfiguration blieb unveraendert
Nebenbefund mit Gewicht: das Protokoll zeigt eine echte Antwort von Exchange
2019 (ServerVersionInfo 15.2) samt aufgeloester FolderId. Der in Plan 14-03 als
fragil markierte, handgeschriebene NTLM/SOAP-Weg ist damit erstmals gegen einen
echten Server gemessen — bisher lag nur gemocktes httpntlm.post vor.
WINDOWS #12 zurueckgestellt (waived): es gibt intern kein Postfach, in das
Ausschreibungs-Alarme hereinkommen. Ein frueheres Missverstaendnis hatte eines
angenommen. Nachzuholen, sobald ein solches Postfach existiert; offen ist dann
allein das Einlesen einer echten Alarm-Mail.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
Abschluss-Dokumentation zum nachgeruesteten Verbindungstest (WINDOWS #16).
Verifikation unabhaengig nachgemessen, nicht aus dem Ausfuehrungsbericht
uebernommen: 646/646 API-Tests, 228/228 Web-Tests, beide Typpruefungen
sauber, und das Sprachschluessel-Gate ist von rot ("de fehlt testConnection")
auf gruen gewechselt. Sicherheitsseitig geprueft: die DTO traegt kein
Eigentuemer-Feld, der Handler zieht userId ausschliesslich aus dem
Auth-Kontext (eigener IDOR-Test mit Koeder-userId), Rueckfall auf gespeicherte
Zugangsdaten sucht nur ueber denselben userId, und in den geaenderten Dateien
findet sich keine Log- oder Antwortstelle mit Zugangsdaten.
Status bleibt human_needed: die Browser-Abnahme gegen ein echtes Postfach
steht aus und braucht einen Neubau durch den User. WINDOWS #16 bleibt
deshalb offen.
Ausserdem workflow.use_worktrees auf false: origin/HEAD ist in diesem Repo
nicht aufloesbar, der Basis-Check des Workflows verlangt daher selbst
sequenzielle Ausfuehrung ("fork-ref-unknown"). Ein isolierter Arbeitsbaum
wuerde von einem veralteten Stand abzweigen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
Schliesst WINDOWS #16. Zwei Tasks: Endpunkt POST email-config/test
(Dienst + Route + Reihenfolge-Waechter) und Knopf 'Verbindung testen'
im Formular unter Meine Quellen samt Beschriftungen in beiden Sprachen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
Beide Korrekturen im Browser gegengeprueft. Der aussagekraeftigste Fall ist die
Gruppe "Alle Benutzer" mit zwei Mitgliedern und einer Freigabe: der Dialog schreibt
"2 Mitglieder und 1 Modul-Freigabe" — Mehrzahl und Einzahl im selben Satz, jede Zahl
einzeln richtig. Bei "Vertrieb Innendienst" mit je einem heisst es durchgaengig
Einzahl.
Die vier Du-Stellen sind ebenfalls im Browser bestaetigt: Aktivierungsdialog,
Sperrseite und Marktplatz-Hinweis siezen jetzt. Der Leerzustand der Gruppenliste ist
live nicht erreichbar, weil Gruppen existieren — er bleibt durch den Komponententest
abgedeckt.
Der UAT-Bericht zu Phase 15, in dem beide Maengel urspruenglich notiert wurden, ist
entsprechend nachgezogen. Dort war nur der Aktivierungsdialog als Du-Stelle vermerkt;
bei der Korrektur kamen drei weitere zum Vorschein.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Zwei Wortlaut-Maengel, beide am Code verifiziert: vier deutsche Texte duzen
statt zu siezen, und der Gruppen-Loeschdialog setzt zwei Zahlen in fest
formulierte Mehrzahl-Woerter ("1 Mitglieder").
Beim Planen nachgeprueft: der Mock-Uebersetzer in groups-page.test.tsx kann
kein ICU-Plural — die Umstellung wuerde die beiden bestehenden
Loeschdialog-Tests brechen. Der Plan loest das ueber dieselbe Regex-Technik,
mit der grants-matrix.test.tsx bereits ICU-select aufloest, und nagelt den
Einzahl-Fall mit einem neuen Test fest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Die Browser-Abnahme hat drei uebersehene Stellen gefunden — "Aenderungen speichern",
"Oeffnen" und einen LDAP-Hinweis — und damit die Luecke im Waechter aufgedeckt, durch
die sie geschluepft sind: sein Verdachtsmuster war case-sensitiv. Beides mit 85d2d77
behoben.
In der SUMMARY festgehalten, wie geprueft wurde: eine unabhaengige Analyse aller
Tokens in de.json findet keine Ersatzschreibung mehr, der Schluesselsatz ist
unveraendert bei 787, und die Modulbeschreibung in der bestehenden Datenbank ist beim
API-Neustart per Seed-Upsert mitgewandert — ohne Migration, wie geplant.
Ausserdem vermerkt, dass eine erste Sichtpruefung per fetch aus der laufenden Seite
faelschlich Entwarnung gab. Dieselbe Methode hatte in dieser Sitzung schon einmal ein
falsches Ergebnis geliefert; die berichteten Zahlen stammen aus echten
Seitenaufrufen.
Backlog-Punkt zu den Umlauten nach completed verschoben.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Dokumentiert die drei ausgefuehrten Tasks (Woerterbuch + de.json,
Vitest-Waechter, API-Texte), die zwei waehrend Task 2 selbst
entdeckten und behobenen Woerterbuch-Luecken sowie die realen
Test-/Build-Ergebnisse fuer beide Apps. Task 4 (Sichtpruefung nach
Docker-Rebuild) bleibt dem Orchestrator ueberlassen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Task 3 (Browser-Abnahme) ist durchgefuehrt. Von den beiden zur Freigabe gestellten
Gestaltungsfragen wurde eine zurueckgewiesen und eine blieb offen:
Die Anordnung auf dem Anmelde-Panel hat der User weder als "Marke oben" noch als
"Marke unten" abgenommen, sondern eine dritte Loesung verlangt — Logo links, Text
rechts daneben, wie in der gelieferten Schriftzug-Datei. Nachgezogen mit 11c0ec6.
Zur Schriftzugfarbe hat er sich nicht geaeussert; sie bleibt vorerst dunkel, die
Rueckkehr zu Gelb wurde als jederzeit moeglich angeboten.
Ausserdem in der SUMMARY festgehalten, dass die Abnahme einen Defekt ausserhalb dieses
Plans aufgedeckt hat: die Tailwind-Dunkelvariante war nie an die .dark-Klasse gebunden
(WINDOWS #13, behoben mit f8d7da0). Der Logo-Einbau hat ihn nur sichtbar gemacht,
verursacht hat er ihn nicht.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Dokumentiert die uebernommenen/ausgelassenen Lieferdateien, die Begruendung
fuer Text- statt Bild-Schriftzug, die Konturloesung der dunklen Platte, die
Zusammenfuehrung des Gelbwerts sowie zwei waehrend Task 2 automatisch
behobene Deviationen. Status halted, weil Task 3
(checkpoint:human-verify) absichtlich nicht ausgefuehrt wurde.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
WINDOWS.md #11 als fixed markiert — Fingerprint-Stufe hasht nur noch
[buyerName, title, deadlineAt], Wert kehrt als exakter Widerspruchs-Veto
zurueck, 16.255 Bestandszeilen wurden gegen die lokale DB nachgerechnet
(0 -> 26 Duplikat-Gruppen, davon 2 durch den Veto geschuetzt).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Fingerprint hasht kuenftig nur noch Vergabestelle/Titel/Frist, der Wert
kehrt als Widerspruchspruefung am Treffer zurueck, Versionsmarke plus
Bootstrap-Nachrechnung stellt Bestand und frische Installation gleich.
Beim Erden gemessen und mit aufgenommen: der Aktualisierungszweig in
TenderDedupService schreibt den Fingerabdruck nicht mit, wodurch drei
Gruppen echter Duplikate schon heute allein durch Drift auseinanderstehen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Beide Tasks des Plans ausgefuehrt, verifiziert und committed
(4a23e13, 69b6418). Automatisierte Verifikation vollstaendig gruen:
Gate-Tests, Layout-Tests, volle Web-Suite (213/213), Typpruefung und
Produktionsbau. Browser-Gegenprobe (A/B/C) bleibt laut Plan Aufgabe
des Orchestrators nach Docker-Rebuild — WINDOWS #10 bleibt bis dahin
offen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
WINDOWS #10: der Zugriffs-Guard sitzt nur in der generischen Route
modules/[category]/[moduleSlug]/page.tsx. Die vier fest verdrahteten
Modulverzeichnisse laufen daran vorbei.
Plan: gemeinsame 403-Komponente + ModuleAccessGate (Server Component),
je ein layout.tsx pro Modulverzeichnis (deckt Unterrouten mit ab),
generische Route auf dieselben Bausteine umgestellt. Zwei Tasks,
Browser-Gegenprobe als human-check.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
Records the user's choice between the two candidate link targets (the notice
page on oeffentlichevergabe.de, not the awarding portal's own page), what was
checked before touching the adapter, and the trap in verifying it: the target
is a single-page app that answers 200 with an identical shell for any id, so
only rendered content proves the link works.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quick task 260811-f9i: plan and summary of the fix, STATE.md row, and the UAT
test 2 result. Test 2 was the read-only A2 check against the real directory --
it turned assumption A2 from "unverified" into "false as implemented" and
surfaced a defect that would have deleted every AD-bound group on the first
real sync.
Also records why the defect survived review: the spec mocks built their
expected filter with the same escape helper the production code used, so the
test asserted self-consistency rather than directory behaviour.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bindDn and bindPassword are now optional on LdapConfig (nullable
migration) and throughout the DTOs/service/client -- an admin can
leave both blank to connect to directories that permit anonymous
read access. LdapService.bind() falls back to an RFC 4513 anonymous
bind (empty DN + empty password) whenever either field is missing,
shared across testConnection, listGroups, and syncUsersForTenant.
Frontend: removed the required attribute from Bind-DN/Bind-Passwort,
added a placeholder hint ("leer = anonymous bind"), and the
"Verbindung testen" button now only needs a Server-URL to enable
(not bindDn+bindPassword). Config responses now return bindPassword
as null (not a misleading "********") when no password is set.
Verified locally: submitted only a Server-URL with both bind fields
empty and confirmed the request reached the anonymous-bind code path
(DNS failure for the unreachable test host, not a validation error).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Prisma: domain String? added to CalendarSource model (db push applied)
- DTOs: domain in CreateCalendarSourceDto, UpdateCalendarSourceDto, new TestCalendarSourceConfigDto
- Service: domain in SOURCE_SAFE_SELECT, addSource, updateSource; new testConnectionFromConfig method
- Controller: POST /calendar/sources/test-config (before :id routes to avoid collision)
- ExchangeProvider: domain in all source interfaces; passed as 3rd arg to EWS WebCredentials
- Frontend: domain in CalendarSource/CreateSourcePayload/UpdateSourcePayload; testSourceConfig API fn
- Form: domain field (Exchange-only), "Test connection" button with idle/loading/success/error states
- i18n: de+en keys for formFieldDomain, formFieldDomainHint, formTestConnection, formTesting, formTestSuccess, formTestFailed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>