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

5.9 KiB
Raw Permalink Blame History

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

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

@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