feat(PROJ-51): Aufbewahrungsfristen nach Dokumentenart (Retention-Kategorien)
Fuehrt archiving_rules ein (PROJ-43-Basis: Tabelle + CRUD-API + Admin-UI) und erweitert die Retention-Logik (PROJ-34) um Regel-basierte Fristen, eine globale Mindestfrist (min_retention_days) sowie Nachvollziehbarkeit der Frist-Quelle (retain_until_source) in API und Mail-Detailansicht.
This commit is contained in:
@@ -70,6 +70,7 @@ import { CertTab } from "@/components/admin/tabs/CertTab";
|
||||
import { ModulesTab } from "@/components/admin/ModulesTab";
|
||||
import { IMAPSettingsTab } from "@/components/admin/tabs/IMAPSettingsTab";
|
||||
import { RetentionTab } from "@/components/admin/tabs/RetentionTab";
|
||||
import { ArchivingRulesTab } from "@/components/admin/tabs/ArchivingRulesTab";
|
||||
import { QuotaTab } from "@/components/admin/tabs/QuotaTab";
|
||||
import { SMTPOutTab } from "@/components/admin/tabs/SMTPOutTab";
|
||||
import { ResetPasswordDialog, DeleteUserDialog } from "@/components/admin/UserDialogs";
|
||||
@@ -712,6 +713,7 @@ export default function AdminPage() {
|
||||
{isSuperAdmin && <TabsTrigger value="cert" onClick={loadCert}>Zertifikat</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="tenants" onClick={loadTenants}>Mandanten</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="retention">Retention</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="archiving-rules">Regeln</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="quotas">Quotas</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="smtp-out">SMTP-Out</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="modules">Module</TabsTrigger>}
|
||||
@@ -975,6 +977,11 @@ export default function AdminPage() {
|
||||
<RetentionTab />
|
||||
</TabsContent>
|
||||
)}
|
||||
{isSuperAdmin && (
|
||||
<TabsContent value="archiving-rules">
|
||||
<ArchivingRulesTab />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
{isSuperAdmin && (
|
||||
<TabsContent value="smtp-out">
|
||||
|
||||
@@ -46,6 +46,23 @@ function formatDate(iso: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
// PROJ-51: human-readable label for the retain_until_source marker.
|
||||
function retentionSourceLabel(source: string): string {
|
||||
if (source.startsWith("rule:")) {
|
||||
return `Archivierungsregel #${source.slice(5)}`;
|
||||
}
|
||||
switch (source) {
|
||||
case "tenant_default":
|
||||
return "Mandanten-Standard";
|
||||
case "global_default":
|
||||
return "Globaler Standard";
|
||||
case "min_retention":
|
||||
return "Globale Mindestfrist";
|
||||
default:
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
function triggerDownload(blob: Blob, filename: string) {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
@@ -115,6 +132,20 @@ function MailHeaderGrid({ mail }: { mail: MailDetail }) {
|
||||
)}
|
||||
<OcrBadge status={mail.ocr_status} />
|
||||
</span>
|
||||
{/* PROJ-51: retention lock + source for auditor traceability */}
|
||||
{mail.retain_until && (
|
||||
<>
|
||||
<span className="font-medium text-muted-foreground">Aufbewahrung:</span>
|
||||
<span className="flex flex-wrap items-center gap-2 text-sm">
|
||||
<span>bis {formatDate(mail.retain_until)}</span>
|
||||
{mail.retain_until_source && (
|
||||
<Badge variant="secondary">
|
||||
{retentionSourceLabel(mail.retain_until_source)}
|
||||
</Badge>
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user