-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsupabase-schema.sql
More file actions
306 lines (262 loc) · 9.97 KB
/
supabase-schema.sql
File metadata and controls
306 lines (262 loc) · 9.97 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
-- Meal Booking System Database Schema
-- Run this SQL in your Supabase SQL Editor
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Create employees table
CREATE TABLE IF NOT EXISTS employees (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
employee_id TEXT UNIQUE NOT NULL,
role TEXT NOT NULL DEFAULT 'employee' CHECK (role IN ('employee', 'admin', 'vendor')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW())
);
-- Create bookings table
CREATE TABLE IF NOT EXISTS bookings (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
employee_id UUID NOT NULL REFERENCES employees(id) ON DELETE CASCADE,
booking_date DATE NOT NULL,
meal_type TEXT NOT NULL CHECK (meal_type IN ('veg', 'non_veg')),
payment_status TEXT NOT NULL DEFAULT 'pending' CHECK (payment_status IN ('pending', 'approved', 'rejected', 'served')),
payment_screenshot_url TEXT,
receipt_number TEXT UNIQUE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
UNIQUE(employee_id, booking_date)
);
-- Create settings table (for future use)
CREATE TABLE IF NOT EXISTS settings (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
key TEXT UNIQUE NOT NULL,
value JSONB NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW())
);
-- Create available_dates table (for admin to control bookable dates)
CREATE TABLE IF NOT EXISTS available_dates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
date DATE UNIQUE NOT NULL,
is_available BOOLEAN NOT NULL DEFAULT true,
is_free_meal BOOLEAN NOT NULL DEFAULT false,
reason TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW())
);
-- Create indexes for better performance
CREATE INDEX IF NOT EXISTS idx_bookings_employee_id ON bookings(employee_id);
CREATE INDEX IF NOT EXISTS idx_bookings_booking_date ON bookings(booking_date);
CREATE INDEX IF NOT EXISTS idx_bookings_payment_status ON bookings(payment_status);
CREATE INDEX IF NOT EXISTS idx_employees_email ON employees(email);
CREATE INDEX IF NOT EXISTS idx_available_dates_date ON available_dates(date);
CREATE INDEX IF NOT EXISTS idx_available_dates_is_available ON available_dates(is_available);
-- Create updated_at trigger function
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = TIMEZONE('utc', NOW());
RETURN NEW;
END;
$$ language 'plpgsql';
-- Create trigger for bookings table
DROP TRIGGER IF EXISTS update_bookings_updated_at ON bookings;
CREATE TRIGGER update_bookings_updated_at
BEFORE UPDATE ON bookings
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Create trigger for settings table
DROP TRIGGER IF EXISTS update_settings_updated_at ON settings;
CREATE TRIGGER update_settings_updated_at
BEFORE UPDATE ON settings
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Create trigger for available_dates table
DROP TRIGGER IF EXISTS update_available_dates_updated_at ON available_dates;
CREATE TRIGGER update_available_dates_updated_at
BEFORE UPDATE ON available_dates
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- =====================================================
-- ROW LEVEL SECURITY (RLS) POLICIES
-- =====================================================
-- Enable RLS on all tables
ALTER TABLE employees ENABLE ROW LEVEL SECURITY;
ALTER TABLE bookings ENABLE ROW LEVEL SECURITY;
ALTER TABLE settings ENABLE ROW LEVEL SECURITY;
ALTER TABLE available_dates ENABLE ROW LEVEL SECURITY;
-- =====================================================
-- EMPLOYEES TABLE POLICIES
-- =====================================================
-- Allow users to read their own profile
CREATE POLICY "Users can view their own profile"
ON employees FOR SELECT
USING (auth.uid() = id);
-- Allow admins to view all profiles
CREATE POLICY "Admins can view all profiles"
ON employees FOR SELECT
USING (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role = 'admin'
)
);
-- Allow users to update their own profile (limited fields)
CREATE POLICY "Users can update their own profile"
ON employees FOR UPDATE
USING (auth.uid() = id)
WITH CHECK (auth.uid() = id);
-- Allow admins to update any profile
CREATE POLICY "Admins can update any profile"
ON employees FOR UPDATE
USING (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role = 'admin'
)
);
-- Allow new users to insert their profile (triggered by auth.users)
CREATE POLICY "Users can insert their own profile"
ON employees FOR INSERT
WITH CHECK (auth.uid() = id);
-- =====================================================
-- BOOKINGS TABLE POLICIES
-- =====================================================
-- Allow users to view their own bookings
CREATE POLICY "Users can view their own bookings"
ON bookings FOR SELECT
USING (employee_id = auth.uid());
-- Allow admins and vendors to view all bookings
CREATE POLICY "Admins and vendors can view all bookings"
ON bookings FOR SELECT
USING (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role IN ('admin', 'vendor')
)
);
-- Allow users to create their own bookings
CREATE POLICY "Users can create their own bookings"
ON bookings FOR INSERT
WITH CHECK (employee_id = auth.uid());
-- Allow users to update their own pending bookings (for edit/resubmit)
CREATE POLICY "Users can update their own pending bookings"
ON bookings FOR UPDATE
USING (employee_id = auth.uid() AND payment_status = 'pending')
WITH CHECK (employee_id = auth.uid());
-- Allow users to delete their own pending bookings
CREATE POLICY "Users can delete their own pending bookings"
ON bookings FOR DELETE
USING (employee_id = auth.uid() AND payment_status = 'pending');
-- Allow admins to update any booking
CREATE POLICY "Admins can update any booking"
ON bookings FOR UPDATE
USING (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role = 'admin'
)
);
-- Allow vendors to update booking status (mark as served)
CREATE POLICY "Vendors can update booking status"
ON bookings FOR UPDATE
USING (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role = 'vendor'
)
)
WITH CHECK (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role = 'vendor'
)
);
-- =====================================================
-- SETTINGS TABLE POLICIES
-- =====================================================
-- Allow everyone to read settings
CREATE POLICY "Everyone can view settings"
ON settings FOR SELECT
USING (true);
-- Only admins can modify settings
CREATE POLICY "Only admins can modify settings"
ON settings FOR ALL
USING (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role = 'admin'
)
);
-- =====================================================
-- AVAILABLE_DATES TABLE POLICIES
-- =====================================================
-- Drop existing policies if they exist
DROP POLICY IF EXISTS "Everyone can view available dates" ON available_dates;
DROP POLICY IF EXISTS "Only admins can modify available dates" ON available_dates;
-- Allow everyone to read available dates
CREATE POLICY "Everyone can view available dates"
ON available_dates FOR SELECT
USING (true);
-- Only admins can modify available dates
CREATE POLICY "Only admins can modify available dates"
ON available_dates FOR ALL
USING (
EXISTS (
SELECT 1 FROM employees
WHERE id = auth.uid() AND role = 'admin'
)
);
-- =====================================================
-- STORAGE BUCKET SETUP
-- =====================================================
-- Create storage bucket for payment screenshots
-- Run this in the Supabase Dashboard Storage section:
-- 1. Create a new bucket named "bookings"
-- 2. Set it to private (not public)
-- 3. Apply the following policies:
-- Storage Policy: Allow authenticated users to upload their payment screenshots
-- INSERT policy:
-- CREATE POLICY "Users can upload payment screenshots"
-- ON storage.objects FOR INSERT
-- WITH CHECK (
-- bucket_id = 'bookings' AND
-- auth.role() = 'authenticated'
-- );
-- Storage Policy: Allow users to view their own screenshots, admins to view all
-- SELECT policy:
-- CREATE POLICY "Users can view payment screenshots"
-- ON storage.objects FOR SELECT
-- USING (
-- bucket_id = 'bookings' AND
-- (auth.role() = 'authenticated')
-- );
-- =====================================================
-- HELPER FUNCTIONS
-- =====================================================
-- Function to automatically create employee profile on signup
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.employees (id, email, name, employee_id, role)
VALUES (
NEW.id,
NEW.email,
COALESCE(NEW.raw_user_meta_data->>'name', 'User'),
COALESCE(NEW.raw_user_meta_data->>'employee_id', 'EMP' || SUBSTR(NEW.id::TEXT, 1, 8)),
'employee'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Trigger to create employee profile on user signup
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
-- =====================================================
-- SAMPLE DATA (OPTIONAL - FOR TESTING)
-- =====================================================
-- Note: You'll need to create actual auth users first, then update this with real UUIDs
-- This is just for reference
-- INSERT INTO employees (id, email, name, employee_id, role) VALUES
-- ('your-admin-uuid', 'admin@yourcompany.com', 'Admin User', 'EMP001', 'admin'),
-- ('your-vendor-uuid', 'vendor@yourcompany.com', 'Vendor User', 'VENDOR001', 'vendor');