-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.sql
More file actions
290 lines (255 loc) · 9.45 KB
/
schema.sql
File metadata and controls
290 lines (255 loc) · 9.45 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
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Users table
CREATE TABLE users (
id UUID PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
phone TEXT,
role TEXT NOT NULL DEFAULT 'customer',
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Addresses table
CREATE TABLE addresses (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
address_line1 TEXT NOT NULL,
address_line2 TEXT,
city TEXT NOT NULL,
state TEXT NOT NULL,
postal_code TEXT NOT NULL,
country TEXT NOT NULL,
is_default BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Categories table
CREATE TABLE categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
description TEXT,
parent_id UUID REFERENCES categories(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Products table
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
description TEXT NOT NULL,
price DECIMAL(10, 2) NOT NULL,
compare_at_price DECIMAL(10, 2),
cost_price DECIMAL(10, 2) NOT NULL,
sku TEXT UNIQUE NOT NULL,
barcode TEXT,
weight DECIMAL(10, 2) NOT NULL,
dimensions JSONB NOT NULL,
inventory_quantity INTEGER NOT NULL DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT true,
category_id UUID NOT NULL REFERENCES categories(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Product images table
CREATE TABLE product_images (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
url TEXT NOT NULL,
alt_text TEXT NOT NULL,
position INTEGER NOT NULL,
is_primary BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Carts table
CREATE TABLE carts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
session_id TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Cart items table
CREATE TABLE cart_items (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
cart_id UUID NOT NULL REFERENCES carts(id) ON DELETE CASCADE,
product_id UUID NOT NULL REFERENCES products(id),
quantity INTEGER NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
UNIQUE(cart_id, product_id)
);
-- Orders table (updated with shipping fields)
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id),
status TEXT NOT NULL DEFAULT 'pending',
total_amount DECIMAL(10, 2) NOT NULL,
subtotal DECIMAL(10, 2) NOT NULL,
tax DECIMAL(10, 2) NOT NULL,
shipping_cost DECIMAL(10, 2) NOT NULL,
discount_amount DECIMAL(10, 2) NOT NULL DEFAULT 0,
stripe_payment_intent_id TEXT,
billing_address_id UUID NOT NULL REFERENCES addresses(id),
shipping_address_id UUID NOT NULL REFERENCES addresses(id),
shipping_method TEXT NOT NULL,
shipping_rate_id TEXT,
carrier TEXT,
label_url TEXT,
shipping_label_created_at TIMESTAMP WITH TIME ZONE,
carrier_account_id TEXT,
tracking_number TEXT,
notes TEXT,
receipt_url TEXT,
payment_method_details JSONB,
dispute_status TEXT,
dispute_reason TEXT,
dispute_evidence JSONB,
dispute_created_at TIMESTAMP WITH TIME ZONE,
dispute_resolved_at TIMESTAMP WITH TIME ZONE,
fraud_warning BOOLEAN DEFAULT false,
fraud_warning_details JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Order items table
CREATE TABLE order_items (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
order_id UUID NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_id UUID NOT NULL REFERENCES products(id),
quantity INTEGER NOT NULL,
unit_price DECIMAL(10, 2) NOT NULL,
total_price DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Shipping events table (new)
CREATE TABLE shipping_events (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
order_id UUID NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
tracking_number TEXT NOT NULL,
carrier TEXT NOT NULL,
status TEXT NOT NULL,
status_details TEXT,
description TEXT,
location TEXT,
event_date TIMESTAMP WITH TIME ZONE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- Function to increment inventory quantity
CREATE OR REPLACE FUNCTION increment_inventory(p_product_id UUID, p_quantity INTEGER)
RETURNS VOID AS $$
BEGIN
UPDATE products
SET inventory_quantity = inventory_quantity + p_quantity,
updated_at = now()
WHERE id = p_product_id;
END;
$$ LANGUAGE plpgsql;
-- RLS (Row Level Security) Policies
-- Enable RLS on all tables
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE addresses ENABLE ROW LEVEL SECURITY;
ALTER TABLE categories ENABLE ROW LEVEL SECURITY;
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
ALTER TABLE product_images ENABLE ROW LEVEL SECURITY;
ALTER TABLE carts ENABLE ROW LEVEL SECURITY;
ALTER TABLE cart_items ENABLE ROW LEVEL SECURITY;
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE order_items ENABLE ROW LEVEL SECURITY;
ALTER TABLE shipping_events ENABLE ROW LEVEL SECURITY;
-- Users table policies
CREATE POLICY "Users can view their own profile" ON users
FOR SELECT USING (auth.uid() = id);
CREATE POLICY "Users can update their own profile" ON users
FOR UPDATE USING (auth.uid() = id);
CREATE POLICY "Admin can view all users" ON users
FOR SELECT USING (auth.jwt() ->> 'role' = 'admin');
-- Addresses table policies
CREATE POLICY "Users can CRUD their own addresses" ON addresses
USING (auth.uid() = user_id);
CREATE POLICY "Admin can view all addresses" ON addresses
FOR SELECT USING (auth.jwt() ->> 'role' = 'admin');
-- Categories table policies
CREATE POLICY "Categories are publicly viewable" ON categories
FOR SELECT USING (true);
CREATE POLICY "Admin can manage categories" ON categories
USING (auth.jwt() ->> 'role' = 'admin');
-- Products table policies
CREATE POLICY "Active products are publicly viewable" ON products
FOR SELECT USING (is_active = true);
CREATE POLICY "Admin can manage products" ON products
USING (auth.jwt() ->> 'role' = 'admin');
-- Product images table policies
CREATE POLICY "Product images are publicly viewable" ON product_images
FOR SELECT USING (true);
CREATE POLICY "Admin can manage product images" ON product_images
USING (auth.jwt() ->> 'role' = 'admin');
-- Carts table policies
CREATE POLICY "Users can manage their own carts" ON carts
USING (
auth.uid() = user_id OR
(user_id IS NULL AND session_id = current_setting('request.headers')::json->>'cart-session-id')
);
CREATE POLICY "Admin can view all carts" ON carts
FOR SELECT USING (auth.jwt() ->> 'role' = 'admin');
-- Cart items table policies
CREATE POLICY "Users can manage their own cart items" ON cart_items
USING (
EXISTS (
SELECT 1 FROM carts
WHERE carts.id = cart_id
AND (
carts.user_id = auth.uid() OR
(carts.user_id IS NULL AND carts.session_id = current_setting('request.headers')::json->>'cart-session-id')
)
)
);
CREATE POLICY "Admin can view all cart items" ON cart_items
FOR SELECT USING (auth.jwt() ->> 'role' = 'admin');
-- Orders table policies
CREATE POLICY "Users can view their own orders" ON orders
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Admin can manage all orders" ON orders
USING (auth.jwt() ->> 'role' = 'admin');
-- Order items table policies
CREATE POLICY "Users can view their own order items" ON order_items
FOR SELECT USING (
EXISTS (
SELECT 1 FROM orders
WHERE orders.id = order_id
AND orders.user_id = auth.uid()
)
);
CREATE POLICY "Admin can manage all order items" ON order_items
USING (auth.jwt() ->> 'role' = 'admin');
-- Shipping events table policies
CREATE POLICY "Users can view their own shipping events" ON shipping_events
FOR SELECT USING (
EXISTS (
SELECT 1 FROM orders
WHERE orders.id = order_id
AND orders.user_id = auth.uid()
)
);
CREATE POLICY "Admin can manage all shipping events" ON shipping_events
USING (auth.jwt() ->> 'role' = 'admin');
-- Create indexes for performance
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_addresses_user_id ON addresses(user_id);
CREATE INDEX idx_products_category_id ON products(category_id);
CREATE INDEX idx_products_is_active ON products(is_active);
CREATE INDEX idx_product_images_product_id ON product_images(product_id);
CREATE INDEX idx_carts_user_id ON carts(user_id);
CREATE INDEX idx_carts_session_id ON carts(session_id);
CREATE INDEX idx_cart_items_cart_id ON cart_items(cart_id);
CREATE INDEX idx_cart_items_product_id ON cart_items(product_id);
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
CREATE INDEX idx_orders_payment_intent_id ON orders(stripe_payment_intent_id);
CREATE INDEX idx_shipping_events_order_id ON shipping_events(order_id);
CREATE INDEX idx_shipping_events_tracking ON shipping_events(tracking_number);