-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadmin-schema.sql
More file actions
232 lines (198 loc) · 9 KB
/
Copy pathadmin-schema.sql
File metadata and controls
232 lines (198 loc) · 9 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
-- DevFlow Admin Panel Schema
-- Run this in your Supabase SQL Editor
-- ============================================
-- Add is_admin column to users table
-- ============================================
ALTER TABLE users ADD COLUMN IF NOT EXISTS is_admin BOOLEAN DEFAULT false;
ALTER TABLE users ADD COLUMN IF NOT EXISTS is_suspended BOOLEAN DEFAULT false;
ALTER TABLE users ADD COLUMN IF NOT EXISTS suspended_at TIMESTAMP WITH TIME ZONE;
ALTER TABLE users ADD COLUMN IF NOT EXISTS suspended_reason TEXT;
-- Index for admin users
CREATE INDEX IF NOT EXISTS idx_users_admin ON users(is_admin) WHERE is_admin = true;
-- ============================================
-- TABLE: admin_settings
-- ============================================
CREATE TABLE IF NOT EXISTS admin_settings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
key TEXT UNIQUE NOT NULL,
value JSONB NOT NULL,
category TEXT DEFAULT 'general',
description TEXT,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_by UUID REFERENCES users(id)
);
-- Insert default settings
INSERT INTO admin_settings (key, value, category, description) VALUES
('maintenance_mode', 'false', 'system', 'Enable maintenance mode'),
('allow_signups', 'true', 'auth', 'Allow new user registrations'),
('max_sync_frequency', '"hourly"', 'sync', 'Minimum time between syncs'),
('ai_insights_enabled', 'true', 'features', 'Enable AI insights generation'),
('leaderboard_enabled', 'true', 'features', 'Show public leaderboard')
ON CONFLICT (key) DO NOTHING;
-- RLS for admin_settings
ALTER TABLE admin_settings ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Admins can manage settings" ON admin_settings;
CREATE POLICY "Admins can manage settings" ON admin_settings
FOR ALL USING (
EXISTS (SELECT 1 FROM users WHERE id = auth.uid() AND is_admin = true)
);
-- ============================================
-- TABLE: announcements
-- ============================================
CREATE TABLE IF NOT EXISTS announcements (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
message TEXT NOT NULL,
type TEXT DEFAULT 'info', -- info, warning, success, error
is_active BOOLEAN DEFAULT true,
show_on_dashboard BOOLEAN DEFAULT true,
show_on_landing BOOLEAN DEFAULT false,
starts_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
ends_at TIMESTAMP WITH TIME ZONE,
created_by UUID REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_announcements_active ON announcements(is_active, starts_at, ends_at);
-- RLS for announcements
ALTER TABLE announcements ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Anyone can view active announcements" ON announcements;
CREATE POLICY "Anyone can view active announcements" ON announcements
FOR SELECT USING (is_active = true AND starts_at <= NOW() AND (ends_at IS NULL OR ends_at > NOW()));
DROP POLICY IF EXISTS "Admins can manage announcements" ON announcements;
CREATE POLICY "Admins can manage announcements" ON announcements
FOR ALL USING (
EXISTS (SELECT 1 FROM users WHERE id = auth.uid() AND is_admin = true)
);
-- ============================================
-- TABLE: admin_logs (Audit Trail)
-- ============================================
CREATE TABLE IF NOT EXISTS admin_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
admin_id UUID REFERENCES users(id),
admin_username TEXT,
action TEXT NOT NULL,
target_type TEXT, -- 'user', 'setting', 'announcement', 'system'
target_id UUID,
target_name TEXT,
details JSONB DEFAULT '{}',
ip_address TEXT,
user_agent TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_admin_logs_admin ON admin_logs(admin_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_admin_logs_action ON admin_logs(action, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_admin_logs_target ON admin_logs(target_type, target_id);
-- RLS for admin_logs
ALTER TABLE admin_logs ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Admins can view logs" ON admin_logs;
CREATE POLICY "Admins can view logs" ON admin_logs
FOR SELECT USING (
EXISTS (SELECT 1 FROM users WHERE id = auth.uid() AND is_admin = true)
);
DROP POLICY IF EXISTS "System can insert logs" ON admin_logs;
CREATE POLICY "System can insert logs" ON admin_logs
FOR INSERT WITH CHECK (true);
-- ============================================
-- TABLE: system_metrics
-- ============================================
CREATE TABLE IF NOT EXISTS system_metrics (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
metric_type TEXT NOT NULL, -- 'dau', 'mau', 'signups', 'syncs', 'api_calls', 'errors'
value INTEGER NOT NULL,
date DATE NOT NULL,
hour INTEGER, -- Optional: for hourly metrics
metadata JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(metric_type, date, hour)
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_system_metrics_type_date ON system_metrics(metric_type, date DESC);
-- RLS for system_metrics
ALTER TABLE system_metrics ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Admins can view metrics" ON system_metrics;
CREATE POLICY "Admins can view metrics" ON system_metrics
FOR SELECT USING (
EXISTS (SELECT 1 FROM users WHERE id = auth.uid() AND is_admin = true)
);
DROP POLICY IF EXISTS "System can insert metrics" ON system_metrics;
CREATE POLICY "System can insert metrics" ON system_metrics
FOR INSERT WITH CHECK (true);
-- ============================================
-- TABLE: feature_flags
-- ============================================
CREATE TABLE IF NOT EXISTS feature_flags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT UNIQUE NOT NULL,
description TEXT,
is_enabled BOOLEAN DEFAULT false,
rollout_percentage INTEGER DEFAULT 100,
conditions JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_by UUID REFERENCES users(id)
);
-- Insert default feature flags
INSERT INTO feature_flags (name, description, is_enabled) VALUES
('dark_mode', 'Enable dark mode toggle', true),
('ai_insights', 'Enable AI-powered insights', true),
('team_features', 'Enable team collaboration', false),
('export_data', 'Allow data export to CSV/PDF', true),
('github_actions', 'Track GitHub Actions workflows', false),
('notifications', 'Enable push notifications', false),
('advanced_analytics', 'Show advanced analytics', true)
ON CONFLICT (name) DO NOTHING;
-- RLS for feature_flags
ALTER TABLE feature_flags ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Anyone can read flags" ON feature_flags;
CREATE POLICY "Anyone can read flags" ON feature_flags
FOR SELECT USING (true);
DROP POLICY IF EXISTS "Admins can manage flags" ON feature_flags;
CREATE POLICY "Admins can manage flags" ON feature_flags
FOR ALL USING (
EXISTS (SELECT 1 FROM users WHERE id = auth.uid() AND is_admin = true)
);
-- ============================================
-- HELPER FUNCTIONS
-- ============================================
-- Function to get admin dashboard stats
CREATE OR REPLACE FUNCTION get_admin_stats()
RETURNS JSON AS $$
DECLARE
result JSON;
BEGIN
SELECT json_build_object(
'total_users', (SELECT COUNT(*) FROM users WHERE deleted_at IS NULL),
'active_users', (SELECT COUNT(*) FROM users WHERE last_synced > NOW() - INTERVAL '7 days'),
'suspended_users', (SELECT COUNT(*) FROM users WHERE is_suspended = true),
'total_commits', (SELECT COALESCE(SUM(total_commits), 0) FROM users),
'total_prs', (SELECT COALESCE(SUM(total_prs), 0) FROM users),
'signups_today', (SELECT COUNT(*) FROM users WHERE DATE(created_at) = CURRENT_DATE),
'signups_week', (SELECT COUNT(*) FROM users WHERE created_at > NOW() - INTERVAL '7 days'),
'signups_month', (SELECT COUNT(*) FROM users WHERE created_at > NOW() - INTERVAL '30 days')
) INTO result;
RETURN result;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- ============================================
-- UPDATE TRIGGERS
-- ============================================
DROP TRIGGER IF EXISTS update_admin_settings_updated_at ON admin_settings;
CREATE TRIGGER update_admin_settings_updated_at BEFORE UPDATE ON admin_settings
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
DROP TRIGGER IF EXISTS update_announcements_updated_at ON announcements;
CREATE TRIGGER update_announcements_updated_at BEFORE UPDATE ON announcements
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
DROP TRIGGER IF EXISTS update_feature_flags_updated_at ON feature_flags;
CREATE TRIGGER update_feature_flags_updated_at BEFORE UPDATE ON feature_flags
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- ============================================
-- IMPORTANT: Set yourself as admin!
-- ============================================
-- Replace 'your-github-username' with your actual GitHub username
-- UPDATE users SET is_admin = true WHERE username = 'your-github-username';
-- ============================================
-- COMPLETE!
-- ============================================