prompt inicial do projeto
This commit is contained in:
90
prompts/FASE-3-web-visitante.md
Normal file
90
prompts/FASE-3-web-visitante.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# FASE 3 — Web do visitante
|
||||
|
||||
## Objetivo
|
||||
|
||||
PWA do visitante completa: QR → aviso → permissões → captura → destino → espera narrada → resultado. Ambos os funis (visita e entrega). Sem videochamada ainda.
|
||||
|
||||
## Pré-requisitos
|
||||
|
||||
FASES 0–2 concluídas. Ler `docs/04-DESIGN-SYSTEM-UX.md` §3 e `docs/03-FLUXOS-E-CONTRATOS.md` §2 e §3.
|
||||
|
||||
## Contexto que determina cada decisão
|
||||
|
||||
O visitante está **em pé na calçada, no sol, com pressa, em 4G, e não vai instalar nada**. Tudo aqui deriva disso: bundle mínimo, uma ação por tela, tipografia grande, contraste alto.
|
||||
|
||||
## Tarefas
|
||||
|
||||
### 1. Base
|
||||
|
||||
Vite + React 19 + TS em `web/visitor`. Roteamento por `/v/{gateId}?s={sig}`. Tokens de `shared-ui`. PWA com manifest, **sem service worker de cache agressivo** — o visitante usa uma vez e o cache velho causaria mais problema que benefício.
|
||||
|
||||
**Orçamento: 200KB gzip**, com gate em CI. O SDK do LiveKit entra por `import()` dinâmico apenas na FASE 4, na tela de chamada — ele sozinho tem o tamanho de todo o resto do app.
|
||||
|
||||
### 2. Telas
|
||||
|
||||
Cinco telas conforme `04-DESIGN-SYSTEM-UX.md` §3, uma ação cada.
|
||||
|
||||
**Tela 1 — Aviso de tratamento.** Não é modal de consentimento com checkbox. A base legal é legítimo interesse; o que se faz é **informar com clareza**. Texto de `06-LGPD-E-SEGURANCA.md` §1, com link "Saiba mais". O botão diz "Continuar", não "Aceito".
|
||||
|
||||
**Tela 2 — Escolha do funil.** `📦 Entrega` primeiro, porque é a maioria do volume. `👤 Visita` abaixo.
|
||||
|
||||
**Tela 3 — Permissões e captura.** Solicita câmera e localização, com explicação **antes** do prompt nativo — pedir permissão sem contexto é a principal causa de negativa. Captura foto do rosto (visita) ou do pacote (entrega). Comprime no cliente para no máximo 1600px no lado maior.
|
||||
|
||||
Permissão negada: localização é bloqueante (`403 LOCATION_REQUIRED`), com instrução de como reabilitar. Câmera negada em entrega degrada para "sem foto"; em visita, é bloqueante.
|
||||
|
||||
**Tela 4 — Destino.** Bloco e unidade, campos livres. **Nenhum autocomplete, nenhuma sugestão, nenhuma validação de existência** — é a busca cega, e um autocomplete a destruiria. Nome do visitante obrigatório; documento e telefone opcionais.
|
||||
|
||||
**Tela 5 — Espera narrada.** A tela onde o produto se ganha ou se perde:
|
||||
|
||||
```
|
||||
TOCANDO "Chamando o morador..." barra 0→20s
|
||||
ESCALONADA "Tentando outros moradores..." barra 0→15s
|
||||
FILA_OPERADOR "Transferindo para a portaria" + posição na fila
|
||||
RECADO "Grave um recado em vídeo" → gravação
|
||||
```
|
||||
|
||||
Nunca um spinner mudo. Um spinner de 35 segundos é indistinguível de um app quebrado.
|
||||
|
||||
**Tela 6 — Resultado.** Autorizado: PIN de 6 dígitos em `display`, QR grande, contagem regressiva de validade. Negado: mensagem clara e sem tom acusatório. Expirado: instrução de contingência (botão físico da portaria).
|
||||
|
||||
### 3. Estado e conexão
|
||||
|
||||
Estado da visita via WebSocket com **fallback automático para polling** de 3s se o WS cair ou não conectar em 5s. O visitante em 4G instável é o caso comum, não a exceção.
|
||||
|
||||
Reconexão com backoff exponencial e teto de 10s. Estado da sessão em `sessionStorage`, para que refresh acidental não perca a visita.
|
||||
|
||||
### 4. Gravação de recado
|
||||
|
||||
`MediaRecorder`, 30s máximo, preview antes de enviar, upload com barra de progresso e retry.
|
||||
|
||||
### 5. Erros
|
||||
|
||||
Todo erro exibido vem do `detail` do `problem+json`, em português e acionável: **"Aproxime-se da entrada e tente novamente"**, nunca `OUTSIDE_GEOFENCE`.
|
||||
|
||||
### 6. Acessibilidade e legibilidade em campo
|
||||
|
||||
- Alvos de toque ≥ 48×48px, sem exceção
|
||||
- Corpo de texto ≥ 16px
|
||||
- Contraste ≥ 4.5:1, verificado em CI
|
||||
- Apenas extremos da escala neutra — sol direto derruba tons médios
|
||||
- `prefers-reduced-motion` respeitado
|
||||
- `lang="pt-BR"`, textos externalizados para i18n futura
|
||||
- Funciona em Safari iOS 15+ e Chrome Android 100+
|
||||
|
||||
## Critérios de aceite
|
||||
|
||||
- [ ] **Bundle ≤ 200KB gzip** (gate de CI)
|
||||
- [ ] TTI < 2s em 4G simulado (Lighthouse throttling)
|
||||
- [ ] Lighthouse: Performance ≥ 90, Acessibilidade = 100
|
||||
- [ ] Fluxo de entrega completo em ≤ 4 toques
|
||||
- [ ] Tela 4 não tem autocomplete nem validação de unidade
|
||||
- [ ] WS derrubado à força → polling assume e o fluxo continua
|
||||
- [ ] Localização negada → mensagem acionável, não erro técnico
|
||||
- [ ] Testado em iPhone e Android reais, sob sol
|
||||
- [ ] Todos os textos de erro em português, sem código técnico
|
||||
|
||||
## Não faça nesta fase
|
||||
|
||||
- Videochamada (FASE 4)
|
||||
- Service worker com cache de assets versionados
|
||||
- Qualquer tela de admin
|
||||
Reference in New Issue
Block a user