mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
dev day #80
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
-- Drop engagement system tables in reverse order
|
||||
DROP TABLE IF EXISTS reward_redemptions;
|
||||
DROP TABLE IF EXISTS reward_items;
|
||||
DROP TABLE IF EXISTS user_achievements;
|
||||
DROP TABLE IF EXISTS achievements;
|
||||
DROP TABLE IF EXISTS points_transactions;
|
||||
DROP TABLE IF EXISTS user_profiles;
|
||||
@@ -0,0 +1,122 @@
|
||||
-- Create user profiles table for gamification
|
||||
CREATE TABLE IF NOT EXISTS user_profiles (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id BIGINT NOT NULL UNIQUE,
|
||||
points BIGINT NOT NULL DEFAULT 0,
|
||||
level INTEGER NOT NULL DEFAULT 1,
|
||||
xp BIGINT NOT NULL DEFAULT 0,
|
||||
username VARCHAR(32) UNIQUE NOT NULL,
|
||||
avatar_url VARCHAR(500),
|
||||
animated_avatar_url VARCHAR(500),
|
||||
avatar_upload_unlocked BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CONSTRAINT fk_user_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_profiles_user_id ON user_profiles(user_id);
|
||||
CREATE INDEX idx_user_profiles_points ON user_profiles(points DESC);
|
||||
CREATE INDEX idx_user_profiles_level ON user_profiles(level DESC);
|
||||
CREATE INDEX idx_user_profiles_xp ON user_profiles(xp DESC);
|
||||
CREATE INDEX idx_user_profiles_username ON user_profiles(LOWER(username));
|
||||
|
||||
-- Create points transactions log
|
||||
CREATE TABLE IF NOT EXISTS points_transactions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id BIGINT NOT NULL,
|
||||
delta BIGINT NOT NULL,
|
||||
xp_delta BIGINT NOT NULL DEFAULT 0,
|
||||
reason VARCHAR(64) NOT NULL,
|
||||
meta JSONB,
|
||||
CONSTRAINT fk_points_tx_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_points_tx_user ON points_transactions(user_id, created_at DESC);
|
||||
CREATE INDEX idx_points_tx_reason ON points_transactions(reason);
|
||||
CREATE INDEX idx_points_tx_created ON points_transactions(created_at DESC);
|
||||
|
||||
-- Create achievements table
|
||||
CREATE TABLE IF NOT EXISTS achievements (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
code VARCHAR(64) UNIQUE NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
points BIGINT NOT NULL DEFAULT 0,
|
||||
xp BIGINT NOT NULL DEFAULT 0,
|
||||
icon VARCHAR(255),
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_achievements_code ON achievements(code);
|
||||
CREATE INDEX idx_achievements_active ON achievements(active);
|
||||
|
||||
-- Create user achievements junction table
|
||||
CREATE TABLE IF NOT EXISTS user_achievements (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id BIGINT NOT NULL,
|
||||
achievement_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_user_ach_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_user_ach_achievement FOREIGN KEY (achievement_id) REFERENCES achievements(id) ON DELETE CASCADE,
|
||||
UNIQUE (user_id, achievement_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_ach_user ON user_achievements(user_id);
|
||||
CREATE INDEX idx_user_ach_achievement ON user_achievements(achievement_id);
|
||||
|
||||
-- Create reward items table
|
||||
CREATE TABLE IF NOT EXISTS reward_items (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(32) NOT NULL,
|
||||
cost_points BIGINT NOT NULL,
|
||||
image_url VARCHAR(500),
|
||||
stock INTEGER NOT NULL DEFAULT 0,
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
metadata JSONB
|
||||
);
|
||||
|
||||
CREATE INDEX idx_reward_items_type ON reward_items(type);
|
||||
CREATE INDEX idx_reward_items_active ON reward_items(active);
|
||||
CREATE INDEX idx_reward_items_cost ON reward_items(cost_points);
|
||||
|
||||
-- Create reward redemptions table
|
||||
CREATE TABLE IF NOT EXISTS reward_redemptions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id BIGINT NOT NULL,
|
||||
reward_id BIGINT NOT NULL,
|
||||
status VARCHAR(24) NOT NULL DEFAULT 'pending',
|
||||
CONSTRAINT fk_reward_red_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_reward_red_reward FOREIGN KEY (reward_id) REFERENCES reward_items(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_reward_red_user ON reward_redemptions(user_id);
|
||||
CREATE INDEX idx_reward_red_reward ON reward_redemptions(reward_id);
|
||||
CREATE INDEX idx_reward_red_status ON reward_redemptions(status);
|
||||
CREATE INDEX idx_reward_red_created ON reward_redemptions(created_at DESC);
|
||||
|
||||
-- Insert default achievements
|
||||
INSERT INTO achievements (code, title, description, points, xp, active) VALUES
|
||||
('first_comment', 'První komentář', 'Napsal/a jste první komentář.', 10, 10, TRUE),
|
||||
('first_vote', 'První hlasování', 'Poprvé jste hlasoval/a v anketě.', 8, 8, TRUE),
|
||||
('newsletter_sub', 'Odběr novinek', 'Přihlášení k odběru newsletteru.', 12, 12, TRUE),
|
||||
('comments_10', 'Komentátor', '10 komentářů!', 20, 20, TRUE),
|
||||
('votes_10', 'Hlasující', '10 hlasování!', 20, 20, TRUE),
|
||||
('comments_50', 'Aktivní člen', '50 komentářů!', 50, 50, TRUE),
|
||||
('votes_50', 'Věrný fanoušek', '50 hlasování!', 50, 50, TRUE),
|
||||
('comments_100', 'Veterán diskuzí', '100 komentářů!', 100, 100, TRUE)
|
||||
ON CONFLICT (code) DO NOTHING;
|
||||
|
||||
-- Create default avatar upload unlock reward
|
||||
INSERT INTO reward_items (name, type, cost_points, stock, active) VALUES
|
||||
('Odemknout vlastní avatar (upload)', 'avatar_upload_unlock', 100, -1, TRUE)
|
||||
ON CONFLICT DO NOTHING;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- Drop comments system tables in reverse order
|
||||
DROP TABLE IF EXISTS comment_reactions;
|
||||
DROP TABLE IF EXISTS comment_reports;
|
||||
DROP TABLE IF EXISTS unban_requests;
|
||||
DROP TABLE IF EXISTS comment_bans;
|
||||
DROP TABLE IF EXISTS comments;
|
||||
@@ -0,0 +1,93 @@
|
||||
-- Create comments table
|
||||
CREATE TABLE IF NOT EXISTS comments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
target_type VARCHAR(30) NOT NULL,
|
||||
target_id VARCHAR(128) NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
parent_id BIGINT,
|
||||
content TEXT NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'visible',
|
||||
spam_score REAL NOT NULL DEFAULT 0,
|
||||
spam_rules TEXT,
|
||||
is_edited BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
edited_at TIMESTAMP WITH TIME ZONE,
|
||||
CONSTRAINT fk_comments_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_comments_parent FOREIGN KEY (parent_id) REFERENCES comments(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_comments_target ON comments(target_type, target_id);
|
||||
CREATE INDEX idx_comments_user ON comments(user_id);
|
||||
CREATE INDEX idx_comments_parent ON comments(parent_id);
|
||||
CREATE INDEX idx_comments_status ON comments(status);
|
||||
CREATE INDEX idx_comments_created ON comments(created_at DESC);
|
||||
CREATE INDEX idx_comments_spam ON comments(spam_score DESC) WHERE spam_score > 0.5;
|
||||
|
||||
-- Create comment bans table
|
||||
CREATE TABLE IF NOT EXISTS comment_bans (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id BIGINT NOT NULL,
|
||||
reason TEXT,
|
||||
until TIMESTAMP WITH TIME ZONE,
|
||||
created_by_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_bans_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_bans_creator FOREIGN KEY (created_by_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_comment_bans_user ON comment_bans(user_id);
|
||||
CREATE INDEX idx_comment_bans_until ON comment_bans(until);
|
||||
CREATE INDEX idx_comment_bans_creator ON comment_bans(created_by_id);
|
||||
|
||||
-- Create unban requests table
|
||||
CREATE TABLE IF NOT EXISTS unban_requests (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id BIGINT NOT NULL,
|
||||
message TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
resolved_by_id BIGINT,
|
||||
resolved_at TIMESTAMP WITH TIME ZONE,
|
||||
CONSTRAINT fk_unban_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_unban_resolver FOREIGN KEY (resolved_by_id) REFERENCES users(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_unban_user ON unban_requests(user_id);
|
||||
CREATE INDEX idx_unban_status ON unban_requests(status);
|
||||
CREATE INDEX idx_unban_created ON unban_requests(created_at DESC);
|
||||
|
||||
-- Create comment reports table
|
||||
CREATE TABLE IF NOT EXISTS comment_reports (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
comment_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
reason VARCHAR(255),
|
||||
CONSTRAINT fk_reports_comment FOREIGN KEY (comment_id) REFERENCES comments(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_reports_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
UNIQUE (comment_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_comment_reports_comment ON comment_reports(comment_id);
|
||||
CREATE INDEX idx_comment_reports_user ON comment_reports(user_id);
|
||||
|
||||
-- Create comment reactions table
|
||||
CREATE TABLE IF NOT EXISTS comment_reactions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
comment_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
type VARCHAR(24) NOT NULL,
|
||||
CONSTRAINT fk_reactions_comment FOREIGN KEY (comment_id) REFERENCES comments(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_reactions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
UNIQUE (comment_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_comment_reactions_comment ON comment_reactions(comment_id);
|
||||
CREATE INDEX idx_comment_reactions_user ON comment_reactions(user_id);
|
||||
CREATE INDEX idx_comment_reactions_type ON comment_reactions(type);
|
||||
@@ -0,0 +1,5 @@
|
||||
-- Drop sweepstakes system tables (reverse)
|
||||
DROP TABLE IF EXISTS sweepstake_winners;
|
||||
DROP TABLE IF EXISTS sweepstake_entries;
|
||||
DROP TABLE IF EXISTS sweepstake_prizes;
|
||||
DROP TABLE IF EXISTS sweepstakes;
|
||||
@@ -0,0 +1,85 @@
|
||||
-- Sweepstakes/Lottery system
|
||||
-- Tables: sweepstakes, sweepstake_prizes, sweepstake_entries, sweepstake_winners
|
||||
|
||||
-- Main sweepstakes table
|
||||
CREATE TABLE IF NOT EXISTS sweepstakes (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
title VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
image_url VARCHAR(500),
|
||||
rules_url VARCHAR(500),
|
||||
|
||||
start_at TIMESTAMPTZ NOT NULL,
|
||||
end_at TIMESTAMPTZ NOT NULL,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'draft', -- draft|scheduled|active|locked|finalized|archived
|
||||
picker_style VARCHAR(16) NOT NULL DEFAULT 'wheel', -- wheel|cycler
|
||||
|
||||
total_prizes INTEGER NOT NULL DEFAULT 1,
|
||||
prize_summary TEXT,
|
||||
|
||||
winners_selected_at TIMESTAMPTZ,
|
||||
visibility_until TIMESTAMPTZ, -- set to end_at + 3 days at finalize
|
||||
draw_seed VARCHAR(64),
|
||||
max_entries_per_user INTEGER NOT NULL DEFAULT 1
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sweepstakes_status ON sweepstakes(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_sweepstakes_start ON sweepstakes(start_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_sweepstakes_end ON sweepstakes(end_at);
|
||||
|
||||
-- Prizes (per sweepstake)
|
||||
CREATE TABLE IF NOT EXISTS sweepstake_prizes (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
sweepstake_id BIGINT NOT NULL REFERENCES sweepstakes(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
image_url VARCHAR(500),
|
||||
value VARCHAR(255),
|
||||
quantity INTEGER NOT NULL DEFAULT 1,
|
||||
display_order INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_prizes_sweepstake ON sweepstake_prizes(sweepstake_id);
|
||||
|
||||
-- Entries (unique per user per sweepstake)
|
||||
CREATE TABLE IF NOT EXISTS sweepstake_entries (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
sweepstake_id BIGINT NOT NULL REFERENCES sweepstakes(id) ON DELETE CASCADE,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'valid', -- valid|invalid|withdrawn
|
||||
ip_hash VARCHAR(64),
|
||||
visual_played_at TIMESTAMPTZ,
|
||||
view_count INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE (sweepstake_id, user_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_entries_sweepstake ON sweepstake_entries(sweepstake_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_entries_user ON sweepstake_entries(user_id);
|
||||
|
||||
-- Winners (one per prize unit, unique winner per sweepstake)
|
||||
CREATE TABLE IF NOT EXISTS sweepstake_winners (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
sweepstake_id BIGINT NOT NULL REFERENCES sweepstakes(id) ON DELETE CASCADE,
|
||||
entry_id BIGINT NOT NULL REFERENCES sweepstake_entries(id) ON DELETE CASCADE,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
prize_id BIGINT REFERENCES sweepstake_prizes(id) ON DELETE SET NULL,
|
||||
prize_name VARCHAR(255), -- denormalized for safety
|
||||
announced_at TIMESTAMPTZ,
|
||||
notified_user_at TIMESTAMPTZ,
|
||||
notified_admin_at TIMESTAMPTZ,
|
||||
claim_status VARCHAR(16) NOT NULL DEFAULT 'pending', -- pending|claimed|delivered
|
||||
claim_note TEXT,
|
||||
UNIQUE (sweepstake_id, user_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_winners_sweepstake ON sweepstake_winners(sweepstake_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_winners_user ON sweepstake_winners(user_id);
|
||||
@@ -0,0 +1,8 @@
|
||||
-- Add non-physical prize support and winner award tracking
|
||||
ALTER TABLE sweepstake_prizes
|
||||
ADD COLUMN IF NOT EXISTS kind VARCHAR(16) NOT NULL DEFAULT 'physical',
|
||||
ADD COLUMN IF NOT EXISTS points BIGINT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS xp BIGINT NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE sweepstake_winners
|
||||
ADD COLUMN IF NOT EXISTS awarded_at TIMESTAMPTZ;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Remove animated avatar upload unlock from user_profiles
|
||||
ALTER TABLE user_profiles
|
||||
DROP COLUMN IF EXISTS animated_avatar_upload_unlocked;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Add animated avatar upload unlock to user_profiles
|
||||
ALTER TABLE user_profiles
|
||||
ADD COLUMN IF NOT EXISTS animated_avatar_upload_unlocked BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
Reference in New Issue
Block a user