-- 007_attachments.sql -- File attachments for chat messages (v0.12.0) -- -- Blobs live in object storage (PVC / S3). This table holds metadata. -- Access control: always join through channels — attachments inherit -- channel membership as their access boundary. CREATE TABLE IF NOT EXISTS attachments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), channel_id UUID NOT NULL REFERENCES channels(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id), message_id UUID REFERENCES messages(id) ON DELETE SET NULL, filename VARCHAR(255) NOT NULL, content_type VARCHAR(127) NOT NULL, size_bytes BIGINT NOT NULL, storage_key TEXT NOT NULL, extracted_text TEXT, metadata JSONB DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Primary access pattern: find attachments for a channel (auth check joins here) CREATE INDEX IF NOT EXISTS idx_attachments_channel ON attachments(channel_id); -- Quota calculation: SUM(size_bytes) WHERE user_id = $1 CREATE INDEX IF NOT EXISTS idx_attachments_user_size ON attachments(user_id); -- Find attachments for a specific message CREATE INDEX IF NOT EXISTS idx_attachments_message ON attachments(message_id) WHERE message_id IS NOT NULL; -- Orphan cleanup: find unlinked attachments older than threshold CREATE INDEX IF NOT EXISTS idx_attachments_orphan ON attachments(created_at) WHERE message_id IS NULL;