gaurv007 commited on
Commit
f89de6b
·
verified ·
1 Parent(s): b9c372e

fix: upload actual schema.sql content — removed hardcoded admin email

Browse files
Files changed (1) hide show
  1. web/lib/supabase/schema.sql +212 -1
web/lib/supabase/schema.sql CHANGED
@@ -1 +1,212 @@
1
- file:/app/web_schema.sql
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -- ClauseGuard — Full Database Schema v3.1
2
+ -- FIX v4.1: Removed hardcoded admin email (was committed to public repo)
3
+ -- Tables ordered by dependency (no forward references)
4
+
5
+ -- ─── 1. Teams (no dependencies) ───
6
+ CREATE TABLE IF NOT EXISTS public.teams (
7
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
8
+ name TEXT NOT NULL,
9
+ owner_id UUID REFERENCES auth.users NOT NULL,
10
+ plan TEXT DEFAULT 'team',
11
+ max_seats INT DEFAULT 5,
12
+ razorpay_subscription_id TEXT,
13
+ created_at TIMESTAMPTZ DEFAULT NOW()
14
+ );
15
+
16
+ -- ─── 2. Profiles (depends on teams) ───
17
+ CREATE TABLE IF NOT EXISTS public.profiles (
18
+ id UUID REFERENCES auth.users ON DELETE CASCADE PRIMARY KEY,
19
+ email TEXT,
20
+ full_name TEXT,
21
+ avatar_url TEXT,
22
+ razorpay_subscription_id TEXT,
23
+ plan TEXT DEFAULT 'free' CHECK (plan IN ('free', 'pro', 'team')),
24
+ role TEXT DEFAULT 'user' CHECK (role IN ('user', 'admin')),
25
+ is_banned BOOLEAN DEFAULT false,
26
+ team_id UUID REFERENCES public.teams(id) ON DELETE SET NULL,
27
+ analyses_this_month INT DEFAULT 0,
28
+ monthly_reset_at TIMESTAMPTZ DEFAULT date_trunc('month', NOW()),
29
+ created_at TIMESTAMPTZ DEFAULT NOW(),
30
+ updated_at TIMESTAMPTZ DEFAULT NOW()
31
+ );
32
+
33
+ -- ─── 3. Team Invites (depends on teams) ───
34
+ CREATE TABLE IF NOT EXISTS public.team_invites (
35
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
36
+ team_id UUID REFERENCES public.teams ON DELETE CASCADE NOT NULL,
37
+ email TEXT NOT NULL,
38
+ role TEXT DEFAULT 'member' CHECK (role IN ('admin', 'member')),
39
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'expired')),
40
+ invited_by UUID REFERENCES auth.users NOT NULL,
41
+ created_at TIMESTAMPTZ DEFAULT NOW(),
42
+ expires_at TIMESTAMPTZ DEFAULT NOW() + INTERVAL '7 days',
43
+ UNIQUE(team_id, email)
44
+ );
45
+
46
+ -- ─── 4. Analyses (depends on profiles, teams) ───
47
+ CREATE TABLE IF NOT EXISTS public.analyses (
48
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
49
+ user_id UUID REFERENCES public.profiles ON DELETE CASCADE NOT NULL,
50
+ team_id UUID REFERENCES public.teams ON DELETE SET NULL,
51
+ source_url TEXT,
52
+ source_type TEXT DEFAULT 'tos' CHECK (source_type IN ('tos', 'contract', 'rental', 'other')),
53
+ total_clauses INT NOT NULL,
54
+ flagged_count INT NOT NULL,
55
+ risk_score INT NOT NULL CHECK (risk_score >= 0 AND risk_score <= 100),
56
+ grade CHAR(1) NOT NULL CHECK (grade IN ('A', 'B', 'C', 'D', 'F')),
57
+ clauses JSONB NOT NULL DEFAULT '[]',
58
+ entities JSONB DEFAULT '[]',
59
+ contradictions JSONB DEFAULT '[]',
60
+ obligations JSONB DEFAULT '[]',
61
+ compliance JSONB DEFAULT '{}',
62
+ raw_text TEXT,
63
+ model TEXT DEFAULT 'regex',
64
+ latency_ms INT DEFAULT 0,
65
+ created_at TIMESTAMPTZ DEFAULT NOW()
66
+ );
67
+
68
+ -- ─── 5. API Keys (depends on profiles, teams) ───
69
+ CREATE TABLE IF NOT EXISTS public.api_keys (
70
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
71
+ user_id UUID REFERENCES public.profiles ON DELETE CASCADE NOT NULL,
72
+ team_id UUID REFERENCES public.teams ON DELETE CASCADE,
73
+ name TEXT NOT NULL,
74
+ key_hash TEXT NOT NULL UNIQUE,
75
+ key_prefix TEXT NOT NULL,
76
+ calls_this_month INT DEFAULT 0,
77
+ calls_limit INT DEFAULT 1000,
78
+ last_used_at TIMESTAMPTZ,
79
+ is_active BOOLEAN DEFAULT true,
80
+ created_at TIMESTAMPTZ DEFAULT NOW()
81
+ );
82
+
83
+ -- ─── 6. Custom Clause Rules (depends on profiles, teams) ───
84
+ CREATE TABLE IF NOT EXISTS public.custom_rules (
85
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
86
+ user_id UUID REFERENCES public.profiles ON DELETE CASCADE,
87
+ team_id UUID REFERENCES public.teams ON DELETE CASCADE,
88
+ name TEXT NOT NULL,
89
+ description TEXT,
90
+ pattern TEXT NOT NULL,
91
+ severity TEXT DEFAULT 'MEDIUM' CHECK (severity IN ('HIGH', 'MEDIUM', 'LOW')),
92
+ category TEXT NOT NULL,
93
+ is_active BOOLEAN DEFAULT true,
94
+ created_at TIMESTAMPTZ DEFAULT NOW(),
95
+ updated_at TIMESTAMPTZ DEFAULT NOW()
96
+ );
97
+
98
+ -- ─── 7. Admin Logs ───
99
+ CREATE TABLE IF NOT EXISTS public.admin_logs (
100
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
101
+ admin_id UUID REFERENCES auth.users NOT NULL,
102
+ action TEXT NOT NULL,
103
+ target_type TEXT,
104
+ target_id TEXT,
105
+ details JSONB,
106
+ created_at TIMESTAMPTZ DEFAULT NOW()
107
+ );
108
+
109
+ -- ─── Indexes ───
110
+ CREATE INDEX IF NOT EXISTS idx_analyses_user_id ON public.analyses(user_id);
111
+ CREATE INDEX IF NOT EXISTS idx_analyses_team_id ON public.analyses(team_id);
112
+ CREATE INDEX IF NOT EXISTS idx_analyses_created_at ON public.analyses(created_at DESC);
113
+ CREATE INDEX IF NOT EXISTS idx_api_keys_key_hash ON public.api_keys(key_hash);
114
+ CREATE INDEX IF NOT EXISTS idx_api_keys_user_id ON public.api_keys(user_id);
115
+ CREATE INDEX IF NOT EXISTS idx_team_invites_email ON public.team_invites(email);
116
+ CREATE INDEX IF NOT EXISTS idx_custom_rules_user_id ON public.custom_rules(user_id);
117
+ CREATE INDEX IF NOT EXISTS idx_custom_rules_team_id ON public.custom_rules(team_id);
118
+ CREATE INDEX IF NOT EXISTS idx_admin_logs_created ON public.admin_logs(created_at DESC);
119
+ CREATE INDEX IF NOT EXISTS idx_profiles_role ON public.profiles(role);
120
+ CREATE INDEX IF NOT EXISTS idx_profiles_email ON public.profiles(email);
121
+
122
+ -- ─── Row Level Security ───
123
+ ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
124
+ ALTER TABLE public.analyses ENABLE ROW LEVEL SECURITY;
125
+ ALTER TABLE public.teams ENABLE ROW LEVEL SECURITY;
126
+ ALTER TABLE public.team_invites ENABLE ROW LEVEL SECURITY;
127
+ ALTER TABLE public.api_keys ENABLE ROW LEVEL SECURITY;
128
+ ALTER TABLE public.custom_rules ENABLE ROW LEVEL SECURITY;
129
+ ALTER TABLE public.admin_logs ENABLE ROW LEVEL SECURITY;
130
+
131
+ -- Profiles
132
+ CREATE POLICY "Users see own profile" ON public.profiles FOR SELECT USING (auth.uid() = id);
133
+ CREATE POLICY "Users update own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id);
134
+ CREATE POLICY "Admins read all profiles" ON public.profiles FOR SELECT USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'admin'));
135
+ CREATE POLICY "Admins update all profiles" ON public.profiles FOR UPDATE USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'admin'));
136
+
137
+ -- Analyses
138
+ CREATE POLICY "Users see own analyses" ON public.analyses FOR SELECT
139
+ USING (auth.uid() = user_id OR team_id IN (SELECT team_id FROM public.profiles WHERE id = auth.uid()));
140
+ CREATE POLICY "Users insert analyses" ON public.analyses FOR INSERT WITH CHECK (auth.uid() = user_id);
141
+ CREATE POLICY "Users delete own analyses" ON public.analyses FOR DELETE USING (auth.uid() = user_id);
142
+ CREATE POLICY "Admins read all analyses" ON public.analyses FOR SELECT USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'admin'));
143
+
144
+ -- Teams
145
+ CREATE POLICY "Team members can view" ON public.teams FOR SELECT
146
+ USING (id IN (SELECT team_id FROM public.profiles WHERE id = auth.uid()) OR owner_id = auth.uid());
147
+ CREATE POLICY "Owner can update team" ON public.teams FOR UPDATE USING (owner_id = auth.uid());
148
+ CREATE POLICY "Admins read all teams" ON public.teams FOR SELECT USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'admin'));
149
+
150
+ -- Team invites
151
+ CREATE POLICY "Members see team invites" ON public.team_invites FOR SELECT
152
+ USING (team_id IN (SELECT team_id FROM public.profiles WHERE id = auth.uid()));
153
+ CREATE POLICY "Users can invite" ON public.team_invites FOR INSERT WITH CHECK (invited_by = auth.uid());
154
+
155
+ -- API Keys
156
+ CREATE POLICY "Users see own API keys" ON public.api_keys FOR SELECT
157
+ USING (user_id = auth.uid() OR team_id IN (SELECT team_id FROM public.profiles WHERE id = auth.uid()));
158
+ CREATE POLICY "Users manage own API keys" ON public.api_keys FOR ALL USING (user_id = auth.uid());
159
+ CREATE POLICY "Admins read all api_keys" ON public.api_keys FOR SELECT USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'admin'));
160
+
161
+ -- Custom Rules
162
+ CREATE POLICY "Users see own rules" ON public.custom_rules FOR SELECT
163
+ USING (user_id = auth.uid() OR team_id IN (SELECT team_id FROM public.profiles WHERE id = auth.uid()));
164
+ CREATE POLICY "Users manage own rules" ON public.custom_rules FOR ALL USING (user_id = auth.uid());
165
+ CREATE POLICY "Admins read all rules" ON public.custom_rules FOR SELECT USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'admin'));
166
+
167
+ -- Admin Logs
168
+ CREATE POLICY "Admins manage logs" ON public.admin_logs FOR ALL
169
+ USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'admin'));
170
+
171
+ -- ─── Auto-create profile on signup ───
172
+ CREATE OR REPLACE FUNCTION public.handle_new_user()
173
+ RETURNS TRIGGER AS $$
174
+ BEGIN
175
+ INSERT INTO public.profiles (id, email, full_name, avatar_url)
176
+ VALUES (
177
+ NEW.id, NEW.email,
178
+ COALESCE(NEW.raw_user_meta_data ->> 'full_name', NEW.raw_user_meta_data ->> 'name', ''),
179
+ COALESCE(NEW.raw_user_meta_data ->> 'avatar_url', NEW.raw_user_meta_data ->> 'picture', '')
180
+ );
181
+ RETURN NEW;
182
+ END;
183
+ $$ LANGUAGE plpgsql SECURITY DEFINER;
184
+
185
+ DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
186
+ CREATE TRIGGER on_auth_user_created
187
+ AFTER INSERT ON auth.users
188
+ FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
189
+
190
+ -- ─── FIX v4.1: Admin setup via environment variable ───
191
+ -- DO NOT hardcode admin emails in source code committed to public repos.
192
+ -- Instead, run this manually after your first signup:
193
+ --
194
+ -- UPDATE public.profiles
195
+ -- SET role = 'admin', plan = 'pro'
196
+ -- WHERE email = '<YOUR_EMAIL>';
197
+ --
198
+ -- Or set ADMIN_EMAIL env var and run:
199
+ -- DO $$ BEGIN
200
+ -- UPDATE public.profiles SET role = 'admin', plan = 'pro'
201
+ -- WHERE email = current_setting('app.admin_email', true);
202
+ -- END $$;
203
+
204
+ -- ─── Monthly reset function ───
205
+ CREATE OR REPLACE FUNCTION public.reset_monthly_usage()
206
+ RETURNS void AS $$
207
+ BEGIN
208
+ UPDATE public.profiles SET analyses_this_month = 0, monthly_reset_at = date_trunc('month', NOW())
209
+ WHERE monthly_reset_at < date_trunc('month', NOW());
210
+ UPDATE public.api_keys SET calls_this_month = 0;
211
+ END;
212
+ $$ LANGUAGE plpgsql SECURITY DEFINER;