/** * portal/mail/model.mjs — 메일 영역 세부 표(§15~§18, §23.2). 중심 표(mail_services·mailboxes·domains)는 portal/core/model.mjs 에 있다. * * mail_servers 운영자가 등록한 AriMail 서버(공개 주소·내부 주소·전체 설정 주소·메일 프로그램 접속 호스트). 비밀(설정 토큰·사용량 키·SSO 비밀)은 보관소 'arimail::*'. * mail_tests 실제 외부 송신·수신·회신 확인 기록(활성화·전환 전후·수동). 단계와 결과만, 메일 내용은 없음. * mail_invites 메일함 초대(초기 비밀번호 대신 링크로 비밀번호를 정함): 토큰 해시·만료·사용 완료·재발송 횟수. * mail_aliases 별칭·전달 전용 주소 기록(정책 미확정이면 생성 불가, §16.2). * mail_exports 해지 뒤 30일 읽기·내보내기(.eml 묶음) 요청 기록(§23.2). * mail_conversions 사이트 대표 메일 → 독립 메일 서비스 전환 점검표와 전후 확인(§14). * mail_usage_log 서비스·메일함 사용량 계측 이력(화면 "마지막 계측 시각"·추이). */ export const MIGRATIONS = [{ id: 'mail_0001', sql: ` CREATE TABLE IF NOT EXISTS mail_servers ( id TEXT PRIMARY KEY, name TEXT NOT NULL, base_url TEXT NOT NULL, internal_url TEXT, setup_url TEXT, mail_host TEXT, is_default INTEGER NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'active', last_health_at TEXT, last_health_json TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS mail_tests ( id TEXT PRIMARY KEY, mail_service_id TEXT NOT NULL, group_id TEXT NOT NULL, kind TEXT NOT NULL, status TEXT NOT NULL, verifier TEXT, job_id TEXT, steps_json TEXT, result_json TEXT, created_by TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, ended_at TEXT ); CREATE INDEX IF NOT EXISTS mail_tests_service ON mail_tests(mail_service_id, created_at); CREATE TABLE IF NOT EXISTS mail_invites ( id TEXT PRIMARY KEY, mailbox_id TEXT NOT NULL, group_id TEXT NOT NULL, email TEXT, token_hash TEXT NOT NULL UNIQUE, expires_at TEXT NOT NULL, used_at TEXT, resent_count INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS mail_aliases ( id TEXT PRIMARY KEY, mail_service_id TEXT NOT NULL, group_id TEXT NOT NULL, address TEXT NOT NULL UNIQUE, target TEXT NOT NULL, kind TEXT NOT NULL DEFAULT 'alias', status TEXT NOT NULL DEFAULT 'active', created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS mail_exports ( id TEXT PRIMARY KEY, mail_service_id TEXT NOT NULL, group_id TEXT NOT NULL, status TEXT NOT NULL, location TEXT, size_bytes INTEGER, created_by TEXT, created_at TEXT NOT NULL, expires_at TEXT, ended_at TEXT, error TEXT ); CREATE TABLE IF NOT EXISTS mail_conversions ( id TEXT PRIMARY KEY, mail_service_id TEXT NOT NULL, group_id TEXT NOT NULL, site_id TEXT NOT NULL, status TEXT NOT NULL, checklist_json TEXT NOT NULL, before_test_id TEXT, after_test_id TEXT, job_id TEXT, created_by TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, ended_at TEXT, error TEXT ); CREATE TABLE IF NOT EXISTS mail_usage_log ( id TEXT PRIMARY KEY, mail_service_id TEXT NOT NULL, group_id TEXT NOT NULL, subject_type TEXT NOT NULL, subject_id TEXT NOT NULL, storage_bytes INTEGER, monthly_messages INTEGER, mailboxes INTEGER, warn_level INTEGER, limited_json TEXT, measured_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS mail_usage_log_subject ON mail_usage_log(subject_type, subject_id, measured_at); ` }];