this repo has no description
1CREATE TYPE notification_channel AS ENUM ('email', 'discord', 'telegram', 'signal');
2CREATE TYPE notification_status AS ENUM ('pending', 'processing', 'sent', 'failed');
3CREATE TYPE notification_type AS ENUM (
4 'welcome',
5 'email_verification',
6 'password_reset',
7 'email_update',
8 'account_deletion',
9 'admin_email',
10 'plc_operation',
11 'two_factor_code'
12);
13
14CREATE TABLE IF NOT EXISTS users (
15 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
16 handle TEXT NOT NULL UNIQUE,
17 email TEXT UNIQUE,
18 did TEXT NOT NULL UNIQUE,
19 password_hash TEXT NOT NULL,
20 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
21 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
22
23 deactivated_at TIMESTAMPTZ,
24 invites_disabled BOOLEAN DEFAULT FALSE,
25 takedown_ref TEXT,
26
27 preferred_notification_channel notification_channel NOT NULL DEFAULT 'email',
28
29 password_reset_code TEXT,
30 password_reset_code_expires_at TIMESTAMPTZ,
31
32 email_pending_verification TEXT,
33 email_confirmation_code TEXT,
34 email_confirmation_code_expires_at TIMESTAMPTZ,
35 email_confirmed BOOLEAN NOT NULL DEFAULT FALSE,
36
37 two_factor_enabled BOOLEAN NOT NULL DEFAULT FALSE,
38
39 discord_id TEXT,
40 discord_verified BOOLEAN NOT NULL DEFAULT FALSE,
41
42 telegram_username TEXT,
43 telegram_verified BOOLEAN NOT NULL DEFAULT FALSE,
44
45 signal_number TEXT,
46 signal_verified BOOLEAN NOT NULL DEFAULT FALSE
47);
48
49CREATE INDEX IF NOT EXISTS idx_users_password_reset_code ON users(password_reset_code) WHERE password_reset_code IS NOT NULL;
50CREATE INDEX IF NOT EXISTS idx_users_email_confirmation_code ON users(email_confirmation_code) WHERE email_confirmation_code IS NOT NULL;
51CREATE INDEX IF NOT EXISTS idx_users_discord_id ON users(discord_id) WHERE discord_id IS NOT NULL;
52CREATE INDEX IF NOT EXISTS idx_users_telegram_username ON users(telegram_username) WHERE telegram_username IS NOT NULL;
53CREATE INDEX IF NOT EXISTS idx_users_signal_number ON users(signal_number) WHERE signal_number IS NOT NULL;
54
55CREATE TABLE IF NOT EXISTS invite_codes (
56 code TEXT PRIMARY KEY,
57 available_uses INT NOT NULL DEFAULT 1,
58 created_by_user UUID NOT NULL REFERENCES users(id),
59 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
60 disabled BOOLEAN DEFAULT FALSE
61);
62
63CREATE TABLE IF NOT EXISTS invite_code_uses (
64 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
65 code TEXT NOT NULL REFERENCES invite_codes(code),
66 used_by_user UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
67 used_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
68 UNIQUE(code, used_by_user)
69);
70
71CREATE TABLE IF NOT EXISTS user_keys (
72 user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
73 key_bytes BYTEA NOT NULL,
74 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
75 encrypted_at TIMESTAMPTZ,
76 encryption_version INTEGER DEFAULT 0
77);
78
79CREATE TABLE IF NOT EXISTS repos (
80 user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
81 repo_root_cid TEXT NOT NULL,
82 repo_rev TEXT,
83 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
84 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
85);
86
87CREATE TABLE IF NOT EXISTS blocks (
88 cid BYTEA PRIMARY KEY,
89 data BYTEA NOT NULL,
90 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
91);
92
93CREATE TABLE IF NOT EXISTS records (
94 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
95 repo_id UUID NOT NULL REFERENCES repos(user_id) ON DELETE CASCADE,
96 collection TEXT NOT NULL,
97 rkey TEXT NOT NULL,
98 record_cid TEXT NOT NULL,
99 takedown_ref TEXT,
100 repo_rev TEXT,
101 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
102 UNIQUE(repo_id, collection, rkey)
103);
104
105CREATE INDEX idx_records_repo_rev ON records(repo_rev);
106
107CREATE TABLE IF NOT EXISTS blobs (
108 cid TEXT PRIMARY KEY,
109 mime_type TEXT NOT NULL,
110 size_bytes BIGINT NOT NULL,
111 created_by_user UUID NOT NULL REFERENCES users(id),
112 storage_key TEXT NOT NULL,
113 takedown_ref TEXT,
114 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
115);
116
117CREATE TABLE IF NOT EXISTS app_passwords (
118 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
119 user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
120 name TEXT NOT NULL,
121 password_hash TEXT NOT NULL,
122 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
123 privileged BOOLEAN NOT NULL DEFAULT FALSE,
124 UNIQUE(user_id, name)
125);
126
127CREATE TABLE reports (
128 id BIGINT PRIMARY KEY,
129 reason_type TEXT NOT NULL,
130 reason TEXT,
131 subject_json JSONB NOT NULL,
132 reported_by_did TEXT NOT NULL,
133 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
134);
135
136CREATE TABLE IF NOT EXISTS account_deletion_requests (
137 token TEXT PRIMARY KEY,
138 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
139 expires_at TIMESTAMPTZ NOT NULL,
140 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
141);
142
143CREATE TABLE IF NOT EXISTS notification_queue (
144 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
145 user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
146 channel notification_channel NOT NULL DEFAULT 'email',
147 notification_type notification_type NOT NULL,
148 status notification_status NOT NULL DEFAULT 'pending',
149 recipient TEXT NOT NULL,
150 subject TEXT,
151 body TEXT NOT NULL,
152 metadata JSONB,
153 attempts INT NOT NULL DEFAULT 0,
154 max_attempts INT NOT NULL DEFAULT 3,
155 last_error TEXT,
156 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
157 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
158 scheduled_for TIMESTAMPTZ NOT NULL DEFAULT NOW(),
159 processed_at TIMESTAMPTZ
160);
161
162CREATE INDEX idx_notification_queue_status_scheduled
163 ON notification_queue(status, scheduled_for)
164 WHERE status = 'pending';
165
166CREATE INDEX idx_notification_queue_user_id ON notification_queue(user_id);
167
168CREATE TABLE IF NOT EXISTS reserved_signing_keys (
169 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
170 did TEXT,
171 public_key_did_key TEXT NOT NULL,
172 private_key_bytes BYTEA NOT NULL,
173 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
174 expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '24 hours',
175 used_at TIMESTAMPTZ
176);
177
178CREATE INDEX IF NOT EXISTS idx_reserved_signing_keys_did ON reserved_signing_keys(did) WHERE did IS NOT NULL;
179CREATE INDEX IF NOT EXISTS idx_reserved_signing_keys_expires ON reserved_signing_keys(expires_at) WHERE used_at IS NULL;
180
181CREATE TABLE repo_seq (
182 seq BIGSERIAL PRIMARY KEY,
183 did TEXT NOT NULL,
184 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
185 event_type TEXT NOT NULL,
186 commit_cid TEXT,
187 prev_cid TEXT,
188 ops JSONB,
189 blobs TEXT[],
190 blocks_cids TEXT[]
191);
192
193CREATE INDEX idx_repo_seq_seq ON repo_seq(seq);
194CREATE INDEX idx_repo_seq_did ON repo_seq(did);
195
196CREATE TABLE IF NOT EXISTS session_tokens (
197 id SERIAL PRIMARY KEY,
198 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
199 access_jti TEXT NOT NULL UNIQUE,
200 refresh_jti TEXT NOT NULL UNIQUE,
201 access_expires_at TIMESTAMPTZ NOT NULL,
202 refresh_expires_at TIMESTAMPTZ NOT NULL,
203 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
204 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
205);
206
207CREATE INDEX idx_session_tokens_did ON session_tokens(did);
208CREATE INDEX idx_session_tokens_access_jti ON session_tokens(access_jti);
209CREATE INDEX idx_session_tokens_refresh_jti ON session_tokens(refresh_jti);
210
211CREATE TABLE IF NOT EXISTS used_refresh_tokens (
212 refresh_jti TEXT PRIMARY KEY,
213 session_id INTEGER NOT NULL REFERENCES session_tokens(id) ON DELETE CASCADE,
214 used_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
215);
216
217CREATE INDEX idx_used_refresh_tokens_session_id ON used_refresh_tokens(session_id);
218
219CREATE TABLE IF NOT EXISTS oauth_device (
220 id TEXT PRIMARY KEY,
221 session_id TEXT NOT NULL UNIQUE,
222 user_agent TEXT,
223 ip_address TEXT NOT NULL,
224 last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
225);
226
227CREATE TABLE IF NOT EXISTS oauth_authorization_request (
228 id TEXT PRIMARY KEY,
229 did TEXT REFERENCES users(did) ON DELETE CASCADE,
230 device_id TEXT REFERENCES oauth_device(id) ON DELETE SET NULL,
231 client_id TEXT NOT NULL,
232 client_auth JSONB,
233 parameters JSONB NOT NULL,
234 expires_at TIMESTAMPTZ NOT NULL,
235 code TEXT UNIQUE
236);
237
238CREATE INDEX idx_oauth_auth_request_expires ON oauth_authorization_request(expires_at);
239CREATE INDEX idx_oauth_auth_request_code ON oauth_authorization_request(code) WHERE code IS NOT NULL;
240
241CREATE TABLE IF NOT EXISTS oauth_token (
242 id SERIAL PRIMARY KEY,
243 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
244 token_id TEXT NOT NULL UNIQUE,
245 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
246 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
247 expires_at TIMESTAMPTZ NOT NULL,
248 client_id TEXT NOT NULL,
249 client_auth JSONB NOT NULL,
250 device_id TEXT REFERENCES oauth_device(id) ON DELETE SET NULL,
251 parameters JSONB NOT NULL,
252 details JSONB,
253 code TEXT UNIQUE,
254 current_refresh_token TEXT UNIQUE,
255 scope TEXT
256);
257
258CREATE INDEX idx_oauth_token_did ON oauth_token(did);
259CREATE INDEX idx_oauth_token_code ON oauth_token(code) WHERE code IS NOT NULL;
260
261CREATE TABLE IF NOT EXISTS oauth_account_device (
262 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
263 device_id TEXT NOT NULL REFERENCES oauth_device(id) ON DELETE CASCADE,
264 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
265 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
266 PRIMARY KEY (did, device_id)
267);
268
269CREATE TABLE IF NOT EXISTS oauth_authorized_client (
270 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
271 client_id TEXT NOT NULL,
272 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
273 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
274 data JSONB NOT NULL,
275 PRIMARY KEY (did, client_id)
276);
277
278CREATE TABLE IF NOT EXISTS oauth_used_refresh_token (
279 refresh_token TEXT PRIMARY KEY,
280 token_id INTEGER NOT NULL REFERENCES oauth_token(id) ON DELETE CASCADE
281);
282
283CREATE TABLE oauth_dpop_jti (
284 jti TEXT PRIMARY KEY,
285 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
286);
287
288CREATE INDEX idx_oauth_dpop_jti_created_at ON oauth_dpop_jti(created_at);
289
290CREATE TABLE plc_operation_tokens (
291 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
292 user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
293 token TEXT NOT NULL UNIQUE,
294 expires_at TIMESTAMPTZ NOT NULL,
295 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
296);
297
298CREATE INDEX idx_plc_op_tokens_user ON plc_operation_tokens(user_id);
299CREATE INDEX idx_plc_op_tokens_expires ON plc_operation_tokens(expires_at);
300
301CREATE TABLE IF NOT EXISTS account_preferences (
302 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
303 user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
304 name TEXT NOT NULL,
305 value_json JSONB NOT NULL,
306 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
307 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
308 UNIQUE(user_id, name)
309);
310
311CREATE INDEX IF NOT EXISTS idx_account_preferences_user_id ON account_preferences(user_id);
312CREATE INDEX IF NOT EXISTS idx_account_preferences_name ON account_preferences(name);
313
314CREATE TABLE oauth_2fa_challenge (
315 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
316 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
317 request_uri TEXT NOT NULL,
318 code TEXT NOT NULL,
319 attempts INTEGER NOT NULL DEFAULT 0,
320 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
321 expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '10 minutes'
322);
323
324CREATE INDEX idx_oauth_2fa_challenge_request_uri ON oauth_2fa_challenge(request_uri);
325CREATE INDEX idx_oauth_2fa_challenge_expires ON oauth_2fa_challenge(expires_at);