prompt inicial do projeto completo

This commit is contained in:
2026-07-22 18:45:09 -03:00
parent 6fb920d333
commit b9ede753c4
12 changed files with 64 additions and 18 deletions

View File

@@ -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