diff --git a/crates/adapters/postgres/migrations/001_initial_schema.sql b/crates/adapters/postgres/migrations/001_initial_schema.sql new file mode 100644 index 0000000..8fb8993 --- /dev/null +++ b/crates/adapters/postgres/migrations/001_initial_schema.sql @@ -0,0 +1,55 @@ +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; + +CREATE TABLE IF NOT EXISTS users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + username VARCHAR(32) NOT NULL UNIQUE, + email VARCHAR(255) NOT NULL UNIQUE, + password_hash TEXT NOT NULL, + display_name VARCHAR(50), + bio VARCHAR(160), + avatar_url TEXT, + header_url TEXT, + custom_css TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS thoughts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + content VARCHAR(128) NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS follows ( + follower_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + following_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + PRIMARY KEY (follower_id, following_id) +); + +CREATE TABLE IF NOT EXISTS top_friends ( + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + friend_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + position SMALLINT NOT NULL, + PRIMARY KEY (user_id, friend_id), + UNIQUE (user_id, position) +); + +CREATE TABLE IF NOT EXISTS tags ( + id SERIAL PRIMARY KEY, + name VARCHAR(50) NOT NULL UNIQUE +); + +CREATE TABLE IF NOT EXISTS thought_tags ( + thought_id UUID NOT NULL REFERENCES thoughts(id) ON DELETE CASCADE, + tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE, + PRIMARY KEY (thought_id, tag_id) +); + +CREATE TABLE IF NOT EXISTS api_keys ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + key_hash TEXT NOT NULL UNIQUE, + name VARCHAR(50) NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); diff --git a/crates/adapters/postgres/migrations/002_federation_columns.sql b/crates/adapters/postgres/migrations/002_federation_columns.sql new file mode 100644 index 0000000..f5f0ece --- /dev/null +++ b/crates/adapters/postgres/migrations/002_federation_columns.sql @@ -0,0 +1,21 @@ +ALTER TABLE users + ADD COLUMN IF NOT EXISTS ap_id TEXT UNIQUE, + ADD COLUMN IF NOT EXISTS inbox_url TEXT, + ADD COLUMN IF NOT EXISTS public_key TEXT, + ADD COLUMN IF NOT EXISTS private_key TEXT, + ADD COLUMN IF NOT EXISTS local BOOLEAN NOT NULL DEFAULT true; + +ALTER TABLE thoughts + ADD COLUMN IF NOT EXISTS in_reply_to_id UUID REFERENCES thoughts(id), + ADD COLUMN IF NOT EXISTS in_reply_to_url TEXT, + ADD COLUMN IF NOT EXISTS ap_id TEXT UNIQUE, + ADD COLUMN IF NOT EXISTS visibility TEXT NOT NULL DEFAULT 'public', + ADD COLUMN IF NOT EXISTS content_warning TEXT, + ADD COLUMN IF NOT EXISTS sensitive BOOLEAN NOT NULL DEFAULT false, + ADD COLUMN IF NOT EXISTS local BOOLEAN NOT NULL DEFAULT true, + ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ; + +ALTER TABLE follows + ADD COLUMN IF NOT EXISTS state TEXT NOT NULL DEFAULT 'accepted', + ADD COLUMN IF NOT EXISTS ap_id TEXT, + ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); diff --git a/crates/adapters/postgres/migrations/003_new_tables.sql b/crates/adapters/postgres/migrations/003_new_tables.sql new file mode 100644 index 0000000..c5e4c8e --- /dev/null +++ b/crates/adapters/postgres/migrations/003_new_tables.sql @@ -0,0 +1,49 @@ +CREATE TABLE IF NOT EXISTS likes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + thought_id UUID NOT NULL REFERENCES thoughts(id) ON DELETE CASCADE, + ap_id TEXT UNIQUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE (user_id, thought_id) +); + +CREATE TABLE IF NOT EXISTS boosts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + thought_id UUID NOT NULL REFERENCES thoughts(id) ON DELETE CASCADE, + ap_id TEXT UNIQUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE (user_id, thought_id) +); + +CREATE TABLE IF NOT EXISTS blocks ( + blocker_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + blocked_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + PRIMARY KEY (blocker_id, blocked_id) +); + +CREATE TABLE IF NOT EXISTS remote_actors ( + url TEXT PRIMARY KEY, + handle TEXT NOT NULL, + display_name TEXT, + inbox_url TEXT NOT NULL, + shared_inbox_url TEXT, + public_key TEXT NOT NULL, + last_fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS notifications ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + type TEXT NOT NULL, + from_user_id UUID REFERENCES users(id) ON DELETE SET NULL, + thought_id UUID REFERENCES thoughts(id) ON DELETE CASCADE, + read BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_thoughts_user_id ON thoughts(user_id); +CREATE INDEX IF NOT EXISTS idx_thoughts_created_at ON thoughts(created_at DESC); +CREATE INDEX IF NOT EXISTS idx_follows_following_id ON follows(following_id); +CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications(user_id, read);