-- 메일 게이트웨이 저장소. www 사이트의 DB와 분리하며 인증만 www DB(users)를 읽습니다. CREATE TABLE messages ( id TEXT PRIMARY KEY, provider_id TEXT UNIQUE, message_id TEXT, direction TEXT NOT NULL CHECK(direction IN ('inbound','outbound')), folder TEXT NOT NULL CHECK(folder IN ('inbox','sent','drafts','trash')), previous_folder TEXT, sender TEXT NOT NULL DEFAULT '', recipients_json TEXT NOT NULL DEFAULT '[]', cc_json TEXT NOT NULL DEFAULT '[]', bcc_json TEXT NOT NULL DEFAULT '[]', reply_to_json TEXT NOT NULL DEFAULT '[]', subject TEXT NOT NULL DEFAULT '', html TEXT, text TEXT NOT NULL DEFAULT '', original_html TEXT, headers_json TEXT NOT NULL DEFAULT '{}', source TEXT NOT NULL DEFAULT 'sync' CHECK(source IN ('webhook','sync','web')), state TEXT NOT NULL DEFAULT 'received' CHECK(state IN ('draft','sending','sent','received','failed')), send_key TEXT, send_started_at TEXT, read_at TEXT, received_at TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, sent_at TEXT, raw_status TEXT NOT NULL DEFAULT 'none' CHECK(raw_status IN ('none','stored','built','unavailable')), raw_size INTEGER NOT NULL DEFAULT 0, expires_at TEXT ); CREATE INDEX messages_folder_date ON messages(folder, received_at DESC); CREATE INDEX messages_expires ON messages(expires_at); CREATE INDEX messages_pop ON messages(direction, folder, received_at); -- 원본(RFC 5322 .eml)은 그대로 보관합니다. POP 은 이 바이트를 그대로 전달합니다. CREATE TABLE message_raw ( message_id TEXT PRIMARY KEY REFERENCES messages(id) ON DELETE CASCADE, eml BLOB NOT NULL, stored_at TEXT NOT NULL ); CREATE TABLE attachments ( id TEXT PRIMARY KEY, message_id TEXT NOT NULL REFERENCES messages(id) ON DELETE CASCADE, provider_id TEXT, filename TEXT NOT NULL DEFAULT '', content_type TEXT NOT NULL DEFAULT 'application/octet-stream', content_id TEXT, disposition TEXT NOT NULL DEFAULT 'attachment', size INTEGER NOT NULL DEFAULT 0, bytes BLOB, created_at TEXT NOT NULL ); CREATE INDEX attachments_message ON attachments(message_id); -- 영구 삭제하거나 보관 기간이 지난 메일을 동기화가 다시 가져오지 않게 합니다. CREATE TABLE tombstones (provider_id TEXT PRIMARY KEY, deleted_at TEXT NOT NULL, reason TEXT NOT NULL DEFAULT 'deleted'); CREATE TABLE sessions ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, login TEXT NOT NULL, expires_at TEXT NOT NULL, created_at TEXT NOT NULL, ip TEXT, ua TEXT ); -- POP 으로 한 번 전달한 메일은 같은 계정에 다시 내려주지 않습니다. CREATE TABLE pop_deliveries ( user_id TEXT NOT NULL, message_id TEXT NOT NULL REFERENCES messages(id) ON DELETE CASCADE, delivered_at TEXT NOT NULL, via TEXT NOT NULL DEFAULT 'retr' CHECK(via IN ('retr','dele')), PRIMARY KEY(user_id, message_id) ); CREATE TABLE webhook_events ( id TEXT PRIMARY KEY, type TEXT NOT NULL, provider_id TEXT, received_at TEXT NOT NULL, status TEXT NOT NULL, detail TEXT ); CREATE INDEX webhook_events_date ON webhook_events(received_at DESC); CREATE TABLE sync_runs ( id INTEGER PRIMARY KEY AUTOINCREMENT, trigger TEXT NOT NULL DEFAULT 'timer', started_at TEXT NOT NULL, finished_at TEXT, imported INTEGER NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'running', detail TEXT ); CREATE TABLE audit_log ( id TEXT PRIMARY KEY, actor TEXT, action TEXT NOT NULL, target TEXT, detail TEXT, created_at TEXT NOT NULL ); CREATE TABLE settings (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at TEXT NOT NULL);