- module-registry.service.ts: findActiveForTenant, activateForTenant,
isModuleActive binden je einen Aktivierungszugriff, deactivateForTenant
bindet beide (Lesen+Schreiben) ueber EINEN Klienten unter tenantPrisma;
alle sechs Katalogzugriffe (findAll/findBySlug/beide
Existenzpruefungen/isModuleActive-Katalogsuche/seedModule) bleiben
bewusst ungebunden, mit Kommentar der Messung von Bedingung trennt
- isModuleActive-Kopfkommentar richtiggestellt: der Waechter ruft sie
nicht auf (0 Aufrufer, TEIL 3 von Aufgabe 1) — Waechter nimmt findBySlug
+ ModuleAccessService.getAccessibleModuleIds
- module-registry.service.spec.ts: NEU, Zwei-Klienten-Nachweis, deckt die
bislang ungetestete Datei mit elf der siebzehn Zugriffe des Bereichs ab,
inkl. der lauten (deactivate ohne Aktivierung) und stillen (isModuleActive
ohne Aktivierung) Richtung und dem Katalog-Wachhund
- tender-scheduler.service.spec.ts: forTenant() auf Identitaet gemockt
(dieselbe Konvention wie ldap.service.spec.ts) — cross-area Bruch durch
die Umstellung von activateForTenant behoben (Rule 1/3)
- docs/mandantentrennung-zugriffsklassifikation.md: alle fuenf
handgepflegten Stellen nachgezogen (Bestandsaufnahme, Uebersichtszeile
7/10, Summenzeile 108/134, Klassen-Verteilung unveraendert bei 63 Paaren,
Hintergrunddienst-Abschnitt haelt die Abwesenheit eines sechsten Falls
fest) — alle gemessen, nicht abgeschrieben, Befund K haelt exakt
- docs/mandantentrennung-etappe2-fehlerrichtung.md: Nachtrag mit
tatsaechlich umgesetzten Pfaden, beiden Falsifizierungsnachweisen
(Testname+Meldung), und der Feststellung zum unveraenderten
Controller-Kommentar
- .planning/WINDOWS.md: neuer offener Eintrag #23 (deviation) — kein Signal
unterscheidet "keine Freigabe" von "Abfrage fand nichts", mit
Vorabpruefung fuer Etappe 4 und begruendeter Verwerfung einer
Laufzeitwarnung
- 833 Tests gruen (56 Dateien), Typpruefung sauber, Wegwerf-Werkzeug 66/66
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AMASaSxv5QMY7RncqZriRR
On a fresh database the DÖE poll cron was never registered: TenderScheduler
read the doe-opendata poll config in its onModuleInit, which raced ahead of
TendersModule.onModuleInit seeding that config. The scheduler saw the config
absent → skipped registering the single global cron that drives pollDueSources
(DÖE + RSS + email-alert) → the platform ingested NOTHING until a second restart.
Observed live on a fresh prod DB (0 tenders, 'doe-opendata config inactive —
cron job not registered', lastIngestedDay null despite isActive=true).
Move the scheduler to onApplicationBootstrap, which runs after every module's
onModuleInit, so the seed is guaranteed complete before the config is read.
Adds a regression test asserting the lifecycle choice.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Proves the phase's headline acceptance criterion: activating tender-radar
for a 2nd tenant triggers zero additional DÖE calls, zero additional cron
jobs (still exactly one 'tender-doe-poll'), and zero additional Tender rows.
Drives the real (unmocked) ModuleRegistryService against a fake prisma to
exercise the genuine activateForTenant() call path.
Passes immediately because Task 2's TenderSchedulerService already
implements the poll-once-fan-out-many invariant correctly — this test
locks in and regression-proofs that already-correct architecture rather
than driving new production code (documented in SUMMARY under TDD Gate
Compliance).