Garbage Collector — model napříč typy dat¶
Status: v0.1 (rozšířeno 2026-05-14 pro sync dirs) Související:
sync-backup.md,s3backup.md,auth-organization.md
1. Cíl¶
Sjednotit mazání S3 dat napříč AVAX komponentami pomocí jediného mechanismu — storage_deletion_requests s grace period + Celery GC worker. Žádné komponenty by neměly mazat ze S3 přímo — vše jde přes deletion request flow.
2. Důvody (proč grace period a ne direct delete)¶
- Anti-rage-delete — uživatel odebere adresář v afektu → 30 dní si to může rozmyslet.
- Forensika / audit — kdo, co, kdy odstranil.
storage_deletion_requestsrow je důkaz. - Recovery — super_admin nebo cancel mechanismus může operaci zvrátit do
delete_afterdeadline. - Bulk consistency — když uživatel maže 10 souborů, je atomická 1 request, ne 10 race-condition operations.
3. Datový model — storage_deletion_requests¶
| Sloupec | Typ | Význam |
|---|---|---|
id |
UUID | PK |
company_id |
UUID FK | Pro filtr / multi-tenant |
requested_by |
UUID FK | Kdo iniciátor (může být system user pro auto-clean) |
approved_by |
UUID FK NULL | Schvalovatel (NULL pro auto-approved) |
status |
VARCHAR(30) | pending_approval / approved / rejected / cancelled / completed |
approve_deadline |
TIMESTAMP NULL | Pro pending_approval — kdy expiruje (defaultně +14d) |
delete_after |
TIMESTAMP NULL | Pro approved — kdy GC smaže (defaultně approved+30d) |
reason |
TEXT NULL | Lidský popis |
file_count |
INT NULL | Pro UI feedback |
total_bytes |
BIGINT NULL | Pro storage usage tracking |
s3_keys |
JSONB NULL | Seznam explicitních S3 klíčů — pro malé deletion (do 100 souborů) |
s3_prefix |
VARCHAR(512) NULL | NOVĚ: Alternativa k s3_keys pro velké adresáře — GC paginate-deletes pod prefixem |
source |
VARCHAR(30) | NOVĚ: Typ deletion: user_request / sync_dir_remove / app_uninstall / chat_export / gdpr_anonymize / ... |
created_at |
TIMESTAMP | |
completed_at |
TIMESTAMP NULL |
Migrace 019 — přidává s3_prefix + source. Existující řádky dostávají source='user_request' (default).
4. Flow per source type¶
4.1 user_request (explicitní žádost o smazání — současné)¶
POST /storage/deletion-requests {s3_keys, reason}
→ status: pending_approval, file_count: len(s3_keys)
→ notifikace company_adminovi
POST /storage/deletion-requests/{id}/approve (admin)
→ status: approved, delete_after: now + 30d
GC v 02:00:
→ vybere approved s delete_after <= now
→ smaže jednotlivé s3_keys
→ status: completed
4.2 sync_dir_remove (uživatel odebírá vlastní sync adresář — NOVĚ)¶
DELETE /storage/sync-dirs/{id}
V services/devices.py:remove_sync_dir:
→ načti entry.s3_prefix
→ IF entry.share_id is None (vlastní dir, ne subscribed):
create StorageDeletionRequest(
status='approved', ← auto-approve, žádný admin nutný
source='sync_dir_remove',
s3_prefix=entry.s3_prefix,
delete_after=now + 30d,
requested_by=user.id,
approved_by=user.id, ← uživatel implicitně schválil
)
→ IF entry.share_id is not None (subscribed):
skip deletion request — cizí source data zůstávají!
→ db.delete(entry); commit
GC v 02:00 (stejný worker):
→ vybere approved s delete_after <= now
→ IF s3_prefix: list_objects_v2 paginate + delete_objects batch (max 1000/batch)
→ IF s3_keys: stará cesta — per-key delete
→ status: completed
Důležité: Uživatel nemusí čekat na approval (sám se rozhodl). Ale fyzický delete čeká 30 dní → recovery možný přes POST /storage/deletion-requests/{id}/cancel.
4.3 app_uninstall (budoucnost)¶
Když firma odhlásí předplatné nebo uživatel smaže AVAX app:
- S3 prefix companies/{cid}/apps/{slug}/
- Auto-approve, 30d grace
- Notifikace ownerovi
4.4 chat_export (budoucnost)¶
Po manuálním exportu chat konverzace:
- S3 prefix companies/{cid}/chat/exported/{conv_id}/
- Auto-approve, 7d grace (kratší — export je dobrovolný)
4.5 gdpr_anonymize (budoucnost)¶
Anonymizace uživatele: - Všechny S3 prefixy patřící uživateli - Auto-approve, 0d grace (GDPR požaduje okamžitě) - Status='approved' + delete_after=now
5. GC worker — gc.delete_expired¶
Celery beat schedule: každou noc 02:00. Manual trigger: POST /admin/storage/gc/run.
Pseudo-code:
async def run_gc(db):
expired = SELECT * FROM storage_deletion_requests
WHERE status='approved' AND delete_after <= now()
for req in expired:
if req.s3_prefix:
# Paginated prefix delete
for batch in list_objects_v2_paginator(prefix=req.s3_prefix, max=1000):
delete_objects(batch)
else:
# Legacy explicit keys
for key in req.s3_keys:
delete_object(key)
req.status = 'completed'
req.completed_at = now()
Retry: při failure jednotlivého klíče/objektu se uloží do s3_keys nebo zachová s3_prefix (s update file_count na zbývající) a GC zkusí znovu příští noc.
6. Cancel flow¶
POST /storage/deletion-requests/{id}/cancel — povolen pro:
- requester (do delete_after)
- company_admin / super_admin (kdykoli před completed)
Cancel u sync_dir_remove ale nevrací sync_dir řádek do device_sync_dirs — ten byl už smazán z DB. Uživatel může:
- Vytvořit nový sync_dir se stejným local_path
- Backup data jsou stále na S3 → můžou si je obnovit pomocí Full Restore flow
7. Pravidla pro nové komponenty¶
Pokud nová komponenta píše do S3 a může to chtít smazat:
- Nikdy
delete_objectpřímo — vždy přesservices/deletion.py:create_deletion_request - Pokud user-initiated →
status='pending_approval'(čeká schválení admin) - Pokud system-initiated (auto-clean, uninstall) →
status='approved', vyplnitapproved_by=system_user_id - Pro velké S3 adresáře (>100 souborů) použít
s3_prefix, nes3_keys - Nastavit
sourcena nový identifikátor pro tracking / metrics
8. Otevřené otázky¶
- Notification ownera při auto-approved sync_dir_remove — pošleme e-mail "soubor budou smazány za 30 dní"? Riziko spamu pokud user často edituje sync dirs.
- S3 bucket versioning interakce — bucket
claudeaimá versioning Enabled.delete_objectvytvoří delete marker, soubory zůstávají versionované. Pro skutečné mazání je nutnýdelete_objects VersionId nebo lifecycle pravidlo. TODO: ověřit chování + případně přidat list_object_versions + per-version delete v GC. - Per-company storage usage —
total_bytesv deletion request nese info o tom co bude smazáno. Mělo by se to započítávat dostorage_usageview: "approved deletes pending" = nevykazují se do current usage ale do reserved-for-deletion? - Audit log entry — každá deletion request creation → audit_log row? Asi ano pro security.
9. Migration checklist¶
- Migrace 019:
s3_prefix,sourcecolumns -
remove_sync_dirvservices/devices.pyvytvoří auto-approved request -
run_gcumís3_prefix(paginated delete) - UI: BackupScreen ukazuje pending deletion requests + cancel button
- UI: confirmation dialog při DELETE sync-dir s textem o 30denní grace
- Reuse pro
app_uninstall(až bude flow) - Reuse pro
gdpr_anonymize(až bude flow)