Add social features and harden beta release
This commit is contained in:
+55
-1
@@ -5,10 +5,57 @@ CREATE TABLE users (
|
||||
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 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,
|
||||
@@ -51,6 +98,9 @@ CREATE TABLE venue_aliases (
|
||||
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,
|
||||
@@ -58,6 +108,7 @@ CREATE TABLE concerts (
|
||||
ticket_url TEXT,
|
||||
ticket_price NUMERIC(10,2),
|
||||
flyer_path TEXT,
|
||||
flyer_url TEXT,
|
||||
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
@@ -82,7 +133,7 @@ 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')
|
||||
status IN ('attending', 'maybe', 'ticket_search', 'ticket_offer')
|
||||
),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (concert_id, user_id)
|
||||
@@ -107,6 +158,9 @@ CREATE INDEX idx_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);
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
ALTER TABLE concerts
|
||||
ADD COLUMN IF NOT EXISTS event_type VARCHAR(20) NOT NULL DEFAULT 'concert'
|
||||
CHECK (event_type IN ('concert', 'festival', 'other'));
|
||||
|
||||
ALTER TABLE concerts
|
||||
ADD COLUMN IF NOT EXISTS parent_event_id INTEGER
|
||||
REFERENCES concerts(id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_concerts_parent_event_id
|
||||
ON concerts(parent_event_id);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS instagram_url VARCHAR(500);
|
||||
@@ -0,0 +1,18 @@
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS profile_visibility VARCHAR(20) NOT NULL DEFAULT 'public'
|
||||
CHECK (profile_visibility IN ('public', 'friends'));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 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 IF NOT EXISTS idx_friendships_pair
|
||||
ON friendships (LEAST(requester_id, addressee_id), GREATEST(requester_id, addressee_id));
|
||||
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE IF NOT EXISTS 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 IF NOT EXISTS idx_direct_messages_conversation
|
||||
ON direct_messages (sender_id, recipient_id, created_at);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_direct_messages_unread
|
||||
ON direct_messages (recipient_id, read_at);
|
||||
@@ -0,0 +1,12 @@
|
||||
ALTER TABLE users
|
||||
ALTER COLUMN profile_visibility SET DEFAULT 'friends';
|
||||
|
||||
ALTER TABLE users
|
||||
DROP CONSTRAINT IF EXISTS users_profile_visibility_check;
|
||||
|
||||
ALTER TABLE users
|
||||
ADD CONSTRAINT users_profile_visibility_check
|
||||
CHECK (profile_visibility IN ('public', 'friends', 'nobody'));
|
||||
|
||||
ALTER TABLE concerts
|
||||
ADD COLUMN IF NOT EXISTS flyer_url TEXT;
|
||||
@@ -0,0 +1,28 @@
|
||||
ALTER TABLE users
|
||||
DROP COLUMN IF EXISTS email_verified;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 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
|
||||
);
|
||||
|
||||
DELETE FROM account_tokens WHERE purpose = 'verify_email';
|
||||
|
||||
ALTER TABLE account_tokens DROP CONSTRAINT IF EXISTS account_tokens_purpose_check;
|
||||
ALTER TABLE account_tokens ADD CONSTRAINT account_tokens_purpose_check
|
||||
CHECK (purpose = 'password_reset');
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_account_tokens_lookup
|
||||
ON account_tokens (token_hash, purpose, expires_at);
|
||||
|
||||
ALTER TABLE concert_attendance
|
||||
DROP CONSTRAINT IF EXISTS concert_attendance_status_check;
|
||||
|
||||
ALTER TABLE concert_attendance
|
||||
ADD CONSTRAINT concert_attendance_status_check
|
||||
CHECK (status IN ('attending', 'maybe', 'ticket_search', 'ticket_offer'));
|
||||
Reference in New Issue
Block a user