httpntlm (exchange.provider, exchange-inbox.provider): NtlmOptions und
NtlmResponse beschreiben genau das, was uebergeben und gelesen wird. Die
ueberfluessige Zusicherung (httpntlm as any) faellt weg.
Graph-Rueckrufe (exchange.provider :157/:313): AuthProviderCallback aus dem
SDK selbst statt Handannotation - als import type, also ohne den dynamischen
Import zur Laufzeit zurueckzunehmen.
imapflow: streamToBuffer() nimmt Readable statt NodeJS.ReadableStream (alle
drei Aufrufer reichen client.download().content herein, imapflow deklariert
das als Readable) - damit traegt der Typ destroy() und die Zusicherung
faellt. node.parameters?.name war ebenfalls schon getypt.
nodemailer: ResolvedTransport.options wird SMTPTransport.Options; beide
Zweige bauen reine SMTP-Optionen, createTransport() nimmt sie ohne
Zusicherung.
node-forge: die vier let p7: any werden Captured<PkcsEnvelopedData |
PkcsSignedData> - der MITGELIEFERTE Typ. Die Lesestellen grenzen mit
'certificates' in p7 ein statt zuzusichern; verhaltensgleich, weil der
enveloped-Form das Feld fehlt und beide Schreibweisen dann die leere Liste
liefern. cert.siginfo war bereits getypt.
apps/web/src/test/setup.ts: expect.extend(matchers) traegt ohne Zusicherung
- geprueft im echten Typlauf (setup.ts liegt im include von
apps/web/tsconfig.json, mit einem absichtlichen Fehler nachgewiesen).
BEFUND 4 (D-03, gemeldet, NICHT repariert) imap.provider.ts:78 - der
Ausdruck (node as any).disposition?.parameters?.filename liest .parameters
von einer ZEICHENKETTE: imapflow deklariert disposition als string
(imap-flow.d.ts:448), die Parameter liegen in dispositionParameters (:450).
dispositionFilename ist damit zur Laufzeit immer ''. Folge: Outlook-Anhaenge,
die als application/octet-stream kommen, werden ueber den Dateinamen aus
Content-Disposition NICHT erkannt - nur ueber den aus Content-Type. Umbiegen
waere eine Verhaltensaenderung; die Zusicherung bleibt sichtbar stehen.
BEFUND 5 (D-03, gemeldet, NICHT repariert) imap.provider.ts:402 -
requireTLS kommt in imapflow 1.4.3 NIRGENDS vor, weder in ImapFlowOptions
noch im Laufzeitcode (beides durchsucht). Die Option wird still verworfen;
STARTTLS wird durch sie nicht erzwungen. Genau das } as any hat es
verdeckt. Bleibt stehen, damit der Befund in der Zaehlung sichtbar ist.
BEFUND 6 (D-03, gemeldet, Verhalten unveraendert) httpntlm liefert den
Rumpf als Zeichenkette, nicht als Buffer: httpreq setzt ihn nur bei
gesetzter Option binary auf Buffer (httpreq@1.1.1/lib/httpreq.js:391),
keiner der beiden Aufrufer setzt sie. Der Bestand rief unbesehen
.toString('utf-8') auf - das ging nur gut, weil String.toString() sein
Argument ignoriert. Die Testdoppel reichen dagegen wirklich Buffer herein.
NtlmResponse.body nennt jetzt beide Formen, die Fallunterscheidung liefert
fuer jede exakt dasselbe Ergebnis wie zuvor.
Urteil BLEIBT mit Begruendung im Code an allen 15 verbleibenden Stellen:
3x addCronJob (require-Umweg aus 07-04), 5x node-forge (EC-Zweig und
extensions: any[] sind in @types/node-forge nicht beschrieben, 2x null as
any wo die Typen die Bibliothek nachweislich falsch beschreiben), 2x
imap-Befunde oben, 2x tx: any plus 2x Gefolge (Aufgabe 1), 1x
disposition-Befund.
noExplicitAny in apps/api/src: 31 -> 15 (Ausgang 288, Schranke 45), apps/web
1 -> 0. type-check 4/4, lint 5/5 (0 error), apps/api 72/1143, apps/web
73/531, rls-access-inventory 30/30. noNonNullAssertion 56, as unknown as 33,
ts-expect-error/ts-ignore 0/0, Unterdrueckungsmarker 1. biome.json, alle
package.json und pnpm-lock.yaml unveraendert.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
- .planning/WINDOWS.md: drei neue offene Eintraege (#30 Startpfad des
Mailmoduls, #31 verschluckte Leere favorites, #32 verschluckte Leere
settings); Platzhalter WINDOWS #TBD-GWH in settings.service.ts und
mail.module.ts durch #30 ersetzt
- docs/mandantentrennung-zugriffsklassifikation.md: Uebersichtszeilen
favorites (0/8, war 7/0) und settings (1/3, war 4/0) neu gemessen;
Summenzeile 68/178 (Endstand Etappe 2); Bestandsaufnahme (favoriteLink
gebunden, smtpConfig gemischt, neue Zeile widgetInstance/gebunden);
Klassen-Verteilung 65 Paare (33/17/13/2); Hintergrunddienst-Abschnitt mit
sechstem Fall (mail.module.ts, WINDOWS #30) und erfuellter
Befund-K-Bedingung; neuer Punkt in "Was diese Etappe NICHT entscheidet"
- docs/mandantentrennung-etappe2-fehlerrichtung.md: Nachtraege unter Befund
K in (t4) und im Uebergaben-Absatz von (d4) -- Reihenfolgebedingung
erfuellt; ## Etappe 2 -- Abschluss mit den derivierten Endzahlen
- docs/anleitung-entwicklung.md: 23 RLS-Tabellen statt sieben, FavoriteLink
nicht mehr als Tabelle ohne Regel, tenantPrisma statt manuellem
tenantId-Filter als gelebter Stil
- rls-access-inventory.spec.ts wieder gruen (11/11), volle Suite 994/994,
Werkzeug 137/137; zwei Dokument-Falsifizierungen durchgefuehrt und
zurueckgenommen (siehe SUMMARY)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AMASaSxv5QMY7RncqZriRR
- favorites.service.ts: alle fuenf Methoden nehmen tenantId als ersten
Parameter, laufen je ueber EINEN Klienten tenantPrisma (7 gebundene
Favoritenzugriffe, 5 Aufrufstellen); create() prueft vor der Icon-Suche,
dass das Ziel-Widget dem Aufrufer gehoert (T-GWH-05, Befund F aus Aufgabe 1
bestaetigt den Fremdschluessel-Durchgriff) -- Widget not found fuer alle
drei Faelle (existiert nicht/Kollege/fremder Mandant)
- favorites.controller.ts: reicht tenantId an alle fuenf Aufrufe durch,
extractContext unveraendert (dashboard-Praezedenzfall)
- settings.service.ts: getSmtpConfig/saveSmtpConfig/getDecryptedSmtpConfig
je EIN Klient (3 gebundene Zugriffe, 3 Aufrufstellen) -- Befund K damit
erfuellt; Startpfad umbenannt in loadAnySmtpConfigForStartupTransport(),
bleibt bewusst ungebunden (sechster Fall der Hintergrunddienst-Falle,
WINDOWS #TBD-GWH -- Aufgabe 3 vergibt die Nummer)
- mail.module.ts: ruft den umbenannten Startpfad auf, Kommentar nennt beide
Zustaende statt "single-tenant default"
- Vier Falsifizierungsnachweise durchgefuehrt und zurueckgenommen (siehe
SUMMARY): (a) 3 Faelle rot, (b) 4 Faelle rot, (c) 9 Faelle rot, (d) 4 Faelle
rot
Bekannt und erwartet (siehe SUMMARY, Praezedenzfall 260911-fh9): zwischen
dieser Aufgabe und Aufgabe 3 ist rls-access-inventory.spec.ts rot (2
Faelle) -- die Klassifikationstabelle ist noch nicht nachgezogen, das ist
Aufgabe 3.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AMASaSxv5QMY7RncqZriRR
Korrigiert die deutschen Zeichenketten in beiden Mails aus
mail.service.ts (Betreff, Passwort-Reset-Fliesstext,
Willkommens-Mail) sowie die domaincheck-Modulbeschreibung in
domaincheck.seed.ts auf echte Umlaute. Wortlaut identisch, nur
Zeichen korrigiert; die englischen Zweige bleiben unveraendert.
seedModule() ist ein upsert mit update-Zweig und laeuft in
onModuleInit — ein API-Neustart schreibt die korrigierte
Beschreibung ueber bestehende Datenbankzeilen, ohne Migration oder
Backfill.
pnpm --filter @tessera/api run build: sauber.
pnpm --filter @tessera/api run type-check: sauber.
pnpm --filter @tessera/api run test: 46 Testdateien, 642 Tests gruen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq