package jobs import ( "context" "time" "github.com/hibiken/asynq" "github.com/rs/zerolog/log" "github.com/treytartt/honeydue-api/internal/models" "github.com/treytartt/honeydue-api/internal/repositories" ) // Data-retention cleanup job types. Registered as periodic crons in // cmd/worker/main.go. These keep transient/log tables from growing unbounded; // none touch user-facing data that the app reads back. const ( TypeNotificationCleanup = "maintenance:notification_cleanup" TypeWebhookLogCleanup = "maintenance:webhook_log_cleanup" TypeAuditLogCleanup = "maintenance:audit_log_cleanup" ) // Retention windows (days). const ( notificationRetentionDays = 90 webhookLogRetentionDays = 180 auditLogRetentionDays = 365 // keep 1 year of security events ) // HandleNotificationCleanup deletes notification rows older than the retention // window. Notifications are delivery records (push/digest history); 90 days is // ample for any in-app history a client might show. func (h *Handler) HandleNotificationCleanup(ctx context.Context, _ *asynq.Task) error { cutoff := time.Now().UTC().AddDate(0, 0, -notificationRetentionDays) res := h.db.WithContext(ctx).Where("created_at < ?", cutoff).Delete(&models.Notification{}) if res.Error != nil { log.Error().Err(res.Error).Msg("notification cleanup failed") return res.Error } log.Info().Int64("deleted", res.RowsAffected).Int("retention_days", notificationRetentionDays).Msg("notification cleanup completed") return nil } // HandleWebhookLogCleanup prunes the webhook dedup log. Rows only matter for the // window in which a provider (Apple/Google) might redeliver an event; 180 days // is a generous safety margin past any real redelivery. func (h *Handler) HandleWebhookLogCleanup(ctx context.Context, _ *asynq.Task) error { cutoff := time.Now().UTC().AddDate(0, 0, -webhookLogRetentionDays) res := h.db.WithContext(ctx).Where("processed_at < ?", cutoff).Delete(&repositories.WebhookEvent{}) if res.Error != nil { log.Error().Err(res.Error).Msg("webhook log cleanup failed") return res.Error } log.Info().Int64("deleted", res.RowsAffected).Int("retention_days", webhookLogRetentionDays).Msg("webhook log cleanup completed") return nil } // HandleAuditLogCleanup prunes audit events older than the retention window. // One year of security events is retained for compliance/forensics. func (h *Handler) HandleAuditLogCleanup(ctx context.Context, _ *asynq.Task) error { cutoff := time.Now().UTC().AddDate(0, 0, -auditLogRetentionDays) res := h.db.WithContext(ctx).Where("created_at < ?", cutoff).Delete(&models.AuditLog{}) if res.Error != nil { log.Error().Err(res.Error).Msg("audit log cleanup failed") return res.Error } log.Info().Int64("deleted", res.RowsAffected).Int("retention_days", auditLogRetentionDays).Msg("audit log cleanup completed") return nil }