# Fase 9 — Proteção + retenção/reciclagem

**Status:** concluída neste ambiente de desenvolvimento  
**Data:** 2026-08-19  
**URL:** https://vms.restor.app.br/protegidas · https://vms.restor.app.br/disks  
**Serviço:** `ipcam-retention.service`

## Contexto de desenvolvimento

Ainda **não há câmeras reais** nem HDD físico. Discos = pastas locais.  
A política de idade está **desligada** (`IPCAM_RETENTION_DAYS=0`) para não apagar o clipe de demo. Reciclagem por espaço só dispara no limiar do disco (ou com cota simulada `quota_bytes` / `--bytes` no artisan).

## Princípio

Reciclagem **nunca** apaga:

- segmentos cobertos por um intervalo protegido
- arquivos com **export lock** (job queued/running)
- segmentos abertos (`ended_at` nulo — FFmpeg ainda gravando)

Remove só o necessário, do mais antigo para o mais novo, com evento em `storage_events`. Sem reencode. O worker é **systemd separado** — restart do painel não interrompe o Recorder e não é o Retention quem grava.

**Retenção atual** no dashboard = idade da gravação ativa mais antiga (cobertura real), não um número de política.

## O que foi entregue

- `protection_ranges` + flag `recordings.protected` (recalculado ao proteger/desproteger)
- UI: proteger intervalo no player; lista `/protegidas`; auditor vê, não altera
- `Recycler` + `php artisan ipcam:retention --once|--dry-run|--bytes=`
- `ipcam-retention` (www-data)
- Dashboard de armazenamento: capacidade/uso/livre, dias reais, câmeras gravando, câmeras com arquivo, protegidas, política de idade
- Cota opcional `quota_bytes` (lab: simular disco cheio no mesmo filesystem)

## Aceite

| Critério | Resultado |
|---|---|
| Protegida não é reciclada | OK |
| Export lock não é reciclado | OK |
| Segmento aberto não é reciclado | OK |
| Mais antigo elegível sai primeiro | OK |
| Dry-run não apaga | OK |
| Tela de discos com dias reais | OK |
| UI sem `relative_path` | OK |
| Sem `if fabricante` | OK |

## Fora desta fase

Eventos ONVIF na timeline (Fase 10 — concluída), carga 60 câmeras (Fase 11), PoC reencode (Fase 12 — **NO-GO** neste lab), cutover produção.
