-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsupabase-schema.sql
More file actions
340 lines (307 loc) · 14.2 KB
/
Copy pathsupabase-schema.sql
File metadata and controls
340 lines (307 loc) · 14.2 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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
-- ClearPix Database Schema
-- Run this FIRST before seed-data.sql
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- =====================================================
-- PROFILES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS profiles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL UNIQUE,
first_name TEXT,
last_name TEXT,
display_name TEXT,
avatar_url TEXT,
referral_source TEXT,
use_case TEXT,
marketing_data JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- USER CREDITS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS user_credits (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL UNIQUE,
credits INTEGER DEFAULT 5 NOT NULL CHECK (credits >= 0),
total_used INTEGER DEFAULT 0 NOT NULL CHECK (total_used >= 0),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- USER PLANS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS user_plans (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL UNIQUE,
plan TEXT DEFAULT 'free' CHECK (plan IN ('free', 'starter', 'pro', 'studio')),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- ENHANCEMENT CATEGORIES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS enhancement_categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
icon TEXT DEFAULT '✨',
sort_order INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- ENHANCEMENT PROMPTS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS enhancement_prompts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT NOT NULL,
prompt TEXT NOT NULL,
credits INTEGER DEFAULT 1 NOT NULL CHECK (credits > 0),
category_id UUID REFERENCES enhancement_categories(id) ON DELETE CASCADE NOT NULL,
thumbnail_url TEXT,
is_featured BOOLEAN DEFAULT false,
is_active BOOLEAN DEFAULT true,
is_new BOOLEAN DEFAULT false,
new_until TIMESTAMPTZ,
sort_order INTEGER DEFAULT 0,
max_images INTEGER DEFAULT 1 CHECK (max_images > 0),
custom_fields JSONB DEFAULT '[]'::jsonb,
requires_image_upload BOOLEAN DEFAULT true,
requires_face_preservation BOOLEAN DEFAULT false,
preferred_model TEXT DEFAULT 'claude-3-sonnet',
launched_at TIMESTAMPTZ DEFAULT NOW(),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- PROCESSED IMAGES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS processed_images (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
original_url TEXT NOT NULL,
processed_url TEXT,
thumbnail_url TEXT,
enhancement_type TEXT NOT NULL,
prompt TEXT,
credits_used INTEGER DEFAULT 1 NOT NULL,
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'completed', 'failed')),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- USER ENHANCEMENT FAVORITES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS user_enhancement_favorites (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
enhancement_slug TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_id, enhancement_slug)
);
-- =====================================================
-- ADMIN USERS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS admin_users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL UNIQUE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- AI USAGE LOGS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS ai_usage_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
processed_image_id UUID REFERENCES processed_images(id) ON DELETE SET NULL,
operation_type TEXT NOT NULL,
enhancement_type TEXT,
model TEXT NOT NULL,
input_tokens INTEGER DEFAULT 0,
output_tokens INTEGER DEFAULT 0,
total_tokens INTEGER DEFAULT 0,
estimated_cost DECIMAL(10, 6) DEFAULT 0,
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- KNOWLEDGE CATEGORIES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS knowledge_categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT,
icon TEXT DEFAULT '📖',
sort_order INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- KNOWLEDGE ARTICLES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS knowledge_articles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
category_id UUID REFERENCES knowledge_categories(id) ON DELETE CASCADE NOT NULL,
slug TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
summary TEXT,
content_html TEXT NOT NULL,
content_text TEXT,
tags TEXT[] DEFAULT ARRAY[]::TEXT[],
is_published BOOLEAN DEFAULT false,
is_featured BOOLEAN DEFAULT false,
view_count INTEGER DEFAULT 0,
related_enhancement_id UUID REFERENCES enhancement_prompts(id) ON DELETE SET NULL,
published_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- EMAIL TEMPLATES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS email_templates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
template_key TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT,
subject TEXT NOT NULL,
body_html TEXT NOT NULL,
body_text TEXT,
variables JSONB DEFAULT '{}'::jsonb,
trigger_config JSONB DEFAULT '{}'::jsonb,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- APP SETTINGS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS app_settings (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
setting_key TEXT NOT NULL UNIQUE,
setting_value JSONB NOT NULL,
description TEXT,
updated_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- USER NOTIFICATION PREFERENCES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS user_notification_preferences (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL UNIQUE,
email_new_enhancements BOOLEAN DEFAULT true,
email_credits_low BOOLEAN DEFAULT true,
email_weekly_digest BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- SHARE ANALYTICS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS share_analytics (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
processed_image_id UUID REFERENCES processed_images(id) ON DELETE SET NULL,
enhancement_type TEXT NOT NULL,
share_method TEXT NOT NULL CHECK (share_method IN ('download', 'native', 'copy')),
watermark_included BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================
-- INDEXES FOR PERFORMANCE
-- =====================================================
CREATE INDEX IF NOT EXISTS idx_profiles_user_id ON profiles(user_id);
CREATE INDEX IF NOT EXISTS idx_user_credits_user_id ON user_credits(user_id);
CREATE INDEX IF NOT EXISTS idx_user_plans_user_id ON user_plans(user_id);
CREATE INDEX IF NOT EXISTS idx_enhancement_prompts_category_id ON enhancement_prompts(category_id);
CREATE INDEX IF NOT EXISTS idx_enhancement_prompts_slug ON enhancement_prompts(slug);
CREATE INDEX IF NOT EXISTS idx_processed_images_user_id ON processed_images(user_id);
CREATE INDEX IF NOT EXISTS idx_processed_images_status ON processed_images(status);
CREATE INDEX IF NOT EXISTS idx_user_favorites_user_id ON user_enhancement_favorites(user_id);
CREATE INDEX IF NOT EXISTS idx_ai_usage_logs_user_id ON ai_usage_logs(user_id);
CREATE INDEX IF NOT EXISTS idx_knowledge_articles_category_id ON knowledge_articles(category_id);
CREATE INDEX IF NOT EXISTS idx_knowledge_articles_slug ON knowledge_articles(slug);
-- =====================================================
-- ROW LEVEL SECURITY (RLS) POLICIES
-- =====================================================
-- Enable RLS on all tables
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_credits ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_plans ENABLE ROW LEVEL SECURITY;
ALTER TABLE processed_images ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_enhancement_favorites ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_notification_preferences ENABLE ROW LEVEL SECURITY;
-- Profiles policies
CREATE POLICY "Users can view own profile" ON profiles FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can update own profile" ON profiles FOR UPDATE USING (auth.uid() = user_id);
-- User credits policies
CREATE POLICY "Users can view own credits" ON user_credits FOR SELECT USING (auth.uid() = user_id);
-- User plans policies
CREATE POLICY "Users can view own plan" ON user_plans FOR SELECT USING (auth.uid() = user_id);
-- Processed images policies
CREATE POLICY "Users can view own images" ON processed_images FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can insert own images" ON processed_images FOR INSERT WITH CHECK (auth.uid() = user_id);
-- User favorites policies
CREATE POLICY "Users can manage own favorites" ON user_enhancement_favorites FOR ALL USING (auth.uid() = user_id);
-- Notification preferences policies
CREATE POLICY "Users can manage own preferences" ON user_notification_preferences FOR ALL USING (auth.uid() = user_id);
-- Enhancement categories and prompts are public (read-only)
ALTER TABLE enhancement_categories ENABLE ROW LEVEL SECURITY;
ALTER TABLE enhancement_prompts ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can view active categories" ON enhancement_categories FOR SELECT USING (is_active = true);
CREATE POLICY "Anyone can view active prompts" ON enhancement_prompts FOR SELECT USING (is_active = true);
-- Knowledge base is public (read-only)
ALTER TABLE knowledge_categories ENABLE ROW LEVEL SECURITY;
ALTER TABLE knowledge_articles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can view active knowledge categories" ON knowledge_categories FOR SELECT USING (is_active = true);
CREATE POLICY "Anyone can view published articles" ON knowledge_articles FOR SELECT USING (is_published = true);
-- =====================================================
-- FUNCTIONS
-- =====================================================
-- Function to check if user is admin
CREATE OR REPLACE FUNCTION is_admin(_user_id UUID)
RETURNS BOOLEAN AS $$
BEGIN
RETURN EXISTS (
SELECT 1 FROM admin_users WHERE user_id = _user_id
);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Function to get user emails for admin
CREATE OR REPLACE FUNCTION get_user_emails_for_admin()
RETURNS TABLE (user_id UUID, email TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, email::TEXT FROM auth.users;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- =====================================================
-- TRIGGERS FOR UPDATED_AT
-- =====================================================
-- Function to update updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create triggers for tables with updated_at
CREATE TRIGGER update_profiles_updated_at BEFORE UPDATE ON profiles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_user_credits_updated_at BEFORE UPDATE ON user_credits FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_user_plans_updated_at BEFORE UPDATE ON user_plans FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_enhancement_categories_updated_at BEFORE UPDATE ON enhancement_categories FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_enhancement_prompts_updated_at BEFORE UPDATE ON enhancement_prompts FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_processed_images_updated_at BEFORE UPDATE ON processed_images FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_knowledge_categories_updated_at BEFORE UPDATE ON knowledge_categories FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_knowledge_articles_updated_at BEFORE UPDATE ON knowledge_articles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_email_templates_updated_at BEFORE UPDATE ON email_templates FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_user_notification_preferences_updated_at BEFORE UPDATE ON user_notification_preferences FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();