feat(260911-gwh): GREEN — favorites/settings binden, Startpfad umbenennen, Widget-Besitzriegel

- 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
This commit is contained in:
2026-09-11 13:57:02 +02:00
parent 8f2c13a35f
commit b5f22e2c4a
4 changed files with 149 additions and 31 deletions
+12 -5
View File
@@ -12,13 +12,19 @@ import { MailService } from './mail.service';
* with an env-var fallback (priority 2) when no DB row exists.
*
* Transport priority:
* 1. DB SmtpConfig (first row — single-tenant default; set via /settings/smtp)
* 1. DB SmtpConfig (loadAnySmtpConfigForStartupTransport — bewusst
* UNGEBUNDEN, sechster Fall der Hintergrunddienst-Falle, 260911-gwh;
* siehe deren Kopfkommentar in settings.service.ts fuer beide
* Zustaende: HEUTE zieht sie den Server EINES beliebigen Mandanten fuer
* alle Systemmails [T-GWH-03], NACH DEM SCHARFSCHALTEN liefert sie
* `null` und diese Rueckfallkette greift — WINDOWS #TBD-GWH)
* 2. Env vars: MAIL_HOST / MAIL_PORT / MAIL_USER / MAIL_PASS
* 3. Legacy env vars: TESSERA_SMTP_HOST / TESSERA_SMTP_PORT / TESSERA_SMTP_USER / TESSERA_SMTP_PASSWORD
* 4. Final hardcoded fallback: localhost:1025 (Mailhog / dev default)
*
* The factory is async because getStartupSmtpConfig() reads from the DB.
* No circular import risk: MailModule → SettingsModule → CalendarModule (no reverse edges).
* The factory is async because loadAnySmtpConfigForStartupTransport() reads
* from the DB. No circular import risk: MailModule → SettingsModule →
* CalendarModule (no reverse edges).
*/
@Module({
imports: [
@@ -26,8 +32,9 @@ import { MailService } from './mail.service';
MailerModule.forRootAsync({
imports: [SettingsModule],
useFactory: async (settingsService: SettingsService, configService: ConfigService) => {
// Priority 1: DB SmtpConfig (getStartupSmtpConfig uses findFirst — single-tenant default)
const db = await settingsService.getStartupSmtpConfig();
// Priority 1: DB SmtpConfig — loadAnySmtpConfigForStartupTransport()
// stays bewusst UNGEBUNDEN (findFirst, no tenant context at boot).
const db = await settingsService.loadAnySmtpConfigForStartupTransport();
if (db) {
// T-07-11: DB password used only to build transport; never logged