-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsupabase-posts-schema.sql
More file actions
183 lines (146 loc) · 6.65 KB
/
supabase-posts-schema.sql
File metadata and controls
183 lines (146 loc) · 6.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
-- ============================================
-- POSTS TABLE - Native social posting with storytelling
-- ============================================
-- Posts table for photos, thoughts, and GIFs
CREATE TABLE IF NOT EXISTS posts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
creator_id UUID REFERENCES creators(id) ON DELETE CASCADE,
creator_did TEXT NOT NULL,
-- Content
text_content TEXT, -- The story/caption/thought
media_urls TEXT[], -- Array of image/GIF URLs
media_types TEXT[], -- Array of media types ('image', 'gif', 'video')
-- Styling & Mood
mood TEXT, -- e.g., 'fierce', 'soft', 'dramatic', 'playful'
background_color TEXT, -- Optional custom background for text-only posts
text_alignment TEXT DEFAULT 'left', -- 'left', 'center', 'right'
-- Metadata
tags TEXT[], -- Hashtags
mentioned_dids TEXT[], -- Tagged creators
location TEXT, -- Optional location
-- Privacy
visibility TEXT DEFAULT 'public' CHECK (visibility IN ('public', 'unlisted', 'private', 'followers-only')),
-- Engagement
likes INTEGER DEFAULT 0,
comment_count INTEGER DEFAULT 0,
repost_count INTEGER DEFAULT 0,
-- Timestamps
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
scheduled_at TIMESTAMPTZ -- For scheduled posts
);
-- ============================================
-- POST COMMENTS
-- ============================================
CREATE TABLE IF NOT EXISTS post_comments (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
creator_id UUID REFERENCES creators(id) ON DELETE CASCADE,
creator_did TEXT NOT NULL,
-- Content
text_content TEXT NOT NULL,
parent_comment_id UUID REFERENCES post_comments(id) ON DELETE CASCADE, -- For threaded replies
-- Engagement
likes INTEGER DEFAULT 0,
-- Timestamps
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================
-- POST LIKES
-- ============================================
CREATE TABLE IF NOT EXISTS post_likes (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
creator_did TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
-- Unique constraint: one like per user per post
UNIQUE(post_id, creator_did)
);
-- ============================================
-- POST REPOSTS/SHARES
-- ============================================
CREATE TABLE IF NOT EXISTS post_reposts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
original_post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
creator_did TEXT NOT NULL,
-- Optional quote/commentary
quote_text TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
-- Unique constraint: one repost per user per post
UNIQUE(original_post_id, creator_did)
);
-- ============================================
-- INDEXES FOR PERFORMANCE
-- ============================================
-- Posts indexes
CREATE INDEX IF NOT EXISTS idx_posts_creator_did ON posts(creator_did);
CREATE INDEX IF NOT EXISTS idx_posts_created_at ON posts(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_posts_visibility ON posts(visibility);
CREATE INDEX IF NOT EXISTS idx_posts_tags ON posts USING GIN(tags);
-- Comments indexes
CREATE INDEX IF NOT EXISTS idx_post_comments_post_id ON post_comments(post_id);
CREATE INDEX IF NOT EXISTS idx_post_comments_created_at ON post_comments(created_at DESC);
-- Likes indexes
CREATE INDEX IF NOT EXISTS idx_post_likes_post_id ON post_likes(post_id);
CREATE INDEX IF NOT EXISTS idx_post_likes_creator_did ON post_likes(creator_did);
-- Reposts indexes
CREATE INDEX IF NOT EXISTS idx_post_reposts_original_post_id ON post_reposts(original_post_id);
CREATE INDEX IF NOT EXISTS idx_post_reposts_creator_did ON post_reposts(creator_did);
-- ============================================
-- RPC FUNCTIONS FOR ATOMIC OPERATIONS
-- ============================================
-- Increment post likes
CREATE OR REPLACE FUNCTION increment_post_likes(post_uuid UUID)
RETURNS void AS $$
BEGIN
UPDATE posts SET likes = likes + 1 WHERE id = post_uuid;
END;
$$ LANGUAGE plpgsql;
-- Decrement post likes
CREATE OR REPLACE FUNCTION decrement_post_likes(post_uuid UUID)
RETURNS void AS $$
BEGIN
UPDATE posts SET likes = GREATEST(0, likes - 1) WHERE id = post_uuid;
END;
$$ LANGUAGE plpgsql;
-- Increment comment count
CREATE OR REPLACE FUNCTION increment_post_comments(post_uuid UUID)
RETURNS void AS $$
BEGIN
UPDATE posts SET comment_count = comment_count + 1 WHERE id = post_uuid;
END;
$$ LANGUAGE plpgsql;
-- Increment repost count
CREATE OR REPLACE FUNCTION increment_post_reposts(post_uuid UUID)
RETURNS void AS $$
BEGIN
UPDATE posts SET repost_count = repost_count + 1 WHERE id = post_uuid;
END;
$$ LANGUAGE plpgsql;
-- ============================================
-- ROW LEVEL SECURITY (RLS)
-- ============================================
-- Enable RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
ALTER TABLE post_comments ENABLE ROW LEVEL SECURITY;
ALTER TABLE post_likes ENABLE ROW LEVEL SECURITY;
ALTER TABLE post_reposts ENABLE ROW LEVEL SECURITY;
-- Posts policies
CREATE POLICY "Posts are viewable by everyone" ON posts FOR SELECT USING (visibility = 'public');
CREATE POLICY "Users can insert their own posts" ON posts FOR INSERT WITH CHECK (true);
CREATE POLICY "Users can update their own posts" ON posts FOR UPDATE USING (creator_did = current_setting('app.current_user_did', true));
CREATE POLICY "Users can delete their own posts" ON posts FOR DELETE USING (creator_did = current_setting('app.current_user_did', true));
-- Comments policies
CREATE POLICY "Comments are viewable by everyone" ON post_comments FOR SELECT USING (true);
CREATE POLICY "Users can insert comments" ON post_comments FOR INSERT WITH CHECK (true);
CREATE POLICY "Users can update their own comments" ON post_comments FOR UPDATE USING (creator_did = current_setting('app.current_user_did', true));
CREATE POLICY "Users can delete their own comments" ON post_comments FOR DELETE USING (creator_did = current_setting('app.current_user_did', true));
-- Likes policies
CREATE POLICY "Likes are viewable by everyone" ON post_likes FOR SELECT USING (true);
CREATE POLICY "Users can like posts" ON post_likes FOR INSERT WITH CHECK (true);
CREATE POLICY "Users can unlike their own likes" ON post_likes FOR DELETE USING (creator_did = current_setting('app.current_user_did', true));
-- Reposts policies
CREATE POLICY "Reposts are viewable by everyone" ON post_reposts FOR SELECT USING (true);
CREATE POLICY "Users can repost" ON post_reposts FOR INSERT WITH CHECK (true);
CREATE POLICY "Users can delete their own reposts" ON post_reposts FOR DELETE USING (creator_did = current_setting('app.current_user_did', true));