feat(frontend): Administração > Usuários e Perfis (convidar, trocar papel)

POST /users (convidar) fecha uma lacuna real: até aqui só dava pra
adicionar alguém a um tenant criando o tenant inteiro ou via script. Se o
e-mail já existe na plataforma, só adiciona membership+role (sem tocar na
senha); se não existe, cria a conta com senha gerada e revelada uma única
vez. PATCH /users/:id/role troca o papel (substitui, 1 papel por tenant).

GET /roles novo (tenant-facing) — versão de /platform/roles filtrada só
pras roles de escopo TENANT, sem expor que platform_super_admin existe.

Frontend: /app/administracao/usuarios (convidar com papel, trocar papel
de qualquer membro exceto o próprio usuário logado) e /perfis (o que cada
papel pode fazer, só leitura).

Testado ponta a ponta contra a API real: convidada conta nova com senha
revelada, convidado usuário com papel Agente, trocado pra Supervisor via
PATCH, confirmado persistido. Perfis mostra as 3 roles de tenant certas.
Smoke test nas 19 telas do tenant + 10 telas platform, todas 200.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
2026-08-30 00:22:18 -03:00
parent 03ec0d556b
commit e9dc973aee
16 changed files with 593 additions and 16 deletions

43
TODO.md
View File

@@ -1353,6 +1353,49 @@ secao 134-139, 168)
definido na especificação além do nome, mesma pendência já
documentada na PHASE 34
## PHASE 37 — Frontend: Administração > Usuários e Perfis (tenant)
(agente.md secao 141-145, 169)
- [x] **Lacuna de backend fechada primeiro**: `POST /users` (convidar) —
até aqui só dava pra adicionar um usuário a um tenant criando o
tenant inteiro (Platform > Clientes > Tenants) ou via script. Se o
e-mail já existe na plataforma, só adiciona `TenantMembership` +
`UserRole` (sem tocar na senha da conta existente); se não existe,
cria o `User` com senha gerada e revelada uma única vez (mesmo
padrão de `TenantsController.create`). `PATCH /users/:id/role`
troca o papel (substitui, não acumula — simplificação deliberada de
"1 papel por tenant" mesmo o schema permitindo várias `UserRole`
por par usuário/tenant).
- [x] `GET /roles` (novo, tenant-facing) — versão filtrada de `/platform/
roles` só com as roles de escopo TENANT (Tenant Admin/Supervisor/
Agente); um tenant não precisa saber que `platform_super_admin`
existe.
- [x] Frontend: `/app/administracao/usuarios` (convidar com papel,
revela senha só quando é conta nova, trocar papel de qualquer
membro exceto o próprio usuário logado — trava de segurança
deliberada contra se auto-rebaixar/trancar fora sem querer).
`/app/administracao/perfis` — cards com o que cada papel pode
fazer, só leitura, mesmo componente visual de `Sistema >
Permissões` (platform) mas com os dados filtrados certos.
- [x] Testado ponta a ponta contra a API real: convidado
`supervisor@acme.b2bcall.local` (conta nova, senha revelada) com
papel Supervisor, convidado `agente1@acme.b2bcall.local` com papel
Agente, depois trocado o papel dele pra Supervisor via `PATCH
.../role` — confirmado via `GET /users` que persistiu. Perfis
mostra as 3 roles de tenant com as permissions certas, sem
`platform_super_admin` na lista. Smoke test de regressão nas 19
telas do tenant + 10 telas platform, todas 200 (alguns timeouts de
navegação intermitentes no script de teste — reproduzidos
isoladamente como falso-positivo do harness, não da aplicação;
toda rota confirmada 200 numa reexecução limpa).
- [ ] Sem remover um usuário do tenant (só trocar papel) — sem endpoint
de "remover membership" ainda; desabilitar a conta inteira já
existe em Platform > Sistema > Usuários, mas isso afeta todos os
tenants dela, não só este
- [ ] Sem trava contra remover o último Tenant Admin de um tenant (ex.:
trocar o papel do único admin pra Agente deixaria o tenant sem
ninguém com `users.manage`) — não implementado, mesma classe de
risco documentada em outras ações administrativas desta sessão
---
## Riscos conhecidos