['rate_limit_attempts', 'created_at < DATE_SUB(NOW(), INTERVAL 23 HOUR)'], // Taeglicher/stuendlicher Lauf mit einer Tagesreserve: hoechstens 180 Tage. 'audit_log' => ['audit_log', 'created_at < DATE_SUB(NOW(), INTERVAL 179 DAY)'], 'outbound_emails' => ['outbound_emails', 'created_at < DATE_SUB(NOW(), INTERVAL 179 DAY)'], 'auth_tokens' => ['user_auth_tokens', 'expires_at < NOW() OR consumed_at < DATE_SUB(NOW(), INTERVAL 1 DAY)'], 'stripe_webhook_events' => ['stripe_webhook_events', 'processed_at < DATE_SUB(NOW(), INTERVAL 2 YEAR)'], // Allgemeine Verjährung: erst nach drei vollständig abgelaufenen // Kalenderjahren. Offene Fälle und Nachweise aktiver Verträge bleiben. 'processed_legal_requests' => ['legal_requests', "status = 'processed' AND received_at < MAKEDATE(YEAR(CURDATE()) - 3, 1)"], 'detached_legal_acceptances' => ['legal_acceptances', 'tenant_id IS NULL AND accepted_at < MAKEDATE(YEAR(CURDATE()) - 3, 1)'], ]; $failed = false; foreach ($rules as $label => [$table, $where]) { try { if ($dryRun) { $count = (int)$pdo->query("SELECT COUNT(*) FROM {$table} WHERE {$where}")->fetchColumn(); echo "{$label}: {$count} würde(n) gelöscht\n"; continue; } $count = $pdo->exec("DELETE FROM {$table} WHERE {$where}"); echo "{$label}: " . (int)$count . " gelöscht\n"; } catch (Throwable $e) { $failed = true; echo "ERROR {$label}: {$e->getMessage()}\n"; } } exit($failed ? 1 : 0);