287 lines
10 KiB
Markdown
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 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)**
|