-- 0.9.3: 대용량 첨부파일(다운로드 링크 발송). -- 큰 파일은 메일에 첨부하지 않고 서버 디스크(FILES_DIR, 기본 /files/)에 두고 메일에는 다운로드 링크만 넣습니다. -- 파일 바이트는 DB 에 넣지 않습니다(1GB 급 BLOB 은 SQLite 와 백업에 부담). 이 표는 파일의 메타데이터와 링크 상태만 가집니다. -- message_id : 파일이 딸린 초안/보낸 메일. 메일이 영구 삭제돼도 보낸 링크는 기한까지 살아 있어야 하므로 NULL 로 풀립니다(초안이면 정리 작업이 파일을 지움). -- token : 다운로드 링크(/dl/)의 비밀 값. 발송할 때 만들어지며 그 전(초안)에는 NULL. -- state : draft(초안에 올려 둠) → sent(링크 발송됨) → expired(기한·횟수 만료 또는 보낸 사람이 링크를 끊음, 파일은 지워짐) -- max_downloads: 허용 다운로드 횟수, downloads: 지금까지 받은 횟수(랜딩 페이지의 다운로드 단추를 누를 때마다 1), expires_at: 보관 기한(ISO) -- 발송 전에 기한과 횟수를 반드시 정하므로 sent 상태의 행은 둘 다 NULL 이 아닙니다(기한·횟수 제한 없는 발송 불가). CREATE TABLE large_files ( id TEXT PRIMARY KEY, message_id TEXT REFERENCES messages(id) ON DELETE SET NULL, mailbox TEXT NOT NULL, filename TEXT NOT NULL DEFAULT 'file', content_type TEXT NOT NULL DEFAULT 'application/octet-stream', size INTEGER NOT NULL DEFAULT 0, token TEXT UNIQUE, state TEXT NOT NULL DEFAULT 'draft' CHECK(state IN ('draft','sent','expired')), max_downloads INTEGER, downloads INTEGER NOT NULL DEFAULT 0, expires_at TEXT, created_at TEXT NOT NULL, sent_at TEXT, last_download_at TEXT ); CREATE INDEX large_files_message ON large_files(message_id); CREATE INDEX large_files_state ON large_files(state, expires_at);