33 lines
1.4 KiB
SQL
33 lines
1.4 KiB
SQL
-- 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;
|