# Plano de testes — `AC-3` Sessão persistente e logout

**Story:** `docs/stories/AC-3-sessao-persistente.md`

Por que esta story concentra risco: **não existe recuperação de senha nesta
versão**. Sessão que cai sozinha custa uma conta — a pessoa pode não lembrar o
cadastro e perde o histórico. E o oposto é igualmente ruim: sessão que não morre
no logout deixa acesso vivo num aparelho emprestado.

| ID | Título | Tipo | Prioridade |
| -- | ------ | ---- | ---------- |
| AC-3-01 | Login devolve os dois tokens | caminho feliz | alta |
| AC-3-02 | Cold start com token válido entra direto | caminho feliz | alta |
| AC-3-03 | Cold start **sem rede** mantém a sessão | borda | alta |
| AC-3-04 | Cold start com token inválido limpa tudo | segurança | alta |
| AC-3-05 | Refresh rotaciona e invalida o anterior | segurança | alta |
| AC-3-06 | Refresh reusado é recusado | segurança | alta |
| AC-3-07 | Logout invalida o access token na hora | segurança | alta |
| AC-3-08 | Logout é idempotente | borda | média |
| AC-3-09 | Devices diferentes são independentes | borda | alta |
| AC-3-10 | Refresh de sessão revogada não ressuscita | segurança | alta |
| AC-3-11 | Token de conta apagada é recusado | borda | média |
| AC-3-12 | Sessão expirada durante envio preserva o rascunho | borda | alta |

---

### AC-3-01 — Login devolve os dois tokens
**Tipo:** caminho feliz · **Prioridade:** alta
**Resultado esperado:** `accessToken` e `refreshToken`, e o refresh **não** fica
em texto no banco (só o hash).

### AC-3-02 — Cold start com token válido entra direto
**Tipo:** caminho feliz · **Prioridade:** alta
**Passos:**
1. Fazer login, fechar o app, reabrir.
**Resultado esperado:** vai direto para a tela inicial, **sem** piscar a tela de
login. Piscar login a cada abertura é o que faz o participante achar que caiu a
sessão e tentar entrar de novo.

### AC-3-03 — Cold start sem rede mantém a sessão
**Tipo:** borda · **Prioridade:** alta
**Pré-condições:** sessão válida guardada; aparelho sem conexão.
**Resultado esperado:** entra com a conta em cache; **não** vai para o login.
_Este caso nasceu de um defeito real (06/08): os dois ramos do `restaurar()`
deslogavam, contrariando o próprio comentário do código._

### AC-3-04 — Cold start com token inválido limpa tudo
**Tipo:** segurança · **Prioridade:** alta
**Pré-condições:** token guardado que o servidor recusa (401).
**Resultado esperado:** volta ao login **e** o armazenamento é limpo — access,
refresh e a conta em cache. Deixar a conta em cache aqui manteria o nome de
alguém na tela de um aparelho que não é mais dele.

### AC-3-05 — Refresh rotaciona e invalida o anterior
**Tipo:** segurança · **Prioridade:** alta
**Resultado esperado:** o refresh usado deixa de funcionar e um novo é entregue.
Refresh reutilizável é credencial de longa duração sem revogação.

### AC-3-06 — Refresh reusado é recusado
**Tipo:** segurança · **Prioridade:** alta
**Passos:**
1. Renovar com o refresh A (recebendo B).
2. Tentar renovar de novo com A.
**Resultado esperado:** 401. É o sinal clássico de token roubado.

### AC-3-07 — Logout invalida o access token na hora
**Tipo:** segurança · **Prioridade:** alta
**Passos:**
1. Logout.
2. Chamar rota protegida com o **access token** de antes.
**Resultado esperado:** 401. JWT sozinho não é revogável; o que torna o logout
real é a sessão no banco ser consultada a cada requisição.

### AC-3-08 — Logout é idempotente
**Tipo:** borda · **Prioridade:** média
**Resultado esperado:** o segundo logout não falha. Toque duplo no botão não pode
virar erro.

### AC-3-09 — Devices diferentes são independentes
**Tipo:** borda · **Prioridade:** alta
**Passos:**
1. Login no device A e no device B.
2. Logout no A.
**Resultado esperado:** B continua funcionando. Logout no celular não pode
derrubar o tablet — e, mais importante, não pode derrubar a sessão de outra
pessoa.

### AC-3-10 — Refresh de sessão revogada não ressuscita
**Tipo:** segurança · **Prioridade:** alta
**Passos:**
1. Logout (revoga a sessão).
2. Tentar renovar com o refresh daquela sessão.
**Resultado esperado:** 401, sem criar sessão nova. Se renovar funcionasse, o
logout seria decorativo.

### AC-3-11 — Token de conta apagada é recusado
**Tipo:** borda · **Prioridade:** média
**Pré-condições:** conta removida do banco, token ainda dentro da validade.
**Resultado esperado:** 401, e nada de 500. Token válido de conta inexistente é
o caminho mais fácil de derrubar o guard com exceção não tratada.

### AC-3-12 — Sessão expirada durante envio preserva o rascunho
**Tipo:** borda · **Prioridade:** alta
**Pré-condições:** rodada com palpite digitado, sessão que morre no meio do envio.
**Resultado esperado:** o app leva ao login **sem perder o digitado**; depois de
entrar, o palpite continua lá e a fila envia. Perder palpite por causa de sessão
é somar dois problemas que o participante nem relaciona.
