Files
Projeto-Portaria/prompts/FASE-8-planos-e-lgpd.md
2026-07-22 15:55:55 -03:00

127 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FASE 8 — Planos, módulos, LGPD e observabilidade
## Objetivo
Fechar o que torna o produto operável e vendável: módulos ligáveis por tenant, canal de WhatsApp preparado (interface, não integração), retenção e expurgo automáticos, direitos do titular, e os SLOs medidos de verdade.
## Pré-requisitos
FASES 07 concluídas. Ler `docs/06-LGPD-E-SEGURANCA.md` §3 e §4, e `docs/05-INFRA-DOCKER.md` §6.
## Tarefas
### 1. Canais de notificação plugáveis
```kotlin
interface NotificationChannel {
val key: FeatureKey? // null = sempre ativo
suspend fun notify(alvo: NotificationTarget, evento: NotificationEvent): Result<Unit>
}
```
`PushChannel` (FCM + APNs) sempre ativo. `WebSocketChannel` sempre ativo.
`NotificationDispatcher` resolve os canais habilitados para o tenant e despacha **em paralelo**, tolerando falha individual — um canal fora do ar não pode impedir os demais.
### 2. WhatsApp — interface e flag, sem integração
O WhatsApp é **módulo pago opcional**; o app é o notificador principal. Nesta fase entrega-se apenas:
- `WhatsAppChannel` com `key = FeatureKey.WHATSAPP_NOTIFICATIONS`, implementação **stub** que registra o que seria enviado
- Toggle no painel admin, com o efeito descrito em uma frase
- Estrutura de templates prevista
- Documentação em `docs/anexos/whatsapp-v2.md` com o que falta: WABA verificada, templates `utility` aprovados, custo (~US$0,004/msg no Brasil, grátis dentro da janela de 24h)
**Não integre com a Meta agora.** Verificação de negócio e aprovação de template levam dias e bloqueariam o lançamento. E registre no documento a limitação de fundo: a latência do WhatsApp não serve para *tocar* uma chamada — ele é aviso paralelo com deep link, nunca o canal primário.
### 3. Feature flags
```kotlin
@Service
class FeatureService {
fun habilitado(tenantId: UUID, key: FeatureKey): Boolean
fun dentroDaQuota(tenantId: UUID, key: FeatureKey, uso: Int): Boolean
}
```
Cache curto (60s) com invalidação ao alterar. Toda mudança de flag vai para `audit_log` com autor.
Quotas relevantes: minutos de vídeo por mês, gravações armazenadas, operadores simultâneos.
### 4. Gravação de chamada
Módulo `video_recording`. LiveKit Egress grava para o MinIO ao entrar em `EM_CHAMADA`, se habilitado.
**Aviso reforçado obrigatório:** ao gravar, o visitante vê aviso explícito antes do início, e a versão desse aviso é registrada. Gravar sem avisar é violação direta.
Retenção de 90 dias. Cada gravação soma banda no SFU — ative com quota.
### 5. Retenção e expurgo
Job diário `MEDIA_PURGE`:
1. Seleciona `media_assets` com `expires_at < now()` e `storage_key IS NOT NULL`
2. Apaga o objeto no MinIO
3. `UPDATE media_assets SET storage_key = NULL, purged_at = now()`
4. **Preserva a linha**
O passo 4 é o ponto: fica provado que existiu uma foto e que ela foi eliminada no prazo — exatamente o que se demonstra numa fiscalização.
Prazos configuráveis por tenant, com **teto** definido pela plataforma. Um condomínio querendo guardar foto por 5 anos configuraria um risco que a plataforma não aceita hospedar.
Job diário de limpeza de `idempotency_keys` vencidas.
### 6. Direitos do titular
`POST /admin/lgpd/export` — busca por CPF ou telefone, devolve JSON com todas as visitas, mídias (URLs assinadas) e registros de aviso.
`POST /admin/lgpd/erase` — apaga mídia, anonimiza `visitor_name` para `[REMOVIDO]`, limpa documento e telefone, **preserva a linha da visita** com data, unidade e resultado. Justificativa: obrigação de guarda de registro de acesso para segurança patrimonial. A linha vira estatística, não identificação.
Ambas registram em `audit_log` e devolvem comprovante em PDF — o condomínio precisa provar que atendeu no prazo de 15 dias.
### 7. Versionamento do aviso de privacidade
Editor no admin. Alterar o texto **cria nova versão**; as visitas antigas continuam apontando para a versão que foi realmente exibida. Sem isso, não há como provar o que o visitante leu naquele dia.
### 8. SLOs medidos
Instrumentar as métricas de `01-ARQUITETURA.md` §5.7:
```
portaria.visit.ring_latency QR → push entregue no dispositivo
portaria.visit.answered_ratio atendidas pelo morador / total
portaria.delivery.resolution_latency QR → resolvida
portaria.delivery.abandoned_ratio canceladas ou expiradas
portaria.entry_flow.availability caminho crítico
```
`ring_latency` mede até a **entrega** do push, não até o envio. A diferença entre os dois é justamente onde a falha acontece.
Dashboards e alertas conforme `05-INFRA-DOCKER.md` §6, incluindo os dois alertas de negócio (taxa de atendimento baixa e tokens mortos) que viram tarefa de customer success, não plantão.
### 9. Runbooks
`docs/anexos/runbook-incidente.md` — vazamento, indisponibilidade, perda de dados; com prazos ANPD.
`docs/anexos/runbook-operacao.md` — restore testado, rotação de segredo, invalidação de QR, adição de condomínio.
`docs/anexos/LIA-modelo.md` — modelo de Legitimate Interest Assessment para preenchimento por condomínio.
## Critérios de aceite
- [ ] Dispatcher despacha em paralelo e tolera falha de um canal
- [ ] `WhatsAppChannel` desligado não é invocado; ligado, registra o que enviaria
- [ ] Toggle de módulo tem efeito imediato e fica em `audit_log`
- [ ] Gravação só ocorre com módulo ativo e aviso reforçado exibido
- [ ] `MEDIA_PURGE` apaga o objeto e preserva a linha
- [ ] Exportação LGPD devolve todos os dados de um titular
- [ ] Eliminação anonimiza e preserva a linha da visita
- [ ] Alterar o aviso cria versão; visitas antigas mantêm a original
- [ ] Todos os SLOs visíveis no Grafana com dados reais
- [ ] Alertas disparam em condição simulada
- [ ] Restore de backup testado e cronometrado
## Não faça nesta fase
- Integração real com a Meta (v2)
- Billing automatizado (v2)
- Ativar multi-tenancy