# Feature Specification: Desk Account Management & Registration (004)

**Criado:** 2026-06-10  
**Concluído:** 2026-06-10  
**Status:** ✅ **FECHADA — entregue e validada** (+ extensão 2FA recovery 2026-06-16)  
**API:** `0.9.4-desk-2fa-recovery`  
**Depende de:** Spec 003 (desk-auth-rbac)  
**Validado por:** Roger — cadastro, ativação, e-mail VM108, QR TOTP, login MFA, **Minha conta**

---

## Resumo

Fluxo completo para equipe técnica e ops do **Ligbox Ops Desk**:

**cadastro → aprovação root → ativação 2-de-3 → login → Minha conta (troca de senha)**

E-mail operacional via **VM108** (`@ligbox.com.br`). UI em **pt-BR**.

---

## Decisões confirmadas (Roger)

| Ponto | Decisão |
|-------|---------|
| **2FA ativação** | Três fatores — candidato completa **qualquer 2 de 3** |
| Perfil | Root escolhe na aprovação (`ops_lead`, `technician`, `noc`) |
| Login | **E-mail** é o username |
| Usuários seed | `root`, `admin`, `mini`, `noc` — sem cadastro |
| Idioma | **Português do Brasil (pt-BR)** |
| E-mail | **Ligbox** — `@ligbox.com.br` via **VM108** (Carbonio) |
| Telefone OTP | Por e-mail (SMS futuro) |
| ntfy | Opcional — `ntfy.sh` (sem instalar na VM122) |
| Troca de senha | Self-service em **Minha conta**; **TOTP obrigatório** se 2FA ativo |
| **Recuperação 2FA** | Link **Perdi acesso ao autenticador** no login — OTP e-mail + novo QR |
| **Códigos backup** | 10 códigos de uso único na ativação (e após recuperação) |

### Regra 2-de-3 (ativação)

| # | Fator | Método |
|---|-------|--------|
| 1 | E-mail | OTP 6 dígitos |
| 2 | Telefone | OTP 6 dígitos (por e-mail) |
| 3 | App autenticador | QR TOTP + ntfy opcional |

---

## Fluxo completo (entregue)

```mermaid
flowchart TD
    A[register.html] --> B[Pedido + ticket + e-mail root]
    B --> C[Root aprova — Mensagens]
    C --> D[E-mail + link activate.html]
    D --> E[2 de 3 fatores — 3 colunas]
    E --> F[Conta ativa]
    F --> G{totp_enabled?}
    G -->|Sim| H[Login senha + TOTP]
    G -->|Não| I[Login senha]
    H --> J[Minha conta]
    I --> J
    J --> K[Trocar senha — TOTP se ativo]
```

---

## Componentes entregues

| Componente | Estado |
|------------|--------|
| `register.html` | ✅ PRG → login |
| `activate.html` | ✅ 3 colunas, QR local, progresso, ntfy |
| `login.html` | ✅ MFA step |
| `index.html` — Mensagens / Admin / **Minha conta** | ✅ |
| Postfix VM122 → LMTP VM108 | ✅ |
| `ligbox-ops@ligbox.com.br` | ✅ |
| `pyotp` + `/login/mfa` | ✅ |
| ntfy push OTP | ✅ |
| Tickets cadastro | ✅ |
| pt-BR (UI + API + e-mails) | ✅ |
| `POST /change-password` | ✅ |
| Formulário Minha conta estável | ✅ sem refresh apagando campos |

---

## API (v0.8)

| Método | Endpoint | Descrição |
|--------|----------|-----------|
| POST | `/api/v1/auth/register` | Novo pedido |
| GET | `/api/v1/auth/registration-requests` | Lista (root) |
| POST | `/api/v1/auth/registration-requests/{id}/approve` | Aprovar |
| POST | `/api/v1/auth/registration-requests/{id}/reject` | Rejeitar |
| GET | `/api/v1/auth/activate?token=` | QR + fatores |
| POST | `/api/v1/auth/activate/send-email-otp` | OTP e-mail |
| POST | `/api/v1/auth/activate/send-phone-otp` | OTP telefone |
| POST | `/api/v1/auth/activate` | 2 de {email, phone, totp} |
| POST | `/api/v1/auth/login` | Pode retornar `mfa_required` |
| POST | `/api/v1/auth/login/mfa` | Conclui login TOTP |
| GET | `/api/v1/auth/me` | Perfil + `totp_enabled` |
| POST | `/api/v1/auth/change-password` | Troca senha (TOTP se ativo) |
| POST | `/api/v1/auth/login/mfa` | TOTP **ou** `backup_code` |
| POST | `/api/v1/auth/mfa-recovery/send-email` | OTP e-mail (sessão 2FA ativa) |
| POST | `/api/v1/auth/mfa-recovery/verify-email` | Valida OTP → `recovery_token` + QR |
| GET | `/api/v1/auth/mfa-recovery/setup` | QR pendente (recovery) |
| POST | `/api/v1/auth/mfa-recovery/complete` | Novo TOTP + JWT + backup codes |

### `POST /change-password`

```json
{
  "current_password": "senha-atual",
  "new_password": "nova-senha-min-8",
  "totp_code": "123456"
}
```

- `totp_code` **obrigatório** quando `totp_enabled = true` (protege sessão abandonada)
- Nova senha ≠ senha atual; mínimo 8 caracteres

---

## UI — telas principais

### `activate.html`
- 3 colunas responsivas · QR em `/assets/qrcode.min.js`
- Barra `X/2 fatores` · link ntfy

### `Minha conta` (todos os perfis)
- Dados do perfil (e-mail, role, último login, 2FA)
- Formulário: senha atual · nova · confirmar · TOTP (se ativo)
- Refresh automático **não** re-renderiza esta tela (preserva digitação)

---

## E-mail (arquitetura)

| VM | Função |
|----|--------|
| **108** | Mail Ligbox — `mail.ligbox.com.br` → LMTP `:7025` |
| **112** | Legado Ibytera — `@ibytera.com`, `@dratcoin.com` |
| **122** | Postfix local — roteamento por domínio |

**Env Desk:** `ligbox-ops@ligbox.com.br` · notificações root: `admin@ligbox.com.br`

Redirect temporário Postfix: `@itecnologys.com` → `@ligbox.com.br`

Docs: `docs/email-ligbox-vm108.md` · `docs/postfix-vm122.md`

---

## Critérios de aceite — todos ✅

- [x] Cadastro com aprovação root
- [x] Ativação 2-de-3 (e-mail, telefone, TOTP)
- [x] QR code funcional (biblioteca local)
- [x] OTP e-mail via VM108
- [x] Login MFA quando TOTP configurado
- [x] Tickets e notificações
- [x] UI pt-BR
- [x] Minha conta — troca de senha self-service
- [x] TOTP obrigatório na troca de senha (se 2FA ativo)
- [x] **Recuperação 2FA** — perdi autenticador (e-mail OTP + novo QR)
- [x] **Códigos backup** — 10× uso único na ativação e após recuperação
- [x] Login MFA aceita código de backup
- [x] Formulário Minha conta persistente ao digitar
- [x] Validação E2E Roger — **aprovado**

---

## Fora de escopo (futuro)

| Item | Notas |
|------|-------|
| SMS telefone | OTP continua por e-mail |
| ntfy self-hosted | Usar `ntfy.sh` por ora |
| Log auditoria senhas | Backlog ops |
| Remover redirect `@itecnologys.com` | Após migrar caixas VM108 |
| `must_change_password` no 1º login | Opcional v2.1 |
| Regenerar backup codes em Minha conta | Requer TOTP — backlog |

---

## Referências

- Spec 003 — auth/RBAC
- `specs/004-desk-account-management/tasks.md`
- `specs/004-desk-account-management/quickstart.md`
- `.cursor/rules/portugues-brasil.mdc`
