# 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 só 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 vê 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 readpst→imap-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 (só 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 cPanel→Carbonio 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)**  
