prompt inicial do projeto

This commit is contained in:
2026-07-22 15:55:55 -03:00
commit 6fb920d333
19 changed files with 2937 additions and 0 deletions

196
docs/06-LGPD-E-SEGURANCA.md Normal file
View File

@@ -0,0 +1,196 @@
# 06 — LGPD e segurança
> Este documento tem consequência jurídica real. O condomínio é controlador dos dados; a plataforma é operadora. Um erro de base legal aqui não é bug — é multa e responsabilidade civil.
> Não substitui parecer jurídico. Antes de operar comercialmente, valide com advogado especializado.
## 1. A base legal — e por que a intuição está errada
A intuição diz: "peça consentimento ao visitante". **Está errada.**
Consentimento na LGPD precisa ser **livre** (art. 5º, XII). Um visitante que só entra no prédio se aceitar ser fotografado não está consentindo livremente — está sob condição. Consentimento obtido assim é frágil e pode ser considerado inválido, derrubando toda a base de tratamento.
Além disso, o titular pode revogar o consentimento a qualquer momento (art. 8º, §5º). Um sistema de segurança cuja base legal evapora quando o visitante pede não serve como sistema de segurança.
**Base legal correta: legítimo interesse** — art. 7º, IX, para segurança patrimonial e das pessoas do condomínio. Em situações de risco à integridade física, o art. 7º, VII também sustenta.
| Dado | Base legal | Finalidade |
|---|---|---|
| Nome do visitante | Legítimo interesse (7º, IX) | Identificação de quem acessa |
| Foto do rosto | Legítimo interesse (7º, IX) | Validação visual pelo morador |
| Geolocalização | Legítimo interesse (7º, IX) | Anti-fraude: confirmar presença física na portaria |
| Documento (opcional) | Legítimo interesse (7º, IX) | Identificação em ocorrência |
| Gravação de chamada | Legítimo interesse + **aviso reforçado** | Prova em disputa (módulo opcional) |
| Dados do morador | Execução de contrato (7º, V) | Prestação do serviço |
### A LIA é obrigatória
Legítimo interesse exige **Legitimate Interest Assessment** documentada e arquivada, com três etapas:
1. **Finalidade legítima** — controle de acesso e segurança patrimonial são interesse legítimo pacífico.
2. **Necessidade** — o dado é o mínimo? Foto do rosto: sim, é como o morador valida quem está lá fora. Geolocalização: sim, é o que impede acionamento remoto fraudulento. **Documento: não é necessário** — por isso é opcional e não bloqueia o fluxo.
3. **Balanceamento** — o direito do titular prevalece? Aqui entram as salvaguardas: retenção curta, acesso restrito e auditado, sem uso secundário, sem compartilhamento, sem biometria.
Modelo de LIA em `docs/anexos/LIA-modelo.md`, a ser preenchido **por condomínio** (cada um é controlador dos seus dados).
### O que muda na prática
Não existe tela de "Aceito os termos" com checkbox. Existe **aviso de tratamento** claro, exibido antes da coleta:
> **Este acesso é registrado.** Sua imagem e localização são coletadas para segurança do condomínio, ficam guardadas por 90 dias e são acessíveis apenas ao morador que você procura e à administração. Base legal: legítimo interesse (LGPD, art. 7º, IX). [Saiba mais]
O que se registra em `privacy_notices` é a **exibição do aviso** — versão do texto, timestamp, IP, user agent. O que precisa ser provável é que a informação foi dada.
E uma placa física na portaria com o mesmo aviso, para quem entra sem usar o sistema.
## 2. Por que não há reconhecimento facial
Dado biométrico é **dado pessoal sensível** (art. 5º, II). Tratamento de dado sensível tem lista fechada de hipóteses (art. 11) e **não admite legítimo interesse**. Restaria consentimento — que, como visto, não é livre nesse contexto.
Ou seja: reconhecimento facial em portaria de visitante fica sem base legal sólida. É por isso que está fora do escopo — decisão jurídica, não limitação técnica.
**Foto ≠ biometria.** Uma foto guardada e vista por um humano é dado pessoal comum. Ela vira biométrica quando é processada para extrair template facial e identificar automaticamente. A fronteira é o processamento, não a imagem.
**Regra de engenharia:** nenhuma biblioteca de detecção ou extração facial entra no projeto, nem "só para enquadrar o rosto". A tentação aparece disfarçada de UX.
## 3. Direitos do titular
| Direito | Implementação | Prazo |
|---|---|---|
| Confirmação e acesso | `POST /admin/lgpd/export` por CPF ou telefone | 15 dias |
| Correção | Admin edita e registra em `audit_log` | 15 dias |
| Eliminação | `POST /admin/lgpd/erase` — apaga mídia, anonimiza nome | 15 dias |
| Portabilidade | Exportação em JSON | 15 dias |
| Informação sobre compartilhamento | Documentada no aviso | imediato |
| Oposição | Registrada; avaliada contra o legítimo interesse | 15 dias |
**Eliminação não apaga a linha da visita.** Apaga o dado pessoal (mídia, nome, documento) e mantém o registro anonimizado 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.
O condomínio é quem responde ao titular; a plataforma fornece a ferramenta. Isso precisa estar no contrato de operador.
## 4. Retenção
| Dado | Prazo | Fundamento |
|---|---|---|
| Foto do visitante | 90 dias | Janela típica para descoberta de ocorrência |
| Foto de pacote | 30 dias | Extravio se descobre rápido |
| Recado em vídeo | 30 dias, ou até resolvido | Finalidade se esgota |
| Gravação de chamada | 90 dias | Só com módulo ativo e aviso reforçado |
| Registro da visita (sem mídia) | 5 anos | Segurança patrimonial |
| `audit_log` | 5 anos | Prova de conformidade |
Job `MEDIA_PURGE` diário: apaga o objeto no MinIO, anula `storage_key`, **preserva a linha** em `media_assets`. Fica provado que existiu uma foto e que ela foi eliminada no prazo — que é exatamente o que se precisa demonstrar numa fiscalização.
Prazos são 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.
## 5. Modelo de ameaças
### A.1 — Enumeração de moradores (crítica)
**Ataque:** com o QR (visível na entrada, fotografável da calçada), alguém testa combinações de bloco e unidade e descobre quais existem e quem mora onde. É reconhecimento para assalto ou stalking — segurança física antes de privacidade.
**Mitigação — busca cega.** A API **nunca** revela se uma unidade existe:
- Visita criada mesmo com `unit_id` nulo, preservando `unit_input`
- Resposta idêntica em corpo, código e headers
- **Tempo de resposta constante** (delay artificial iguala os caminhos — sem isso o ataque vira timing attack)
- Nome do morador nunca aparece antes do atendimento
- Rate limit por IP e por dispositivo, com bloqueio progressivo
**Regra de implementação:** a tela do visitante nunca exibe autocomplete, sugestão ou validação de unidade. O campo é livre.
### A.2 — Acionamento remoto fraudulento
**Ataque:** foto do QR, acionamento de casa, engenharia social por vídeo ("sou da manutenção").
**Mitigação:** geofence `ST_DWithin` contra `gates.location`; fora do raio, `403 OUTSIDE_GEOFENCE`. Localização negada bloqueia o fluxo. O selo de distância aparece na tela do morador durante a chamada — `⚠ A 340m da portaria` é o sinal mais claro possível.
**Limitação assumida:** GPS é falsificável com app rooteado. A defesa é dissuasória, não absoluta; complementada por rate limit e auditoria. Um atacante determinado passa — mas a tentativa fica registrada com foto.
### A.3 — DoS social
**Ataque:** tocar em todos os apartamentos de madrugada.
**Mitigação:** `condominiums.quiet_hours` — na janela de silêncio, visitas não pré-autorizadas vão direto para operador ou recado, sem acordar moradores. Rate limit por dispositivo, bloqueio progressivo, e alerta no admin ao detectar padrão de varredura.
### A.4 — Vazamento de mídia
**Mitigação:** bucket privado, **nenhuma URL pública**; acesso só por URL assinada de 5 minutos gerada sob autenticação; todo acesso registrado em `audit_log`; criptografia em repouso; `sha256` de cada objeto como prova de integridade.
### A.5 — Adulteração de auditoria
**Ataque:** síndico envolvido em ocorrência altera ou apaga registros.
**Mitigação:** `audit_log` é append-only, com `UPDATE` e `DELETE` **revogados no banco** para o usuário da aplicação:
```sql
REVOKE UPDATE, DELETE ON audit_log FROM portaria_app;
```
Nem a aplicação comprometida altera o log. Somado ao `sha256` da mídia, isso é o que dá valor probatório ao registro.
### A.6 — Roubo de token
**Mitigação:** JWT de visitante com 15 min, escopo de uma visita, atado ao `gateId` e ao IP de origem. Refresh do morador no Keystore/Keychain com biometria de dispositivo. Rotação de refresh token e revogação por dispositivo no admin.
### A.7 — QR vazado ou clonado
**Mitigação:** `gates.qr_version` — incrementar invalida todos os QRs anteriores. Reimprime a placa e os códigos antigos param de validar. Não é rotação automática (o QR é impresso), mas é resposta a incidente.
## 6. Autenticação e autorização
| Perfil | Mecanismo | Sessão |
|---|---|---|
| Visitante | JWT efêmero pós-QR + geofence | 15 min, uma visita |
| Morador | OIDC + refresh no keystore | 15 min / 30 dias |
| Operador | OIDC + refresh | 15 min / 30 dias |
| Admin | OIDC + **MFA obrigatório** | 8h |
MFA no admin não é opcional: esse perfil vê fotos de todos os visitantes e a localização de todos os acessos. É o alvo mais valioso do sistema.
**Autorização** com Spring Security por método, sempre com `tenant_id` no predicado:
```kotlin
@PreAuthorize("@access.canViewVisit(#visitId, authentication)")
fun getVisit(visitId: UUID): VisitDto
```
Morador vê apenas visitas das suas unidades. Operador vê apenas as que estão ou estiveram na fila. Admin vê todas do seu tenant — e cada acesso a mídia gera linha de auditoria.
## 7. Segurança da aplicação
Headers no Traefik: HSTS, `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`, CSP restritiva com `frame-ancestors 'none'`.
Upload de mídia: `Content-Type` validado por **magic bytes**, não por extensão; limite de 8MB para foto e 30MB para vídeo; metadados EXIF removidos no servidor (**EXIF carrega GPS próprio, que não é o dado que queremos e não passou pelo aviso**); nome de arquivo gerado pelo servidor, nunca o do cliente.
Rate limits: sessão de visitante 5/min por IP e 20/h por dispositivo; criação de visita 3/min por sessão; login admin 5/15min com bloqueio progressivo.
Dependências: Dependabot ativo, `gradle dependencyCheck` e `pnpm audit` em CI, build falha em vulnerabilidade alta ou crítica.
## 8. Contratos e papéis
**Condomínio = controlador. Plataforma = operadora.** O contrato de operador precisa fixar: finalidades permitidas, proibição de uso secundário, prazos de retenção, obrigação de auxílio no atendimento a titulares, notificação de incidente em até 24h, e destino dos dados no encerramento.
Cada condomínio indica um **encarregado (DPO)**, cadastrado no admin e exibido no aviso de privacidade.
**Incidente de segurança:** contenção → registro → avaliação de risco → comunicação à ANPD e aos titulares em prazo razoável (a ANPD orienta 2 dias úteis) → relatório final. Runbook em `docs/anexos/runbook-incidente.md`.
## 9. Checklist de conformidade
- [ ] LIA preenchida e arquivada por condomínio
- [ ] Aviso de tratamento visível antes de qualquer coleta, com versão registrada
- [ ] Placa física na portaria
- [ ] Encarregado indicado e publicado
- [ ] Retenção configurada e job de expurgo rodando
- [ ] Exportação e eliminação testadas ponta a ponta
- [ ] `audit_log` com `UPDATE`/`DELETE` revogados no banco
- [ ] Nenhuma URL pública de mídia
- [ ] Nenhuma biblioteca de reconhecimento facial no `build.gradle.kts` ou no `package.json`
- [ ] Busca cega verificada — inclusive tempo de resposta constante
- [ ] Contrato de operador assinado
- [ ] Runbook de incidente testado
## 10. Referências
- [Insoft4 — controle de visitantes sob a LGPD](https://www.insoft4.com.br/blog/controle-de-acesso-dos-visitantes-de-acordo-com-a-lgpd)
- [ConJur — reconhecimento facial em condomínios](https://www.conjur.com.br/2024-abr-07/reconhecimento-facial-em-condominios-desafios-sob-a-otica-da-lgpd/)
- [ConJur — LGPD e condomínios](https://www.conjur.com.br/2022-dez-17/william-rocha-lgpd-condominios/)