-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsupabase_moderator_schema.sql
More file actions
148 lines (129 loc) · 5.36 KB
/
supabase_moderator_schema.sql
File metadata and controls
148 lines (129 loc) · 5.36 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
-- =============================================================================
-- Supabase Schema: Moderator Applications
--
-- Tables:
-- 1. moderator_applications — stores all moderator access requests
-- 2. Updates to existing 'users' table — adds 'role' column if missing
--
-- Designed to mirror the Firebase Firestore schema exactly.
-- =============================================================================
-- ─── 1. Ensure users table has a 'role' column ─────────────────────────────
-- If your Supabase 'users' table already exists, add the role column:
ALTER TABLE users ADD COLUMN IF NOT EXISTS role TEXT DEFAULT NULL;
-- Create an index on role for efficient lookups
CREATE INDEX IF NOT EXISTS idx_users_role ON users (role);
-- ─── 2. Moderator Applications Table ────────────────────────────────────────
CREATE TABLE IF NOT EXISTS moderator_applications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
applicant_uid TEXT NOT NULL UNIQUE, -- Firebase Auth UID (one application per user)
applicant_email TEXT NOT NULL,
applicant_name TEXT NOT NULL,
applicant_photo_url TEXT,
reason TEXT NOT NULL,
experience TEXT DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'approved', 'rejected')),
reviewed_by TEXT, -- Admin UID who reviewed
reviewed_at TIMESTAMPTZ,
review_note TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Indexes for common query patterns
CREATE INDEX IF NOT EXISTS idx_mod_apps_status ON moderator_applications (status);
CREATE INDEX IF NOT EXISTS idx_mod_apps_applicant ON moderator_applications (applicant_uid);
CREATE INDEX IF NOT EXISTS idx_mod_apps_created ON moderator_applications (created_at DESC);
-- ─── 3. Row Level Security (RLS) ────────────────────────────────────────────
ALTER TABLE moderator_applications ENABLE ROW LEVEL SECURITY;
-- Policy: Applicants can read their own application
CREATE POLICY "Users can read own application"
ON moderator_applications
FOR SELECT
USING (auth.uid()::TEXT = applicant_uid);
-- Policy: Admins can read all applications
CREATE POLICY "Admins can read all applications"
ON moderator_applications
FOR SELECT
USING (
EXISTS (
SELECT 1 FROM users
WHERE users.id::TEXT = auth.uid()::TEXT
AND users.role = 'admin'
)
);
-- Policy: Authenticated users can insert their own application
CREATE POLICY "Users can create own application"
ON moderator_applications
FOR INSERT
WITH CHECK (
auth.uid()::TEXT = applicant_uid
AND status = 'pending'
);
-- Policy: Only admins can update applications (approve/reject)
CREATE POLICY "Admins can update applications"
ON moderator_applications
FOR UPDATE
USING (
EXISTS (
SELECT 1 FROM users
WHERE users.id::TEXT = auth.uid()::TEXT
AND users.role = 'admin'
)
);
-- Policy: Only admins can delete applications
CREATE POLICY "Admins can delete applications"
ON moderator_applications
FOR DELETE
USING (
EXISTS (
SELECT 1 FROM users
WHERE users.id::TEXT = auth.uid()::TEXT
AND users.role = 'admin'
)
);
-- ─── 4. Auto-update trigger for updated_at ──────────────────────────────────
CREATE OR REPLACE FUNCTION update_moderator_applications_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_moderator_applications_updated_at
BEFORE UPDATE ON moderator_applications
FOR EACH ROW
EXECUTE FUNCTION update_moderator_applications_updated_at();
-- ─── 5. Seed Data ───────────────────────────────────────────────────────────
INSERT INTO moderator_applications
(applicant_uid, applicant_email, applicant_name, reason, experience, status, created_at)
VALUES
(
'sample-user-uid-001',
'priya.sharma@example.com',
'Priya Sharma',
'I am a child rights advocate and social worker with 5 years of experience.',
'Worked with UNICEF India as a field volunteer.',
'pending',
'2026-02-15T10:30:00Z'
),
(
'sample-user-uid-002',
'rahul.gupta@example.com',
'Rahul Gupta',
'As a teacher in a government school, I frequently educate children about safety.',
'Primary school teacher for 8 years. Conducted over 100 child safety workshops.',
'approved',
'2026-02-14T08:00:00Z'
),
(
'sample-user-uid-003',
'anita.desai@example.com',
'Anita Desai',
'I am passionate about children welfare and want to contribute.',
'NGO volunteer for 3 years. Social media content moderator at a child helpline.',
'rejected',
'2026-02-13T16:45:00Z'
)
ON CONFLICT (applicant_uid) DO NOTHING;
-- Done!
-- ═══════════════════════════════════════════════════════════════════════════