Data Model: Email Migration (013)
Storage: SQLite (VM122) — extensão do schema existente.
Tabelas
migration_jobs
| Coluna |
Tipo |
Descrição |
id |
INTEGER PK |
|
tenant_id |
INTEGER FK |
Tenant destino (VM112…) |
ticket_id |
INTEGER FK NULL |
Ticket Desk associado |
domain |
TEXT |
Domínio migrado |
phase |
TEXT |
discovered, preflight, initial_sync, delta_sync, cutover_ready, dns_cutover, final_sync, verified, closed, failed |
migration_gate |
TEXT |
blocked, warning, ready_for_dns |
source_server_label |
TEXT |
Ex.: "cPanel HostGator", "Exchange O365" |
dest_imap_host |
TEXT |
mail.dominio.com |
notes |
TEXT |
|
approved_by |
TEXT NULL |
user_id ops_lead |
approved_at |
TEXT NULL |
ISO8601 |
dns_cutover_at |
TEXT NULL |
|
created_at |
TEXT |
|
updated_at |
TEXT |
|
migration_mailboxes
| Coluna |
Tipo |
Descrição |
id |
INTEGER PK |
|
job_id |
INTEGER FK |
|
email |
TEXT |
user@domain.com |
source_type |
TEXT |
imap, imap_oauth, pst, mbox, eml, tgz, zimbra, dovecot |
source_host |
TEXT NULL |
|
source_user |
TEXT NULL |
|
credentials_ref |
TEXT NULL |
ID encriptado (não password plain) |
pst_path |
TEXT NULL |
caminho upload |
folder_map_json |
TEXT NULL |
{"Sent Items":"Sent"} |
messages_source |
INTEGER DEFAULT 0 |
última contagem origem |
messages_dest |
INTEGER DEFAULT 0 |
última contagem destino |
bytes_source |
INTEGER DEFAULT 0 |
|
bytes_dest |
INTEGER DEFAULT 0 |
|
sync_percent |
REAL DEFAULT 0 |
|
last_error |
TEXT NULL |
|
status |
TEXT |
pending, syncing, ok, error, quarantine |
created_at |
TEXT |
|
updated_at |
TEXT |
|
migration_runs
| Coluna |
Tipo |
Descrição |
id |
INTEGER PK |
|
job_id |
INTEGER FK |
|
mailbox_id |
INTEGER FK NULL |
NULL = job-level |
run_type |
TEXT |
preflight, initial, delta, final, verify, pst_extract, pst_upload, tgz_export, tgz_import |
tool |
TEXT |
imapsync, readpst, imap-upload, zmmailbox, doveadm, verify |
status |
TEXT |
queued, running, success, partial, failed |
exit_code |
INTEGER NULL |
|
log_path |
TEXT |
|
stats_json |
TEXT |
{"transferred":1200,"errors":2,"folders":14} |
started_at |
TEXT |
|
finished_at |
TEXT NULL |
|
triggered_by |
TEXT |
user_id ou worker |
migration_gate_checks
| Coluna |
Tipo |
Descrição |
id |
INTEGER PK |
|
job_id |
INTEGER FK |
|
check_id |
TEXT |
count_ratio, inbox_complete, sent_complete, pst_quarantine, delta_pending, manual_approval |
status |
TEXT |
pass, warn, fail |
message |
TEXT |
|
checked_at |
TEXT |
|
migration_credentials (vault)
| Coluna |
Tipo |
Descrição |
id |
TEXT PK |
uuid |
mailbox_id |
INTEGER FK |
|
secret_blob |
BLOB |
Fernet encrypted JSON {password, oauth_token} |
created_at |
TEXT |
|
expires_at |
TEXT NULL |
OAuth |
Estados — phase
discovered → preflight → initial_sync → delta_sync → cutover_ready
→ dns_cutover → final_sync → verified → closed
Qualquer fase → failed (retry manual)
Estados — migration_gate
| Valor |
Significado |
DNS |
blocked |
Checks críticos falham |
❌ Bloqueado |
warning |
Quase pronto; revisão humana |
❌ Bloqueado |
ready_for_dns |
Aprovado ops_lead + checks OK |
✅ Permitido |
Payload ticket (extensão)
{
"migration_job_id": 42,
"migration_phase": "delta_sync",
"migration_gate": "warning",
"migration_sync_percent": 87.5
}
Índices
CREATE INDEX idx_migration_jobs_domain ON migration_jobs(domain);
CREATE INDEX idx_migration_jobs_phase ON migration_jobs(phase);
CREATE INDEX idx_migration_mailboxes_job ON migration_mailboxes(job_id);
CREATE INDEX idx_migration_runs_job ON migration_runs(job_id);