Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
82 lines
3.5 KiB
SQL
82 lines
3.5 KiB
SQL
-- 메일 게이트웨이 저장소. 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);
|