Files
Holzleitner---Backend--aktu…/crates/application/src/ports/signature_storage.rs
Dennis Nemec 47eb8ec57d feat(signature): Signaturen beim Report-Upload behalten + Cron-Cleanup nach Frist
Bisher loeschte die Report-Pipeline die Unterschriften nach erfolgreichem
DOCUframe-Upload. Wir brauchen die Signatur-Dateien aber weiterhin, daher:

- ProcessDeliveryReportUseCase: Signatur-Loeschung (delete_for_delivery) aus dem
  Cleanup entfernt + SignatureStorage-Dependency raus (Report-PDF/Bild-Notiz-
  Cleanup bleibt).
- SignatureStorage: neue Methode delete_older_than(max_age) -> Anzahl; lokaler
  Adapter loescht PNGs aelter als die Frist (per mtime).
- Config [signature]: retention_days (Default 90, 0 = aus) + cleanup_cron
  (Default taeglich 04:00).
- main.rs: Signatur-Cleanup-Scheduler (gated retention_days > 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 16:16:12 +02:00

63 lines
2.4 KiB
Rust

//! Port für den Unterschriften-Speicher.
//!
//! Im Gegensatz zu Notiz-Bildern (die nach DOCUframe gehen) liegen
//! Unterschriften bewusst **lokal im Backend-Server** — ein einfacher
//! Datei-Speicher reicht, und die Daten verlassen die Maschine nicht.
//!
//! Die konkrete Impl (lokales Dateisystem) lebt in
//! `holzleitner-infrastructure`. Der Use Case erhält eine relative
//! Referenz zurück, die in `delivery_completions` persistiert wird.
use std::time::Duration;
use async_trait::async_trait;
use uuid::Uuid;
use crate::error::ApplicationError;
/// Wer hat unterschrieben — bestimmt den Dateinamen.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SignatureRole {
Customer,
Driver,
}
impl SignatureRole {
pub fn as_str(self) -> &'static str {
match self {
SignatureRole::Customer => "customer",
SignatureRole::Driver => "driver",
}
}
}
#[async_trait]
pub trait SignatureStorage: Send + Sync {
/// Speichert eine Unterschrift (PNG-Bytes) für eine Lieferung+Rolle und
/// liefert die persistente, relative Referenz (Dateiname) zurück.
/// Deterministisch über `delivery_id`+`role` — ein Retry überschreibt
/// dieselbe Datei statt Müll anzuhäufen.
async fn save(
&self,
delivery_id: Uuid,
role: SignatureRole,
bytes: Vec<u8>,
) -> Result<String, ApplicationError>;
/// Lädt die gespeicherten PNG-Bytes einer Unterschrift über ihre relative
/// Referenz (Dateiname, wie von [`save`](Self::save) geliefert) — fürs
/// Einbetten in den PDF-Report. `None`, wenn die Datei fehlt.
async fn load(&self, reference: &str) -> Result<Option<Vec<u8>>, ApplicationError>;
/// Löscht beide Unterschriften (Kunde + Fahrer) einer Lieferung. Idempotent
/// (fehlende Datei = ok). Hinweis: Wird NICHT mehr beim Report-Upload
/// aufgerufen — Unterschriften bleiben erhalten und werden per Cron über
/// [`delete_older_than`](Self::delete_older_than) nach Frist entfernt.
async fn delete_for_delivery(&self, delivery_id: Uuid) -> Result<(), ApplicationError>;
/// Löscht alle Unterschrifts-Dateien, deren letzte Änderung länger als
/// `max_age` zurückliegt (Aufbewahrungsfrist). Für den periodischen
/// Cron-Cleanup. Liefert die Anzahl gelöschter Dateien.
async fn delete_older_than(&self, max_age: Duration) -> Result<u64, ApplicationError>;
}