prompt inicial do projeto
This commit is contained in:
93
prompts/FASE-4-chamada.md
Normal file
93
prompts/FASE-4-chamada.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# FASE 4 — Videochamada
|
||||
|
||||
## Objetivo
|
||||
|
||||
LiveKit integrado ponta a ponta: emissão de tokens, sala por visita, vídeo no navegador do visitante, e degradação graciosa quando o SFU falha.
|
||||
|
||||
## Pré-requisitos
|
||||
|
||||
FASES 0–3 concluídas. Ler `docs/05-INFRA-DOCKER.md` §3 e §4, e `docs/01-ARQUITETURA.md` §5.5.
|
||||
|
||||
> **Faça a POC antes de escrever código de produção.** Suba `livekit-server` + `coturn` e feche uma chamada entre um navegador móvel em 4G real e um Android, medindo o tempo até o primeiro frame. É o maior risco técnico do projeto e o mais barato de derrubar cedo. Se a POC falhar, o problema quase sempre é a faixa UDP fechada no firewall.
|
||||
|
||||
## Tarefas
|
||||
|
||||
### 1. Porta de vídeo
|
||||
|
||||
```kotlin
|
||||
interface VideoCallProvider {
|
||||
suspend fun criarSala(visitId: UUID): RoomInfo
|
||||
suspend fun emitirToken(visitId: UUID, participante: Participant): String
|
||||
suspend fun encerrarSala(visitId: UUID)
|
||||
suspend fun saudavel(): Boolean
|
||||
}
|
||||
```
|
||||
|
||||
Adaptador `LiveKitProvider`. A porta existe para permitir trocar por serviço gerenciado sem tocar nos apps — decisão registrada em `01-ARQUITETURA.md` ADR-003.
|
||||
|
||||
### 2. Emissão de tokens
|
||||
|
||||
Token JWT do LiveKit gerado **pelo backend**, nunca pelo cliente. Escopo mínimo:
|
||||
|
||||
- `roomJoin` apenas na sala daquela visita
|
||||
- `canPublish` para vídeo e áudio
|
||||
- `canPublishData: false`
|
||||
- TTL de 10 minutos, alinhado à expiração da visita
|
||||
|
||||
`room_name` derivado determinísticamente de `visitId`, gravado em `visits.room_name`.
|
||||
|
||||
**Um token nunca dá acesso a outra sala.** Verifique isso com teste explícito.
|
||||
|
||||
### 3. Ciclo de vida da sala
|
||||
|
||||
Sala criada na transição para `EM_CHAMADA`, não antes — criar em `PENDENTE` desperdiça recurso do SFU em visitas que nunca são atendidas.
|
||||
|
||||
Encerrada ao chegar em estado final. `empty_timeout: 120` no LiveKit é a rede de segurança para sala órfã.
|
||||
|
||||
### 4. Vídeo na web do visitante
|
||||
|
||||
SDK `livekit-client` carregado por **`import()` dinâmico**, apenas quando a visita entra em `EM_CHAMADA`. Ele sozinho pesa mais que todo o resto do app — carregá-lo no bundle inicial destruiria o orçamento de 200KB da FASE 3.
|
||||
|
||||
Vídeo remoto em tela cheia, auto-preview pequeno no canto, botão de mudo e de encerrar. Indicador de qualidade de conexão.
|
||||
|
||||
### 5. Degradação graciosa
|
||||
|
||||
Circuit breaker (Resilience4j) sobre o `VideoCallProvider`. Ao abrir:
|
||||
|
||||
```
|
||||
LiveKit fora ─► AUDIO (mesma sala, sem vídeo, muito menos banda)
|
||||
└─► FOTO_TEXTO (visitante manda foto, morador aprova sem chamada)
|
||||
└─► FILA_OPERADOR (resolução por telefone)
|
||||
```
|
||||
|
||||
O nível vigente vai em `visits.degraded_mode`, é emitido como `DEGRADED_MODE` no WebSocket, aparece em `/actuator/health` e no painel admin.
|
||||
|
||||
**Comunique a degradação, nunca a esconda.** Esconder faz o usuário achar que o produto quebrou; nomear faz o produto parecer resiliente — que é o que ele é.
|
||||
|
||||
### 6. Configuração de mídia
|
||||
|
||||
**Limite de resolução imposto no servidor**, não no cliente: 480p a ~600kbps. 480p basta para reconhecer alguém na portaria; 1080p multiplicaria o custo de banda por quatro sem melhorar nenhuma decisão. Ver o dimensionamento em `05-INFRA-DOCKER.md` §4.
|
||||
|
||||
Simulcast desligado (só dois participantes). `adaptiveStream` e `dynacast` ligados. TURN configurado com o segredo do coturn.
|
||||
|
||||
### 7. Métricas
|
||||
|
||||
`portaria.call.time_to_first_frame` · `portaria.call.duration` · `portaria.call.failed_ratio` · `portaria.call.turn_usage_ratio` (uso alto de TURN indica problema de rede na portaria) · `portaria.call.degraded_ratio`.
|
||||
|
||||
## Critérios de aceite
|
||||
|
||||
- [ ] POC validada em rede real antes do código de produção
|
||||
- [ ] Chamada completa entre navegador móvel em 4G e Android
|
||||
- [ ] Tempo até o primeiro frame < 3s em rede boa
|
||||
- [ ] Teste: token de uma sala é rejeitado em outra sala
|
||||
- [ ] Teste: com LiveKit derrubado, o sistema degrada para áudio e depois para foto+texto
|
||||
- [ ] Teste: sala encerrada em todos os estados finais
|
||||
- [ ] SDK do LiveKit **não** aparece no bundle inicial do visitante
|
||||
- [ ] Bundle inicial continua ≤ 200KB gzip
|
||||
- [ ] Chamada funciona atrás de NAT simétrico (valida o coturn)
|
||||
|
||||
## Não faça nesta fase
|
||||
|
||||
- Gravação (módulo `video_recording`, FASE 8)
|
||||
- App do morador (FASE 5)
|
||||
- Mais de 2 participantes por sala
|
||||
Reference in New Issue
Block a user