/** * @file Definiert Tabellen für Bildanhänge und Analyse-Caches und bereitet Anhangsmetadaten auf. */ export function initializeAttachments(db) { db.exec(` CREATE TABLE IF NOT EXISTS attachments ( id TEXT PRIMARY KEY, username TEXT NOT NULL REFERENCES users(username) ON DELETE CASCADE ON UPDATE CASCADE, original_name TEXT NOT NULL, storage_key TEXT NOT NULL UNIQUE, mime_type TEXT NOT NULL, size_bytes INTEGER NOT NULL, width INTEGER NOT NULL, height INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'temporary' CHECK(status IN ('temporary','attached')), created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, vision_model TEXT, vision_analysis TEXT, vision_analyzed_at TEXT ); CREATE TABLE IF NOT EXISTS message_attachments ( message_id INTEGER NOT NULL REFERENCES chat_messages(id) ON DELETE CASCADE, attachment_id TEXT NOT NULL REFERENCES attachments(id) ON DELETE CASCADE, position INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(message_id, attachment_id) ); CREATE INDEX IF NOT EXISTS attachment_references ON message_attachments(attachment_id); CREATE TABLE IF NOT EXISTS attachment_vision_analyses ( attachment_id TEXT NOT NULL REFERENCES attachments(id) ON DELETE CASCADE, vision_model TEXT NOT NULL, prompt_version INTEGER NOT NULL, question TEXT NOT NULL, analysis TEXT NOT NULL, analyzed_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (attachment_id, vision_model, prompt_version, question) ); CREATE TABLE IF NOT EXISTS upload_deletions (storage_key TEXT PRIMARY KEY); CREATE TABLE IF NOT EXISTS upload_leases ( token TEXT PRIMARY KEY, username TEXT NOT NULL REFERENCES users(username) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS upload_leases_user ON upload_leases(username); CREATE TABLE IF NOT EXISTS workspace_operation_leases ( username TEXT PRIMARY KEY REFERENCES users(username) ON DELETE CASCADE, token TEXT NOT NULL UNIQUE, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TRIGGER IF NOT EXISTS release_message_attachment AFTER DELETE ON message_attachments BEGIN DELETE FROM attachments WHERE id = OLD.attachment_id AND status = 'attached' AND NOT EXISTS (SELECT 1 FROM message_attachments WHERE attachment_id = OLD.attachment_id); END; CREATE TRIGGER IF NOT EXISTS queue_attachment_file_delete AFTER DELETE ON attachments BEGIN INSERT OR IGNORE INTO upload_deletions(storage_key) VALUES(OLD.storage_key); END; `); } export const attachmentMetadata = (row) => ({ id: row.id, type: "image", originalName: row.original_name, mimeType: row.mime_type, sizeBytes: row.size_bytes, width: row.width, height: row.height });