# 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) ```json { "migration_job_id": 42, "migration_phase": "delta_sync", "migration_gate": "warning", "migration_sync_percent": 87.5 } ``` --- ## Índices ```sql 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); ```