# Análise do DataModule `ServidorWhatsapp.DataModule.DmServer`

## Resumo

A estrutura ficou melhor e mais coerente com a separação entre administradores (`usuarios`) e operadores (`operadores`).

O CRUD de operadores no `DmServer` já foi ajustado para trabalhar com os dados próprios do operador, sem depender de `usuario_id`:

```json
{
  "nome": "Operador Suporte",
  "email": "operador@empresa.com.br",
  "senha": "123456",
  "nome_exibicao": "Suporte",
  "max_atendimentos_simultaneos": 5,
  "status": "A"
}
```

## Pontos positivos encontrados

- `/api/admin/usuarios` ficou separado para administradores.
- `/api/atendimento/operadores` agora usa `nome`, `email`, `senha`, `nome_exibicao`, `max_atendimentos_simultaneos` e `status`.
- As rotas de setor do operador ficaram bem organizadas:
  - `GET /api/atendimento/operadores/{id}/setores`
  - `POST /api/atendimento/operadores/{id}/setores`
  - `DELETE /api/atendimento/operadores/{id}/setores/{setor_id}`
- Já existe rota para alterar senha do operador:
  - `PATCH /api/atendimento/operadores/{id}/senha`
- Já existe rota para alterar status do operador:
  - `PATCH /api/atendimento/operadores/{id}/status?novo=A`
- Já existe rota para alterar online/offline:
  - `PATCH /api/atendimento/operadores/{id}/online?novo=1`
- A rota de entrada de mensagens foi registrada no DFM:
  - `POST /api/atendimento/entrada`

## Ajuste crítico 1 — Token de operador ainda não é validado corretamente

### Problema

O método `ServerMethodDataModuleGetToken` permite login de operador:

```pascal
TAtendimentoOperadorModel.ValidateLogin(...)
```

Porém o método `ServerMethodDataModuleUserTokenAuth` valida qualquer token usando apenas:

```pascal
TUsuarioModel.GetUsuario(...)
```

Isso significa que:

1. Um operador consegue gerar token.
2. Na próxima requisição autenticada, esse token pode falhar porque o ID será procurado na tabela `usuarios`.
3. Se existir um admin com o mesmo ID do operador, o token do operador pode ser aceito indevidamente como se fosse usuário/admin.

### Correção recomendada

O `UserTokenAuth` precisa ler o campo `tipo` salvo no token e validar em tabelas diferentes:

- `tipo = admin` → `TUsuarioModel.GetUsuario`
- `tipo = operador` → `TAtendimentoOperadorModel.GetRestOperador` ou um método próprio `GetOperador/ValidarToken`

## Ajuste crítico 2 — JSON do token deve escapar strings

Hoje o token é montado com `Format`:

```pascal
AuthOptions.GetToken(Format('{"id":%s, "tipo": "%s", "nome":"%s", "nome_exibicao": "%s", "status":"%s"}', ...));
```

Se `nome` ou `nome_exibicao` tiver aspas, barra invertida ou algum caractere especial, o JSON do token pode ficar inválido.

Recomendado usar `JsonEscape` nos campos string ou montar com objeto JSON.

## Ajuste importante 3 — `CriarEventosWebhooksCadastrados` tem erro no `finally`

### Problema

No final do método está assim:

```pascal
finally
  if LWebHooksJs = nil then
    LWebHooksJs.Free;
end;
```

O correto é:

```pascal
finally
  if LWebHooksJs <> nil then
    LWebHooksJs.Free;
end;
```

Do jeito atual, o objeto não é liberado quando existe.

Também é recomendado validar se `data` existe antes de usar:

```pascal
if LWebHooksJs.GetValue('data') = nil then
  Exit;
```

## Ajuste importante 4 — Rotas dinâmicas de webhook só são carregadas no startup

O método `CriarEventosWebhooksCadastrados` roda no `OnCreate`.

Se o admin cadastrar um novo webhook pelo painel, essa rota dinâmica provavelmente só ficará disponível depois de reiniciar o servidor, a menos que você chame uma rotina de recarregamento dos eventos.

Recomendado criar futuramente:

```http
POST /api/admin/webhooks/recarregar-rotas
```

Ou chamar internamente `CriarEventosWebhooksCadastrados` após inserir/alterar um webhook.

## Ajuste importante 5 — Entrada de mensagens está protegida por token

No DFM, a rota:

```http
/api/atendimento/entrada
```

está com `NeedAuthorization = True`.

Isso é bom para segurança, mas o componente/serviço que envia as mensagens recebidas para esse endpoint precisará enviar Bearer Token válido.

Se essa rota for chamada por processo interno ou por webhook externo, o ideal é decidir entre:

1. Bearer Token interno.
2. Assinatura HMAC.
3. Token fixo de integração.
4. IP whitelist + token.

## Rotas de atendimento identificadas

| Método | Rota | Situação |
|---|---|---|
| GET | `/api/atendimento/canais` | OK |
| POST | `/api/atendimento/canais` | OK |
| PUT | `/api/atendimento/canais/{id}` | OK |
| PATCH | `/api/atendimento/canais/{id}/status?novo=A` | OK |
| GET | `/api/atendimento/palavras_chave` | OK |
| POST | `/api/atendimento/palavras_chave` | OK |
| PUT | `/api/atendimento/palavras_chave/{id}` | OK |
| PATCH | `/api/atendimento/palavras_chave/{id}/status?novo=A` | OK |
| GET | `/api/atendimento/setores` | OK |
| GET | `/api/atendimento/setores/menu` | OK |
| POST | `/api/atendimento/setores` | OK |
| PUT | `/api/atendimento/setores/{id}` | OK |
| PATCH | `/api/atendimento/setores/{id}/status?novo=A` | OK |
| GET | `/api/atendimento/operadores` | OK |
| GET | `/api/atendimento/operadores/{id}` | OK |
| POST | `/api/atendimento/operadores` | OK |
| PUT | `/api/atendimento/operadores/{id}` | OK |
| PATCH | `/api/atendimento/operadores/{id}/senha` | OK |
| PATCH | `/api/atendimento/operadores/{id}/status?novo=A` | OK |
| PATCH | `/api/atendimento/operadores/{id}/online?novo=1` | OK |
| GET | `/api/atendimento/operadores/{id}/setores` | OK |
| POST | `/api/atendimento/operadores/{id}/setores` | OK |
| DELETE | `/api/atendimento/operadores/{id}/setores/{setor_id}` | OK |
| GET | `/api/atendimento/contatos` | OK |
| GET | `/api/atendimento/contatos/{id}` | OK |
| PATCH | `/api/atendimento/contatos/{id}/status?novo=A` | OK |
| GET | `/api/atendimento/atendimentos` | OK |
| GET | `/api/atendimento/atendimentos/{id}` | OK |
| GET | `/api/atendimento/atendimentos/{id}/mensagens` | OK |
| POST | `/api/atendimento/atendimentos/{id}/assumir` | OK |
| POST | `/api/atendimento/atendimentos/{id}/mensagens` | OK |
| PATCH | `/api/atendimento/atendimentos/{id}/finalizar` | OK |
| PATCH | `/api/atendimento/atendimentos/{id}/lidas_operador` | OK |
| GET | `/api/atendimento/fila?operador_id=1` | OK |
| GET | `/api/atendimento/em_andamento?operador_id=1` | OK |
| POST | `/api/atendimento/entrada` | OK, mas atenção à autenticação |

## Ordem recomendada de correção

1. Corrigir `ServerMethodDataModuleUserTokenAuth`.
2. Escapar corretamente os campos string no JSON do token.
3. Corrigir o `finally` de `CriarEventosWebhooksCadastrados`.
4. Validar se a rota `/api/atendimento/entrada` será chamada com Bearer Token.
5. Depois disso, testar login admin e login operador separadamente no Postman.
