-- Hosted mail domains and mailboxes (Stalwart provisioning) CREATE TABLE mail_domains ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name TEXT NOT NULL UNIQUE, status TEXT NOT NULL DEFAULT 'pending_verification', verification_token TEXT NOT NULL DEFAULT '', dkim_selector TEXT NOT NULL DEFAULT '', dkim_public_key TEXT NOT NULL DEFAULT '', stalwart_domain_id TEXT NOT NULL DEFAULT '', is_platform_domain BOOLEAN NOT NULL DEFAULT false, mx_verified_at TIMESTAMPTZ, txt_verified_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_mail_domains_status ON mail_domains(status); CREATE TABLE mailboxes ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), domain_id UUID NOT NULL REFERENCES mail_domains(id) ON DELETE CASCADE, local_part TEXT NOT NULL, user_id UUID REFERENCES users(id) ON DELETE SET NULL, mail_account_id UUID REFERENCES mail_accounts(id) ON DELETE SET NULL, stalwart_account_id TEXT NOT NULL DEFAULT '', quota_bytes BIGINT NOT NULL DEFAULT 5368709120, status TEXT NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(domain_id, local_part) ); CREATE INDEX idx_mailboxes_user ON mailboxes(user_id); CREATE INDEX idx_mailboxes_mail_account ON mailboxes(mail_account_id); -- Migration projects (Google Workspace / Microsoft 365 transitions) CREATE TABLE migration_projects ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), domain_id UUID REFERENCES mail_domains(id) ON DELETE SET NULL, name TEXT NOT NULL DEFAULT '', source_provider TEXT NOT NULL DEFAULT 'google', status TEXT NOT NULL DEFAULT 'draft', cutover_at TIMESTAMPTZ, delta_mode BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_migration_projects_status ON migration_projects(status); CREATE TABLE migration_invites ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), project_id UUID NOT NULL REFERENCES migration_projects(id) ON DELETE CASCADE, email TEXT NOT NULL, token TEXT NOT NULL UNIQUE, status TEXT NOT NULL DEFAULT 'invited', claimed_at TIMESTAMPTZ, user_id UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(project_id, email) ); CREATE INDEX idx_migration_invites_token ON migration_invites(token); CREATE INDEX idx_migration_invites_email ON migration_invites(email); CREATE TABLE migration_jobs ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), project_id UUID NOT NULL REFERENCES migration_projects(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, service TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', cursor_json JSONB NOT NULL DEFAULT '{}', stats_json JSONB NOT NULL DEFAULT '{}', error TEXT NOT NULL DEFAULT '', started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(project_id, user_id, service) ); CREATE INDEX idx_migration_jobs_status ON migration_jobs(status); CREATE TABLE migration_credentials ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, project_id UUID NOT NULL REFERENCES migration_projects(id) ON DELETE CASCADE, provider TEXT NOT NULL, encrypted_token BYTEA NOT NULL, scopes TEXT[] NOT NULL DEFAULT '{}', expires_at TIMESTAMPTZ, revoked_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(user_id, project_id, provider) ); CREATE INDEX idx_migration_credentials_user ON migration_credentials(user_id);