-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathschema-postgres.sql
More file actions
196 lines (180 loc) · 6.31 KB
/
schema-postgres.sql
File metadata and controls
196 lines (180 loc) · 6.31 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
-- ============================================================
-- MERCHANT DATABASE SCHEMA (Postgres)
-- Use this if you need to scale beyond D1
-- Run: psql $DATABASE_URL < schema-postgres.sql
-- ============================================================
-- Stores
CREATE TABLE stores (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'enabled' CHECK (status IN ('disabled', 'enabled')),
stripe_secret_key TEXT,
stripe_webhook_secret TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- API Keys
CREATE TABLE api_keys (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
key_hash TEXT NOT NULL UNIQUE,
key_prefix TEXT NOT NULL,
role TEXT NOT NULL CHECK (role IN ('public', 'admin')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Products
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
title TEXT NOT NULL,
description TEXT DEFAULT '',
image_url TEXT,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'draft')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Variants (SKUs)
CREATE TABLE variants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES products(id),
store_id UUID NOT NULL REFERENCES stores(id),
sku TEXT NOT NULL,
title TEXT NOT NULL,
price_cents INTEGER NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
weight_g INTEGER NOT NULL,
dims_cm JSONB,
image_url TEXT,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'draft')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Inventory
CREATE TABLE inventory (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
sku TEXT NOT NULL,
on_hand INTEGER NOT NULL DEFAULT 0,
reserved INTEGER NOT NULL DEFAULT 0,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(store_id, sku)
);
-- Inventory Logs
CREATE TABLE inventory_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
sku TEXT NOT NULL,
delta INTEGER NOT NULL,
reason TEXT NOT NULL CHECK (reason IN ('restock', 'correction', 'damaged', 'return', 'sale', 'release')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Carts
CREATE TABLE carts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'checked_out', 'expired')),
customer_email TEXT NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
stripe_checkout_session_id TEXT,
discount_code TEXT,
discount_id UUID REFERENCES discounts(id),
discount_amount_cents INTEGER DEFAULT 0,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Cart Items
CREATE TABLE cart_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cart_id UUID NOT NULL REFERENCES carts(id),
sku TEXT NOT NULL,
title TEXT NOT NULL,
qty INTEGER NOT NULL,
unit_price_cents INTEGER NOT NULL
);
-- Discounts
CREATE TABLE discounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
code TEXT,
type TEXT NOT NULL CHECK (type IN ('percentage', 'fixed_amount')),
value INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive')),
min_purchase_cents INTEGER DEFAULT 0,
max_discount_cents INTEGER,
starts_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
usage_limit INTEGER,
usage_limit_per_customer INTEGER DEFAULT 1,
usage_count INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(store_id, code)
);
-- Orders
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
number TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'paid' CHECK (status IN ('pending', 'paid', 'processing', 'shipped', 'delivered', 'refunded', 'canceled')),
customer_email TEXT NOT NULL,
ship_to JSONB,
subtotal_cents INTEGER NOT NULL,
tax_cents INTEGER NOT NULL,
shipping_cents INTEGER NOT NULL DEFAULT 0,
total_cents INTEGER NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
discount_code TEXT,
discount_id UUID REFERENCES discounts(id),
discount_amount_cents INTEGER DEFAULT 0,
tracking_number TEXT,
tracking_url TEXT,
shipped_at TIMESTAMPTZ,
stripe_checkout_session_id TEXT,
stripe_payment_intent_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Order Items
CREATE TABLE order_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_id UUID NOT NULL REFERENCES orders(id),
sku TEXT NOT NULL,
title TEXT NOT NULL,
qty INTEGER NOT NULL,
unit_price_cents INTEGER NOT NULL
);
-- Refunds
CREATE TABLE refunds (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_id UUID NOT NULL REFERENCES orders(id),
stripe_refund_id TEXT NOT NULL,
amount_cents INTEGER NOT NULL,
status TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Events (webhook deduplication)
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
store_id UUID NOT NULL REFERENCES stores(id),
stripe_event_id TEXT UNIQUE,
type TEXT NOT NULL,
payload JSONB NOT NULL,
processed_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Discount Usage
CREATE TABLE discount_usage (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
discount_id UUID NOT NULL REFERENCES discounts(id),
order_id UUID NOT NULL REFERENCES orders(id),
customer_email TEXT NOT NULL,
discount_amount_cents INTEGER NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Indexes
CREATE INDEX idx_api_keys_hash ON api_keys(key_hash);
CREATE INDEX idx_products_store ON products(store_id);
CREATE INDEX idx_variants_store_sku ON variants(store_id, sku);
CREATE INDEX idx_inventory_store_sku ON inventory(store_id, sku);
CREATE INDEX idx_carts_store ON carts(store_id);
CREATE INDEX idx_carts_expires ON carts(expires_at) WHERE status = 'open';
CREATE INDEX idx_orders_store ON orders(store_id);
CREATE INDEX idx_discounts_store_code ON discounts(store_id, code);
CREATE INDEX idx_discount_usage_order ON discount_usage(order_id);
CREATE INDEX idx_discount_usage_customer ON discount_usage(discount_id, customer_email);