obsidian-vault/ligbox-ops-platform/specs/013-email-server-migration/spec.md
2026-06-19 17:26:42 +00:00

287 lines
10 KiB
Markdown

# Feature Specification: Migração de E-mail entre Servidores (013)
**Criado:** 2026-06-10
**Solicitado por:** Roger
**Status:** 📋 **Draft — Spec 019 execução VM122 (2026-06-16)**
**Execução OPS:** Ver `specs/019-email-migration-vm122-execution/spec.md` — migração legado **só VM122**, wizard VM112 só após gate DNS.
**Prioridade:** **P0** (bloqueia cutover DNS seguro em migrações)
**Depende de:** Spec 001 (webhooks), Spec 010 (assist/takeover), Spec 012 (ticket/lead)
**Pesquisa:** [research.md](./research.md)
**Plano técnico:** [plan.md](./plan.md)
---
## Resumo
Módulo **Email Migration** no Ligbox Ops Platform para **iniciar, acompanhar e finalizar** migrações de e-mail entre servidores diferentes (origem heterogénea → **Carbonio Ligbox**), com suporte a:
- **IMAP** (cPanel, Zimbra, O365, Gmail, outro Carbonio…)
- **PST / OST** (Outlook)
- **mbox / EML**
- **TGZ** (export nativo Zimbra/Carbonio)
**Regra de ouro (Roger):** a decisão de migração e a **validação técnica** devem estar **concluídas antes de virar o DNS** (MX/SPF/DKIM/DMARC). O cutover DNS é um **gate** controlado pelo Ops Desk — não um passo do wizard sem pré-requisito.
---
## Problema
Hoje o funil VM112 aplica DNS e cria contas sem um módulo formal que:
1. Inventarie mailboxes e formatos de origem.
2. Execute sync incremental **enquanto o servidor antigo ainda recebe mail**.
3. Valide integridade (contagens, amostras, erros PST).
4. **Bloqueie** cutover DNS até `migration_gate = ready_for_dns`.
5. Registe tudo no ticket Desk para auditoria.
Risco sem este módulo: perda de e-mail, duplicatas, PST corrompido importado silenciosamente, MX apontado cedo demais.
---
## Decisões de arquitectura (propostas — Roger valida)
| # | Tema | Decisão proposta |
|---|------|------------------|
| 1 | Ordem operacional | **Migrar → validar → depois DNS** |
| 2 | Motor IMAP | **imapsync** (primário) |
| 3 | Motor PST | **readpst** + **imap-upload** (pipeline oficial) |
| 4 | Motor Zimbra/Carbonio | **zmmailbox TGZ** (nativo) + imapsync fallback |
| 5 | Orquestração | VM122 API + Worker (não no wizard cliente) |
| 6 | UI | Vista **Email Migration** no Desk + painel no ticket |
| 7 | Gate DNS | API `migration_gate` integrada ao fluxo `dns.applied` / assist |
| 8 | Credenciais origem | Vault encriptado SQLite; nunca em logs |
| 9 | Execução ferramentas | Worker em VM122 (piloto) ou **VM123 dedicada** (produção — ver [infrastructure.md](./infrastructure.md)) |
| 10 | VM / recursos | **Decisão futura** — documentado em [infrastructure.md](./infrastructure.md); **não provisionar hoje** |
---
## Fases do ciclo de migração (antes e depois do DNS)
```mermaid
stateDiagram-v2
[*] --> discovered: Inventário origem
discovered --> preflight: Contas destino criadas
preflight --> initial_sync: 1ª sync bulk
initial_sync --> delta_sync: Syncs incrementais
delta_sync --> cutover_ready: Gate técnico OK
cutover_ready --> dns_cutover: MX/DNS alterado
dns_cutover --> final_sync: Última delta
final_sync --> verified: Contagens OK
verified --> closed: Ticket fechado
initial_sync --> failed: Erro crítico
delta_sync --> failed
failed --> delta_sync: Retry após fix
```
### Fase 0 — `discovered` (antes de qualquer sync)
- Domínio e lista de mailboxes (manual ou CSV).
- Por mailbox: `source_type` (imap | pst | mbox | eml | tgz | zimbra).
- Tamanho estimado, pastas, requisitos OAuth.
- **Saída:** job de migração criado no Desk.
### Fase 1 — `preflight`
- Conta destino existe no Carbonio (`zmprov` / wizard já criou).
- Teste credencial origem (`imapsync --justlogin` ou `readpst -V`).
- Teste IMAP destino.
- Plano de mapeamento pastas (ex.: `Sent Items``Sent`).
### Fase 2 — `initial_sync` (AINDA SEM DNS)
- Sync bulk enquanto MX ainda aponta para **origem**.
- Mail novo continua a chegar ao servidor antigo.
- Pode durar horas/dias conforme volume.
### Fase 3 — `delta_sync` (AINDA SEM DNS)
- Syncs incrementais agendados (ex.: 6/6h ou manual).
- Dashboard mostra: msgs origem vs destino, % completo, último erro.
### Fase 4 — `cutover_ready` — **GATE antes do DNS**
Critérios mínimos (configuráveis):
| Check | Threshold default |
|-------|-------------------|
| Contagem mensagens destino ≥ origem | ≥ 99% |
| Pastas críticas (Inbox, Sent) | 100% |
| Erros PST em quarentena | 0 críticos sem revisão |
| Delta última sync | < 50 msgs pendentes |
| Aprovação ops_lead | Manual (botão) |
**Estado `migration_gate`:** `blocked` | `warning` | `ready_for_dns`
### Fase 5 — `dns_cutover` (só com gate OK)
- Alterar MX/SPF/DKIM/DMARC (Cloudflare / pfSense).
- Wizard VM112 avança `dns.applied` final se gate = `ready_for_dns` **OU** flag `MIGRATION_GATE_OVERRIDE` (super_admin + motivo).
### Fase 6 — `final_sync`
- Janela de manutenção: sync final imapsync / doveadm sync -1.
- TTL MX baixo aplicado na fase 4.
### Fase 7 — `verified` → `closed`
- Relatório PDF/JSON no ticket.
- Cliente notificado.
- Credenciais origem revogadas do vault.
---
## Tipos de origem e pipeline
| source_type | Pipeline | Ferramenta |
|-------------|----------|------------|
| `imap` | Direct sync | imapsync |
| `imap_oauth` | OAuth token + sync | imapsync + oauth2_imap |
| `pst` | Extract upload | readpst imap-upload |
| `mbox` | Upload | imap-upload |
| `eml` | Bulk import | zmmailbox addMessage (lotes) |
| `tgz` | Native | zmmailbox getRestURL / postRestURL |
| `zimbra` | TGZ ou IMAP | zmmailbox + imapsync fallback |
| `dovecot` | dsync | doveadm backup (se aplicável) |
Detalhe ferramentas: [research.md](./research.md).
---
## Integração Ligbox Ops Desk
### Novo menu / vista
- **Email Migration** (`view-email-migration`)
- Lista jobs: domínio, tenant, fase, % sync, gate DNS
- Acções: Iniciar sync, Ver log, Aprovar gate, Bloquear DNS
### Ligação ao ticket (Spec 010)
- Ticket tipo `email_migration` ou tag em ticket onboarding existente.
- Cada `migration_run` gera nota no ticket.
- Assist/takeover: técnico credenciais mascaradas e logs.
### Webhooks (opcional Fase B)
- `migration.started` / `migration.phase_changed` / `migration.gate_ready`
- VM112 wizard consulta `GET /api/v1/migration/gate?domain=` antes de DNS final.
---
## API (contrato resumido)
| Método | Rota | Descrição |
|--------|------|-----------|
| POST | `/api/v1/migration/jobs` | Criar job |
| GET | `/api/v1/migration/jobs` | Listar |
| GET | `/api/v1/migration/jobs/{id}` | Detalhe + mailboxes |
| POST | `/api/v1/migration/jobs/{id}/preflight` | Correr preflight |
| POST | `/api/v1/migration/jobs/{id}/sync` | Disparar sync (initial/delta/final) |
| GET | `/api/v1/migration/jobs/{id}/runs` | Histórico execuções |
| GET | `/api/v1/migration/jobs/{id}/verify` | Relatório verificação |
| GET | `/api/v1/migration/gate?domain=` | Estado gate DNS |
| POST | `/api/v1/migration/jobs/{id}/approve-gate` | ops_lead aprova cutover |
| POST | `/api/v1/migration/jobs/{id}/upload-pst` | Upload PST (multipart) |
Permissões: `can_manage_migration` `super_admin`, `ops_lead`, `technician`.
---
## Requisitos não-funcionais
| ID | Requisito |
|----|-----------|
| NFR-1 | Logs de imapsync/readpst guardados 90 dias |
| NFR-2 | Credenciais origem AES-256 em SQLite |
| NFR-3 | PST upload max 50 GB (configurável) |
| NFR-4 | Worker timeout 24h por mailbox (retomável) |
| NFR-5 | Rate limit IMAP para não bloquear origem |
| NFR-6 | Relatório verificação obrigatório antes gate |
---
## User Stories
### US1 — Criar job de migração (P0)
**Como** ops_lead
**Quero** registar migração domínio X com lista de mailboxes e tipo de origem
**Para** planear sync antes do DNS
**Aceite:** job criado; ticket associado; fase `discovered`.
### US2 — Sync incremental IMAP (P0)
**Como** técnico
**Quero** correr imapsync agendado origem Carbonio
**Para** copiar mail sem duplicar e retomar após falha
**Aceite:** log parseado; contagens actualizadas; sem duplicatas em re-run.
### US3 — Import PST (P0)
**Como** técnico
**Quero** enviar ficheiro .pst e ver progresso por pasta
**Para** migrar Outlook sem erros silenciosos
**Aceite:** pipeline readpstimap-upload; erros em quarentena; relatório final.
### US4 — Gate DNS (P0)
**Como** ops_lead
**Quero** que o sistema bloqueie cutover DNS até validação OK
**Para** nunca virar MX com migração incompleta
**Aceite:** `migration_gate=blocked` impede DNS; `ready_for_dns` libera com auditoria.
### US5 — Verificação pós-sync (P1)
**Como** noc
**Quero** comparar contagens origem/destino por pasta
**Para** detectar perda antes do go-live
**Aceite:** relatório 99% ou lista de excepções justificadas.
---
## Fora de escopo (MVP / hoje)
- Migração calendário/contactos CardDAV ( e-mail IMAP/PST)
- Ferramentas comerciais (BitRecover, etc.)
- Migração automática sem ticket humano
- Execução imapsync **dentro** do container API (vai para worker host)
- **Provisionar VM123** ou volume extra na VM122 ver [infrastructure.md](./infrastructure.md) (**futuro**)
---
## Riscos
| Risco | Mitigação |
|-------|-----------|
| PST corrupto | readpst validate; quarentena ERR_MBOX |
| O365 bloqueia password | OAuth2 obrigatório |
| imap-upload encoding | `--debug`; retry; charset normalização |
| MX virado cedo | Gate API + override auditado |
| Mailbox gigante | Chunk por pasta; `--maxsize` imapsync |
---
## Critérios de aceite global
- [ ] Job percorre fases até `verified` em ambiente de teste (2 domínios)
- [ ] PST de teste importado sem perda em Inbox/Sent
- [ ] imapsync cPanelCarbonio com re-run sem duplicatas
- [ ] Gate bloqueia DNS quando contagem < 99%
- [ ] Gate libera com aprovação + relatório
- [ ] Logs e contagens visíveis no Desk
- [ ] Documentação quickstart reproduzível por técnico
---
## Próximos documentos
1. [plan.md](./plan.md) módulos, ficheiros, worker
2. [data-model.md](./data-model.md) tabelas SQLite
3. [tasks.md](./tasks.md) fases de implementação
4. [quickstart.md](./quickstart.md) runbook técnico
5. [infrastructure.md](./infrastructure.md) **VM/recursos (futuro — não hoje)**