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), is_admin BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); 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), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE concerts ( id SERIAL PRIMARY KEY, artist VARCHAR(255) NOT 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, created_by INTEGER REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); 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') ), updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (concert_id, user_id) ); 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_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);