feat(17-01): move TenderEmailConfig ownership from tenant to user
Alert-Postfach gehoert jetzt dem einzelnen Nutzer (userId @unique) statt
dem Mandanten (D-01) — ein zweiter Kollege desselben Mandanten kann sein
eigenes Postfach anbinden. tenantId bleibt denormalisiert (SMTP-Aufloesung,
Herkunftsmarkierung), wird auf create UND update mitgeschrieben.
- Handgeschriebene Migration (prisma migrate dev verweigert die
nicht-interaktive Shell): befuellt Bestandszeilen mit dem aeltesten
aktiven Administrator ihres Mandanten, entfernt verwaiste Zeilen ohne
Administrator, ersetzt die tenantId-Eindeutigkeit durch userId.
Lokal getestet (0 Bestandszeilen lokal und auf alpha — Zaehlung im
Task-1-Checkpoint), Index-Ergebnis verifiziert.
- TenderEmailConfigService.getConfigForApi/saveConfig auf userId als
Schluessel umgestellt; saveConfig nimmt {userId, tenantId}.
- TendersController: email-config-Routen von @Roles(ADMIN,SUPER_ADMIN)
auf @UseModule('tender-radar') umgestellt (Postfach ist jetzt
Nutzereinstellung); Route-Reihenfolge vor @Get(':id') unveraendert.
- Neue Seite /modules/tender-radar/my-sources ("Meine Quellen") mit dem
unveraenderten EmailAlertConfigForm; Hinweistext benennt D-05 (Tender
bleibt plattform-global — nur wer Quellen einspeist aendert sich).
- tenders.controller.spec.ts an neue Service-Signatur angepasst (Rule 3,
nicht im Plan gelistet, aber zum Kompilieren/Bestehen erforderlich).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
'use client';
|
||||
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { EmailAlertConfigForm } from '../settings/components/EmailAlertConfigForm';
|
||||
|
||||
/**
|
||||
* "Meine Quellen" — the per-user Ausschreibungs-Radar module page (Phase
|
||||
* 17, Plan 01, D-01/D-05).
|
||||
*
|
||||
* Until this plan, the alert mailbox lived on the admin-only
|
||||
* `/modules/tender-radar/settings` page, one config per TENANT — a second
|
||||
* colleague with their own portal account could not connect their own
|
||||
* inbox. Phase 17 moves ownership to the USER (TenderEmailConfig.userId).
|
||||
* This page is where every user with module access manages their own
|
||||
* mailbox, reusing the existing `EmailAlertConfigForm` UNCHANGED — it
|
||||
* already talks to the same `GET`/`PUT /modules/tender-radar/email-config`
|
||||
* endpoints, which now resolve ownership by userId instead of tenantId
|
||||
* (TendersController.getEmailConfig/saveEmailConfig).
|
||||
*
|
||||
* Deliberately a SEPARATE page from `/settings` (D-01 open point 4), not a
|
||||
* new section on `/settings/general`: module-specific settings stay with
|
||||
* the module rather than accumulating on a generic account page as more
|
||||
* modules adopt the same per-user pattern (DKV-Fleet, future modules).
|
||||
*
|
||||
* D-05 (harte Grenze): `Tender` stays platform-global — connecting a
|
||||
* mailbox here only changes WHO feeds sources in, not WHO sees hits. The
|
||||
* intro text below says so explicitly, so nobody is surprised that a
|
||||
* colleague's inbox produces results everyone at the tenant can see.
|
||||
*
|
||||
* No module-loader whitelist change needed — nested route under the
|
||||
* already-whitelisted `tender-radar` module page (same reasoning as
|
||||
* `/settings`, Plan 10-02).
|
||||
*/
|
||||
export default function TenderRadarMySourcesPage() {
|
||||
const t = useTranslations('tenderRadar');
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-2xl p-6">
|
||||
<h1 className="text-2xl font-semibold tracking-tight mb-2">
|
||||
{t('mySources.title')}
|
||||
</h1>
|
||||
<p className="mb-6 text-sm text-muted-foreground">
|
||||
{t('mySources.intro')}
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-foreground mb-4">
|
||||
{t('mySources.mailboxSectionTitle')}
|
||||
</h2>
|
||||
<EmailAlertConfigForm />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -933,6 +933,11 @@
|
||||
"save": "Speichern",
|
||||
"saveSuccess": "Einstellungen gespeichert.",
|
||||
"errorSave": "Einstellungen konnten nicht gespeichert werden"
|
||||
},
|
||||
"mySources": {
|
||||
"title": "Meine Quellen",
|
||||
"intro": "Ausschreibungen, die aus Ihrem Postfach hereinkommen, erscheinen danach in der Trefferliste aller Kolleginnen und Kollegen Ihres Mandanten — es gibt keine getrennte Sichtbarkeit je Postfach.",
|
||||
"mailboxSectionTitle": "Mein Postfach"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,6 +933,11 @@
|
||||
"save": "Save",
|
||||
"saveSuccess": "Settings saved.",
|
||||
"errorSave": "Could not save settings"
|
||||
},
|
||||
"mySources": {
|
||||
"title": "My sources",
|
||||
"intro": "Tenders that arrive through your mailbox will then appear in the results list for every colleague at your organization — there is no separate visibility per mailbox.",
|
||||
"mailboxSectionTitle": "My mailbox"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user