forked from phulin/oy2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproduction_schema.sql
More file actions
229 lines (192 loc) · 7.19 KB
/
Copy pathproduction_schema.sql
File metadata and controls
229 lines (192 loc) · 7.19 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
-- Production schema snapshot for PostgreSQL (generated from migrations-pg).
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
phone TEXT,
phone_verified INTEGER DEFAULT 0,
admin INTEGER DEFAULT 0,
oauth_provider TEXT,
oauth_sub TEXT,
email TEXT
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_username_lower
ON users (LOWER(username));
CREATE INDEX IF NOT EXISTS idx_users_username_trgm
ON users USING GIN (username gin_trgm_ops);
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_oauth
ON users(oauth_provider, oauth_sub)
WHERE oauth_provider IS NOT NULL;
CREATE TABLE IF NOT EXISTS user_last_seen (
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
last_seen INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_user_last_seen_last_seen
ON user_last_seen(last_seen DESC, user_id);
CREATE TABLE IF NOT EXISTS friendships (
user_id INTEGER NOT NULL,
friend_id INTEGER NOT NULL,
nickname TEXT,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
PRIMARY KEY (user_id, friend_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (friend_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_friendships_user
ON friendships(user_id);
CREATE INDEX IF NOT EXISTS idx_friendships_friend_id
ON friendships(friend_id);
CREATE TABLE IF NOT EXISTS last_oy_info (
user_id INTEGER NOT NULL,
friend_id INTEGER NOT NULL,
last_oy_id INTEGER,
last_oy_type TEXT,
last_oy_created_at INTEGER,
last_oy_from_user_id INTEGER,
streak_start_date INTEGER,
PRIMARY KEY (user_id, friend_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (friend_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_last_oy_info_user
ON last_oy_info(user_id);
CREATE TABLE IF NOT EXISTS oys (
id SERIAL PRIMARY KEY,
from_user_id INTEGER NOT NULL,
to_user_id INTEGER NOT NULL,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
type TEXT DEFAULT 'oy',
payload TEXT,
FOREIGN KEY (from_user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (to_user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_oys_to_user
ON oys(to_user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_oys_to_user_created_at_id
ON oys(to_user_id, created_at DESC, id DESC);
CREATE INDEX IF NOT EXISTS idx_oys_from_user_created_at_id
ON oys(from_user_id, created_at DESC, id DESC);
CREATE TABLE IF NOT EXISTS push_subscriptions (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
platform TEXT NOT NULL DEFAULT 'web' CHECK (platform IN ('web', 'ios', 'android')),
endpoint TEXT,
keys_p256dh TEXT,
keys_auth TEXT,
native_token TEXT,
apns_environment TEXT CHECK (apns_environment IN ('sandbox', 'production')),
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
CHECK (
(
platform = 'web' AND
endpoint IS NOT NULL AND
keys_p256dh IS NOT NULL AND
keys_auth IS NOT NULL AND
native_token IS NULL AND
apns_environment IS NULL
) OR (
platform = 'android' AND
native_token IS NOT NULL AND
endpoint IS NULL AND
keys_p256dh IS NULL AND
keys_auth IS NULL AND
apns_environment IS NULL
) OR (
platform = 'ios' AND
native_token IS NOT NULL AND
endpoint IS NULL AND
keys_p256dh IS NULL AND
keys_auth IS NULL
)
),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_push_subscriptions_endpoint
ON push_subscriptions(endpoint)
WHERE endpoint IS NOT NULL;
CREATE UNIQUE INDEX IF NOT EXISTS idx_push_subscriptions_native_token
ON push_subscriptions(native_token)
WHERE native_token IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_push_subscriptions_user
ON push_subscriptions(user_id);
CREATE TABLE IF NOT EXISTS notifications (
id SERIAL PRIMARY KEY,
to_user_id INTEGER NOT NULL,
from_user_id INTEGER NOT NULL,
type TEXT NOT NULL,
payload TEXT NOT NULL,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
FOREIGN KEY (to_user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (from_user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_notifications_to_user
ON notifications(to_user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_notifications_created_at
ON notifications(created_at DESC);
CREATE TABLE IF NOT EXISTS notification_deliveries (
id SERIAL PRIMARY KEY,
notification_id INTEGER NOT NULL,
endpoint TEXT NOT NULL,
attempt INTEGER NOT NULL,
success INTEGER NOT NULL,
status_code INTEGER,
error_message TEXT,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
FOREIGN KEY (notification_id) REFERENCES notifications(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_notification_deliveries_notification
ON notification_deliveries(notification_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_notification_deliveries_created_at
ON notification_deliveries(created_at DESC);
CREATE TABLE IF NOT EXISTS sessions (
token TEXT PRIMARY KEY,
user_id INTEGER NOT NULL,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_sessions_user
ON sessions(user_id);
CREATE TABLE IF NOT EXISTS passkeys (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
credential_id BYTEA NOT NULL UNIQUE,
public_key BYTEA NOT NULL,
counter INTEGER NOT NULL DEFAULT 0,
transports TEXT[],
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
last_used_at INTEGER,
device_name TEXT
);
CREATE INDEX IF NOT EXISTS idx_passkeys_user
ON passkeys(user_id);
CREATE INDEX IF NOT EXISTS idx_passkeys_credential
ON passkeys(credential_id);
CREATE TABLE IF NOT EXISTS user_blocks (
blocker_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
blocked_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
PRIMARY KEY (blocker_user_id, blocked_user_id),
CHECK (blocker_user_id <> blocked_user_id)
);
CREATE INDEX IF NOT EXISTS idx_user_blocks_blocked_user
ON user_blocks(blocked_user_id);
CREATE TABLE IF NOT EXISTS user_reports (
id SERIAL PRIMARY KEY,
reporter_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
target_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
reason TEXT NOT NULL,
details TEXT,
created_at INTEGER DEFAULT EXTRACT(EPOCH FROM NOW())::INTEGER,
status TEXT NOT NULL DEFAULT 'open',
reviewed_by_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
reviewed_at INTEGER,
resolution_note TEXT,
CHECK (reporter_user_id <> target_user_id)
);
CREATE INDEX IF NOT EXISTS idx_user_reports_target_created
ON user_reports(target_user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_user_reports_reporter_created
ON user_reports(reporter_user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_user_reports_status_created
ON user_reports(status, created_at DESC);