prompt inicial do projeto completo
This commit is contained in:
@@ -40,7 +40,7 @@ Um controller `GET /api/v1/health` devolvendo `{"status":"UP"}`, só para provar
|
||||
|
||||
### 6. `infra/`
|
||||
|
||||
`docker-compose.yml` exatamente como em `docs/05-INFRA-DOCKER.md` §2, mais `docker-compose.observability.yml` e `.env.example`. Configs em `livekit/livekit.yaml`, `traefik/`, `postgres/init/01-extensions.sql` (`CREATE EXTENSION postgis; CREATE EXTENSION pgcrypto;`).
|
||||
`docker-compose.yml` exatamente como em `docs/05-INFRA-DOCKER.md` §2, mais `docker-compose.observability.yml` e `.env.example`. Configs em `livekit/livekit.yaml`, `traefik/`, `postgres/init/01-extensions.sql` (`CREATE EXTENSION postgis; CREATE EXTENSION pgcrypto;`) e `postgres/init/02-roles.sh` (cria o papel `portaria_app`, sem ownership, com a senha de `POSTGRES_APP_PASSWORD` — ver `02-MODELO-DE-DADOS.md` §8).
|
||||
|
||||
### 7. CI — GitHub Actions
|
||||
|
||||
|
||||
@@ -73,7 +73,9 @@ Filtro/interceptor que lê `Idempotency-Key`, consulta `idempotency_keys`, e:
|
||||
|
||||
Spring Security com três cadeias de filtro conforme `06-LGPD-E-SEGURANCA.md` §6: `/api/v1/visitor/**` (JWT efêmero), `/api/v1/app/**` (OIDC), `/api/v1/admin/**` (OIDC + MFA).
|
||||
|
||||
Emissão e validação do JWT de visitante: 15 min, escopo de uma visita, atado a `gateId` e IP.
|
||||
Emissão e validação do JWT de visitante: 15 min, escopo de uma visita, atado a `gateId` e à sessão — **não ao IP**: IP de celular muda no meio da sessão (CGNAT, troca de torre) e derrubaria visitante legítimo.
|
||||
|
||||
**Conexões ao banco:** Flyway como `portaria` (dono), aplicação como `portaria_app` — sem essa separação, o revoke do `audit_log` e a RLS futura são decorativos (dono ignora ambos). Ver `02-MODELO-DE-DADOS.md` §8.
|
||||
|
||||
### 8. Auditoria
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ Localização ausente ou negada → `403 LOCATION_REQUIRED`. Fora do raio → `4
|
||||
- Resolve `unit_id` a partir de bloco + unidade; **se não existir, cria a visita com `unit_id = NULL`** e preserva `unit_input`
|
||||
- Resposta **idêntica** — mesmo corpo, mesmo status, mesmos headers — nos dois casos
|
||||
- **Tempo de resposta constante:** meça o caminho mais lento e aplique delay artificial no mais rápido. Sem isso o ataque vira timing attack e a busca cega não serve para nada
|
||||
- **Visita-sombra:** com `unit_id` NULL — ou unidade sem nenhum dispositivo ativo — os jobs percorrem a **mesma linha do tempo de estados**, nos mesmos tempos, sem notificar ninguém; com `operator_queue` ativo, entra na fila marcada "unidade não cadastrada" (`03-FLUXOS-E-CONTRATOS.md` §2). Sem isso, a sequência de estados no WebSocket entrega o que o tempo constante escondeu
|
||||
- Nome de morador nunca aparece na resposta
|
||||
- Rate limit por IP e por dispositivo, com bloqueio progressivo
|
||||
|
||||
@@ -91,6 +92,7 @@ Importação CSV de unidades com **dry-run obrigatório** — devolve o que seri
|
||||
|
||||
- [ ] Testes de integração com Testcontainers cobrindo os fluxos A, B e C ponta a ponta
|
||||
- [ ] **Teste de busca cega:** unidade existente e inexistente produzem resposta idêntica, e a diferença de tempo fica abaixo do ruído de medição
|
||||
- [ ] **Teste de visita-sombra:** unidade inexistente percorre a mesma sequência de estados, nos mesmos tempos, que uma visita real não atendida — e ninguém é notificado
|
||||
- [ ] Teste: geofence rejeita fora do raio e aceita dentro
|
||||
- [ ] Teste: `quiet_hours` desvia do morador
|
||||
- [ ] Teste: dois `resolve` concorrentes — um vence, outro recebe `409` com o autor
|
||||
|
||||
@@ -22,7 +22,7 @@ Login OIDC com **MFA obrigatório** — este perfil vê fotos de todos os visita
|
||||
|
||||
### 2. Auditoria de visitas — a tela mais importante
|
||||
|
||||
Tabela virtualizada com filtros persistidos na URL: período, condomínio, bloco, unidade, tipo, estado, **dentro/fora do geofence**, e quem resolveu.
|
||||
Tabela virtualizada com filtros persistidos na URL: período, condomínio, bloco, unidade, tipo, estado, **dentro/fora do geofence**, quem resolveu, e **"unidade não cadastrada"** (visitas-sombra: erro de digitação legítimo ou tentativa de enumeração — recorrência do mesmo dispositivo em unidades diferentes é padrão de varredura e deve gerar destaque).
|
||||
|
||||
Colunas: data/hora, tipo, visitante, unidade, estado, quem resolveu, duração, selo de geofence.
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ Mesmo binário Compose Multiplatform, perfil decidido por `GET /me`. Layout mais
|
||||
|
||||
**Contexto** à direita, antes de assumir: histórico da unidade, visitas recentes, regra de entrega, nomes dos moradores, telefone. **O operador nunca atende sem contexto** — atender às cegas é o que faz a portaria remota parecer pior que a física.
|
||||
|
||||
**Visitas-sombra** (`unit_id` nulo — busca cega, `03-FLUXOS-E-CONTRATOS.md` §2) chegam à fila marcadas como **"unidade não cadastrada"**, visível só para o operador. Ele trata como um porteiro trataria quem errou o número: pergunta, corrige a unidade (`PATCH` que resolve o `unit_id` e registra em `audit_log`) e redireciona — ou nega. Para o visitante, nada distingue esse atendimento de um normal.
|
||||
|
||||
Presença: `DISPONIVEL` / `EM_ATENDIMENTO` / `OFFLINE`, com heartbeat. Operador que perde conexão volta para `OFFLINE` automaticamente e suas visitas retornam à fila.
|
||||
|
||||
Ao resolver, o operador registra `resolution_reason` — obrigatório, e é o que alimenta a análise de por que o modelo autônomo falhou naquele caso.
|
||||
|
||||
@@ -18,7 +18,7 @@ Playwright para os webs, Maestro para os apps. Cenários obrigatórios:
|
||||
2. Entrega em um toque, resolvida pela notificação, em menos de 10s
|
||||
3. Escalonamento completo: ninguém atende → outros moradores → fila → operador → autorizado
|
||||
4. Recado: ninguém atende, sem módulo de operador → grava → morador resolve depois
|
||||
5. Unidade inexistente: visita criada, ninguém notificado, expira — **resposta indistinguível de unidade válida**
|
||||
5. Unidade inexistente: visita criada, ninguém notificado, e a **sequência de estados vista pelo visitante é idêntica** à de uma visita real não atendida (visita-sombra) — incluindo os tempos das transições
|
||||
6. Fora do geofence: bloqueado com mensagem acionável
|
||||
7. Quiet hours: desvia sem tocar em ninguém
|
||||
8. Dois moradores respondendo juntos: um vence, o outro vê quem resolveu
|
||||
@@ -56,7 +56,7 @@ Derrube cada peça, uma por vez, com uma visita em andamento, e verifique o comp
|
||||
|
||||
Percorra o modelo de ameaças de `06-LGPD-E-SEGURANCA.md` §5 e prove cada mitigação:
|
||||
|
||||
- [ ] **A.1 Busca cega** — tempo de resposta constante medido estatisticamente, não no olho. Este é o teste mais importante da fase
|
||||
- [ ] **A.1 Busca cega** — tempo de resposta constante medido estatisticamente, não no olho, **e** linha do tempo de estados idêntica entre unidade real não atendida e visita-sombra. Este é o teste mais importante da fase
|
||||
- [ ] **A.2 Geofence** — rejeita fora do raio; GPS falsificado é registrado
|
||||
- [ ] **A.3 DoS social** — rate limit e quiet hours funcionam; varredura gera alerta
|
||||
- [ ] **A.4 Mídia** — nenhuma URL pública; assinada expira; acesso auditado
|
||||
|
||||
Reference in New Issue
Block a user