feat(quick-260914-eym): Mail-Transport je Versand nach Mandant (WINDOWS #30), ldap/digest/matching ueber Systemkontext, vier Tabellen im Werkzeug, Erlaubnisliste vollstaendig
- mail: MailerModule-Fabrik und DB-Startpfad (findFirst beim Boot) ersatzlos entfernt; MailService baut je Versand einen nodemailer-Transport aus getDecryptedSmtpConfig(tenantId) des Empfaenger-Mandanten, Umgebungs-Kette (MAIL_* -> TESSERA_SMTP_* -> localhost:1025) nur als Rueckfall; Fehler weiter verschluckt (T-02-12), close() im finally; neue mail.service.spec.ts (4 Tests, T-GWH-03 geschlossen) - settings: Startpfad-Methode samt vier Spec-Tests geloescht; auth: requestPasswordReset reicht user.tenantId durch (Spec-Zusicherung) - ldap: getAllActiveConfigs und Nachverschluesselung lesen ueber forSystem (zwei Zuweisungen), Schreibzeile je Altzeile ueber forTenant(config.tenantId); Tests 301/306 umgedreht, neuer Altzeilen-Test - tender-digest: Kandidatenabfrage ueber forSystem, Schleife gebunden (+1 Test) - tender-matching: Profilabfrage ueber forSystem, Katalog (D-03) ungebunden (+1 Test) - tender-notifications.integration.spec: Mock um forSystem - Werkzeug: LdapConfig (15 Spalten), LdapFieldMapping (6), TenderMatch (8), TenderSavedSearch (8) je neun Kennungen plus Relations-Kennung ldapconfig-systemkontext-include-fieldmappings-beider-mandanten -> Alle 253 Pruefungen bestanden - Detektor: FORSYSTEM_ALLOWED_CALL_SITES auf 4 Dateien / 5 Aufrufe; Proben-Empfaenger sysPrisma (Gate-Zaehlung, Name nicht hartkodiert) - Klassifikation: 6 Zeilen system-gebunden, settings/smtpConfig gebunden - Falsifizierung durch Rueckbau ausgefuehrt und zurueckgenommen: (a) FOR SELECT bei TenderMatch entfernt -> 5 von 253 rot (Insert gelingt, cmd ALL); (b) Regel TenderSavedSearch aus der Datei entfernt -> 1 von 245 rot (Extraktion), lebende DB bleibt bei 34; (c) local=false -> gruen, plus Reset entfernt -> 5 rot (Erben sichtbar); (d) Zahl 0 -> 2 rot, Fremddatei admin-seed -> 3 rot - Baseline: 64 Dateien / 1054 Tests, tsc 0, Werkzeug 253 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
@@ -133,12 +133,29 @@ const RELATION_SPEC_EXCEPTIONS = new Set<string>(['apps/api/src/tenders/backfill
|
||||
* ist die Liste kein "mindestens", sondern ein "genau": jede Datei mit
|
||||
* `forSystem(` ausserhalb der Liste, jede Abweichung der Zahl (auch ein
|
||||
* ZWEITER Aufruf in einer erlaubten Datei) und jeder veraltete Eintrag
|
||||
* (Datei weg oder Zahl gesunken) machen die Spec rot. Aufgabe 1 traegt den
|
||||
* ersten Aufrufer (DKV-Planer-Startpfad); Aufgabe 2 erweitert auf die vier
|
||||
* Dateien der sechs Hintergrunddienst-Faelle.
|
||||
* (Datei weg oder Zahl gesunken) machen die Spec rot.
|
||||
*
|
||||
* Die sechs Faelle der Hintergrunddienst-Falle
|
||||
* (docs/mandantentrennung-zugriffsklassifikation.md) und wo sie stehen:
|
||||
* (1) DKV-Planer-Startpfad -> dkv.service.ts (1 Aufruf,
|
||||
* `loadActiveConfigsForScheduler`); (2) Mailmodul-Startpfad -> NICHT in der
|
||||
* Liste: der Startpfad ist ENTFERNT, `MailService` baut je Versand einen
|
||||
* Transport gebunden ueber `getDecryptedSmtpConfig(tenantId)`
|
||||
* (settings.service.ts/mail.service.ts rufen `forSystem` nie); (3) ldap ->
|
||||
* ldap-config.service.ts (2 Aufrufe: `getAllActiveConfigs` und die
|
||||
* Nachverschluesselung in `onApplicationBootstrap`, je eigene Methode);
|
||||
* (4) tender-digest -> tender-digest.scheduler.ts (1, Kandidatenabfrage);
|
||||
* (5) tender-matching -> tender-matching.service.ts (1, Profilabfrage);
|
||||
* (6) admin-seed -> NICHT in der Liste: der einzige Lesezugriff ausserhalb
|
||||
* der Schleife ist `tenant.findMany` auf `Tenant`, das in keiner Migration
|
||||
* eine Regel traegt — kein Systemkontext noetig, Datei unveraendert.
|
||||
* Summe: 4 Dateien, 5 Aufrufe.
|
||||
*/
|
||||
const FORSYSTEM_ALLOWED_CALL_SITES = new Map<string, number>([
|
||||
['apps/api/src/dkv/dkv.service.ts', 1],
|
||||
['apps/api/src/ldap/ldap-config.service.ts', 2],
|
||||
['apps/api/src/tenders/tender-digest.scheduler.ts', 1],
|
||||
['apps/api/src/tenders/tender-matching.service.ts', 1],
|
||||
]);
|
||||
|
||||
const STAND_TOKENS = ['gebunden', 'ungebunden', 'gemischt', 'system-gebunden'] as const;
|
||||
@@ -1023,13 +1040,13 @@ class ProbeService {
|
||||
expect(unresolvedResult.unresolvedRelationSpecValues).toHaveLength(1);
|
||||
expect(unresolvedResult.unresolvedRelationSpecValues[0]).toContain('IMPORTED_SELECT');
|
||||
});
|
||||
it('Probe C (260914-eym, Systemkontext): `include: { fieldMappings: true }` auf einem forSystem(-Klienten liefert systemModels mit ldapConfig UND ldapFieldMapping, beide weder in bound noch unbound, Stand system-gebunden', () => {
|
||||
it('Probe C (260914-eym, Systemkontext, Empfaengername absichtlich nicht systemPrisma): `include: { fieldMappings: true }` auf einem forSystem(-Klienten liefert systemModels mit ldapConfig UND ldapFieldMapping, beide weder in bound noch unbound, Stand system-gebunden', () => {
|
||||
const probe = `
|
||||
class ProbeService {
|
||||
constructor(private readonly prisma: any) {}
|
||||
async getAllActiveConfigs() {
|
||||
const systemPrisma = forSystem(this.prisma) as any;
|
||||
return systemPrisma.ldapConfig.findMany({
|
||||
const sysPrisma = forSystem(this.prisma) as any;
|
||||
return sysPrisma.ldapConfig.findMany({
|
||||
where: { isActive: true },
|
||||
include: { fieldMappings: true },
|
||||
});
|
||||
@@ -1052,8 +1069,8 @@ class ProbeService {
|
||||
class ProbeService {
|
||||
constructor(private readonly prisma: any) {}
|
||||
async readAll() {
|
||||
const systemPrisma = forSystem(this.prisma) as any;
|
||||
return systemPrisma.ldapConfig.findMany();
|
||||
const sysPrisma = forSystem(this.prisma) as any;
|
||||
return sysPrisma.ldapConfig.findMany();
|
||||
}
|
||||
async writeOne(tenantId: string) {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
@@ -1070,8 +1087,8 @@ class ProbeService {
|
||||
class ProbeService {
|
||||
constructor(private readonly prisma: any) {}
|
||||
async readAll() {
|
||||
const systemPrisma = forSystem(this.prisma) as any;
|
||||
return systemPrisma.ldapConfig.findMany();
|
||||
const sysPrisma = forSystem(this.prisma) as any;
|
||||
return sysPrisma.ldapConfig.findMany();
|
||||
}
|
||||
async readRaw() {
|
||||
return this.prisma.ldapConfig.findMany();
|
||||
|
||||
Reference in New Issue
Block a user