196 lines
6.6 KiB
SQL
196 lines
6.6 KiB
SQL
CREATE TABLE users (
|
|
id SERIAL PRIMARY KEY,
|
|
username VARCHAR(50) NOT NULL UNIQUE,
|
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
display_name VARCHAR(100),
|
|
avatar_path TEXT,
|
|
instagram_url VARCHAR(500),
|
|
profile_visibility VARCHAR(20) NOT NULL DEFAULT 'friends'
|
|
CHECK (profile_visibility IN ('public', 'friends', 'nobody')),
|
|
is_admin BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE account_tokens (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
purpose VARCHAR(30) NOT NULL CHECK (purpose = 'password_reset'),
|
|
token_hash TEXT NOT NULL UNIQUE,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
used_at TIMESTAMP,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_account_tokens_lookup
|
|
ON account_tokens (token_hash, purpose, expires_at);
|
|
|
|
CREATE TABLE friendships (
|
|
id SERIAL PRIMARY KEY,
|
|
requester_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
addressee_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
status VARCHAR(20) NOT NULL DEFAULT 'pending'
|
|
CHECK (status IN ('pending', 'accepted')),
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CHECK (requester_id <> addressee_id),
|
|
UNIQUE (requester_id, addressee_id)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_friendships_pair
|
|
ON friendships (LEAST(requester_id, addressee_id), GREATEST(requester_id, addressee_id));
|
|
|
|
CREATE TABLE user_blocks (
|
|
blocker_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
blocked_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (blocker_id, blocked_id),
|
|
CHECK (blocker_id <> blocked_id)
|
|
);
|
|
|
|
CREATE INDEX idx_user_blocks_blocked
|
|
ON user_blocks (blocked_id, blocker_id);
|
|
|
|
CREATE TABLE direct_messages (
|
|
id SERIAL PRIMARY KEY,
|
|
sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
recipient_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
body TEXT NOT NULL,
|
|
read_at TIMESTAMP,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CHECK (sender_id <> recipient_id)
|
|
);
|
|
|
|
CREATE INDEX idx_direct_messages_conversation
|
|
ON direct_messages (sender_id, recipient_id, created_at);
|
|
|
|
CREATE INDEX idx_direct_messages_unread
|
|
ON direct_messages (recipient_id, read_at);
|
|
|
|
CREATE TABLE registration_invites (
|
|
id SERIAL PRIMARY KEY,
|
|
token_hash TEXT NOT NULL UNIQUE,
|
|
expires_at TIMESTAMP,
|
|
used_by INTEGER REFERENCES users(id),
|
|
used_at TIMESTAMP,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE sessions (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
token_hash TEXT NOT NULL UNIQUE,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE venues (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
street VARCHAR(255),
|
|
postal_code VARCHAR(20),
|
|
city VARCHAR(100),
|
|
country VARCHAR(100) DEFAULT 'Deutschland',
|
|
latitude DOUBLE PRECISION,
|
|
longitude DOUBLE PRECISION,
|
|
external_id VARCHAR(255),
|
|
source VARCHAR(50),
|
|
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE venue_aliases (
|
|
id SERIAL PRIMARY KEY,
|
|
venue_id INTEGER NOT NULL REFERENCES venues(id) ON DELETE CASCADE,
|
|
alias VARCHAR(255) NOT NULL,
|
|
UNIQUE (venue_id, alias)
|
|
);
|
|
|
|
CREATE TABLE concerts (
|
|
id SERIAL PRIMARY KEY,
|
|
artist VARCHAR(255) NOT NULL,
|
|
event_type VARCHAR(20) NOT NULL DEFAULT 'concert'
|
|
CHECK (event_type IN ('concert', 'festival', 'other')),
|
|
parent_event_id INTEGER REFERENCES concerts(id) ON DELETE SET NULL,
|
|
venue_id INTEGER REFERENCES venues(id) ON DELETE SET NULL,
|
|
start_datetime TIMESTAMP NOT NULL,
|
|
end_datetime TIMESTAMP,
|
|
description TEXT,
|
|
ticket_url TEXT,
|
|
ticket_price NUMERIC(10,2),
|
|
flyer_path TEXT,
|
|
flyer_url TEXT,
|
|
visibility VARCHAR(20) NOT NULL DEFAULT 'public'
|
|
CHECK (visibility IN ('public', 'friends', 'private')),
|
|
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE event_invitations (
|
|
concert_id INTEGER NOT NULL REFERENCES concerts(id) ON DELETE CASCADE,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
invited_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
viewed_at TIMESTAMP,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (concert_id, user_id)
|
|
);
|
|
|
|
CREATE INDEX idx_event_invitations_user ON event_invitations (user_id, viewed_at);
|
|
|
|
CREATE TABLE concert_comments (
|
|
id SERIAL PRIMARY KEY,
|
|
concert_id INTEGER NOT NULL REFERENCES concerts(id) ON DELETE CASCADE,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
body TEXT NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE concert_photos (
|
|
id SERIAL PRIMARY KEY,
|
|
concert_id INTEGER NOT NULL REFERENCES concerts(id) ON DELETE CASCADE,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
path TEXT NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE concert_attendance (
|
|
concert_id INTEGER NOT NULL REFERENCES concerts(id) ON DELETE CASCADE,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
status VARCHAR(20) NOT NULL CHECK (
|
|
status IN ('attending', 'maybe', 'ticket_search', 'ticket_offer')
|
|
),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (concert_id, user_id)
|
|
);
|
|
|
|
CREATE TABLE user_badges (
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
badge_code VARCHAR(50) NOT NULL,
|
|
awarded_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (user_id, badge_code)
|
|
);
|
|
|
|
CREATE INDEX idx_concerts_start_datetime
|
|
ON concerts(start_datetime);
|
|
|
|
CREATE INDEX idx_venues_name
|
|
ON venues(name);
|
|
|
|
CREATE INDEX idx_venues_external_id
|
|
ON venues(external_id);
|
|
|
|
CREATE INDEX idx_venue_aliases_alias
|
|
ON venue_aliases (LOWER(alias));
|
|
|
|
CREATE INDEX idx_concerts_parent_event_id
|
|
ON concerts(parent_event_id);
|
|
|
|
CREATE INDEX idx_concert_comments_concert
|
|
ON concert_comments(concert_id, created_at);
|
|
|
|
CREATE INDEX idx_concert_photos_concert
|
|
ON concert_photos(concert_id, created_at);
|
|
|
|
CREATE INDEX idx_concert_attendance_concert
|
|
ON concert_attendance(concert_id, status);
|