prompt inicial do projeto
This commit is contained in:
126
prompts/FASE-8-planos-e-lgpd.md
Normal file
126
prompts/FASE-8-planos-e-lgpd.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 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 0–7 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
|
||||
Reference in New Issue
Block a user