mirror of
https://github.com/pezkuwichain/pezkuwi-telegram-miniapp.git
synced 2026-04-22 05:27:54 +00:00
Initial commit - PezkuwiChain Telegram MiniApp
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
-- Pezkuwi Telegram Mini App Database Schema
|
||||
-- Run this in Supabase SQL Editor
|
||||
|
||||
-- Enable UUID extension
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Users table (synced from Telegram)
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
telegram_id BIGINT UNIQUE NOT NULL,
|
||||
username TEXT,
|
||||
first_name TEXT NOT NULL,
|
||||
last_name TEXT,
|
||||
photo_url TEXT,
|
||||
language_code TEXT DEFAULT 'ku',
|
||||
is_admin BOOLEAN DEFAULT FALSE,
|
||||
wallet_address TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Announcements (admin posts)
|
||||
CREATE TABLE announcements (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
image_url TEXT,
|
||||
link_url TEXT,
|
||||
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
likes INTEGER DEFAULT 0,
|
||||
dislikes INTEGER DEFAULT 0,
|
||||
views INTEGER DEFAULT 0,
|
||||
is_published BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Announcement reactions
|
||||
CREATE TABLE announcement_reactions (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
announcement_id UUID NOT NULL REFERENCES announcements(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
reaction TEXT NOT NULL CHECK (reaction IN ('like', 'dislike')),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE(announcement_id, user_id)
|
||||
);
|
||||
|
||||
-- Forum threads
|
||||
CREATE TABLE threads (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
reply_count INTEGER DEFAULT 0,
|
||||
likes INTEGER DEFAULT 0,
|
||||
views INTEGER DEFAULT 0,
|
||||
last_activity TIMESTAMPTZ DEFAULT NOW(),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Thread likes
|
||||
CREATE TABLE thread_likes (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
thread_id UUID NOT NULL REFERENCES threads(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE(thread_id, user_id)
|
||||
);
|
||||
|
||||
-- Replies to threads
|
||||
CREATE TABLE replies (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
thread_id UUID NOT NULL REFERENCES threads(id) ON DELETE CASCADE,
|
||||
content TEXT NOT NULL,
|
||||
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
likes INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Reply likes
|
||||
CREATE TABLE reply_likes (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
reply_id UUID NOT NULL REFERENCES replies(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE(reply_id, user_id)
|
||||
);
|
||||
|
||||
-- Indexes for performance
|
||||
CREATE INDEX idx_announcements_created_at ON announcements(created_at DESC);
|
||||
CREATE INDEX idx_announcements_author ON announcements(author_id);
|
||||
CREATE INDEX idx_threads_created_at ON threads(created_at DESC);
|
||||
CREATE INDEX idx_threads_last_activity ON threads(last_activity DESC);
|
||||
CREATE INDEX idx_threads_author ON threads(author_id);
|
||||
CREATE INDEX idx_replies_thread ON replies(thread_id);
|
||||
CREATE INDEX idx_replies_author ON replies(author_id);
|
||||
CREATE INDEX idx_users_telegram_id ON users(telegram_id);
|
||||
|
||||
-- Updated at trigger function
|
||||
CREATE OR REPLACE FUNCTION update_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Apply updated_at triggers
|
||||
CREATE TRIGGER update_users_updated_at
|
||||
BEFORE UPDATE ON users
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
CREATE TRIGGER update_announcements_updated_at
|
||||
BEFORE UPDATE ON announcements
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
CREATE TRIGGER update_threads_updated_at
|
||||
BEFORE UPDATE ON threads
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
CREATE TRIGGER update_replies_updated_at
|
||||
BEFORE UPDATE ON replies
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
-- Row Level Security (RLS)
|
||||
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE announcements ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE announcement_reactions ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE threads ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE thread_likes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE replies ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE reply_likes ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- RLS Policies
|
||||
|
||||
-- Users: everyone can read, only self can update
|
||||
CREATE POLICY "Users are viewable by everyone" ON users
|
||||
FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Users can update own profile" ON users
|
||||
FOR UPDATE USING (auth.uid()::text = id::text);
|
||||
|
||||
-- Announcements: everyone can read published
|
||||
CREATE POLICY "Published announcements are viewable" ON announcements
|
||||
FOR SELECT USING (is_published = true);
|
||||
|
||||
CREATE POLICY "Admins can manage announcements" ON announcements
|
||||
FOR ALL USING (
|
||||
EXISTS (SELECT 1 FROM users WHERE id::text = auth.uid()::text AND is_admin = true)
|
||||
);
|
||||
|
||||
-- Announcement reactions: authenticated users
|
||||
CREATE POLICY "Anyone can view reactions" ON announcement_reactions
|
||||
FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can react" ON announcement_reactions
|
||||
FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);
|
||||
|
||||
CREATE POLICY "Users can manage own reactions" ON announcement_reactions
|
||||
FOR DELETE USING (user_id::text = auth.uid()::text);
|
||||
|
||||
-- Threads: everyone can read
|
||||
CREATE POLICY "Threads are viewable by everyone" ON threads
|
||||
FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can create threads" ON threads
|
||||
FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);
|
||||
|
||||
CREATE POLICY "Authors can update own threads" ON threads
|
||||
FOR UPDATE USING (author_id::text = auth.uid()::text);
|
||||
|
||||
CREATE POLICY "Authors and admins can delete threads" ON threads
|
||||
FOR DELETE USING (
|
||||
author_id::text = auth.uid()::text OR
|
||||
EXISTS (SELECT 1 FROM users WHERE id::text = auth.uid()::text AND is_admin = true)
|
||||
);
|
||||
|
||||
-- Thread likes
|
||||
CREATE POLICY "Anyone can view thread likes" ON thread_likes
|
||||
FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can like threads" ON thread_likes
|
||||
FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);
|
||||
|
||||
CREATE POLICY "Users can remove own likes" ON thread_likes
|
||||
FOR DELETE USING (user_id::text = auth.uid()::text);
|
||||
|
||||
-- Replies
|
||||
CREATE POLICY "Replies are viewable by everyone" ON replies
|
||||
FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can create replies" ON replies
|
||||
FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);
|
||||
|
||||
CREATE POLICY "Authors can update own replies" ON replies
|
||||
FOR UPDATE USING (author_id::text = auth.uid()::text);
|
||||
|
||||
CREATE POLICY "Authors and admins can delete replies" ON replies
|
||||
FOR DELETE USING (
|
||||
author_id::text = auth.uid()::text OR
|
||||
EXISTS (SELECT 1 FROM users WHERE id::text = auth.uid()::text AND is_admin = true)
|
||||
);
|
||||
|
||||
-- Reply likes
|
||||
CREATE POLICY "Anyone can view reply likes" ON reply_likes
|
||||
FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can like replies" ON reply_likes
|
||||
FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);
|
||||
|
||||
CREATE POLICY "Users can remove own reply likes" ON reply_likes
|
||||
FOR DELETE USING (user_id::text = auth.uid()::text);
|
||||
Reference in New Issue
Block a user