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);
11
12CREATE TABLE IF NOT EXISTS users (
13 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
14 handle TEXT NOT NULL UNIQUE,
15 email TEXT NOT NULL UNIQUE,
16 did TEXT NOT NULL UNIQUE,
17 password_hash TEXT NOT NULL,
18 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
19 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
20
21 deactivated_at TIMESTAMPTZ,
22 invites_disabled BOOLEAN DEFAULT FALSE,
23 takedown_ref TEXT,
24
25 preferred_notification_channel notification_channel NOT NULL DEFAULT 'email',
26
27 password_reset_code TEXT,
28 password_reset_code_expires_at TIMESTAMPTZ,
29
30 email_pending_verification TEXT,
31 email_confirmation_code TEXT,
32 email_confirmation_code_expires_at TIMESTAMPTZ
33);
34
35CREATE INDEX IF NOT EXISTS idx_users_password_reset_code ON users(password_reset_code) WHERE password_reset_code IS NOT NULL;
36CREATE INDEX IF NOT EXISTS idx_users_email_confirmation_code ON users(email_confirmation_code) WHERE email_confirmation_code IS NOT NULL;
37
38CREATE TABLE IF NOT EXISTS invite_codes (
39 code TEXT PRIMARY KEY,
40 available_uses INT NOT NULL DEFAULT 1,
41 created_by_user UUID NOT NULL REFERENCES users(id),
42 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
43 disabled BOOLEAN DEFAULT FALSE
44);
45
46CREATE TABLE IF NOT EXISTS invite_code_uses (
47 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
48 code TEXT NOT NULL REFERENCES invite_codes(code),
49 used_by_user UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
50 used_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
51 UNIQUE(code, used_by_user)
52);
53
54CREATE TABLE IF NOT EXISTS user_keys (
55 user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
56 key_bytes BYTEA NOT NULL,
57 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
58 encrypted_at TIMESTAMPTZ,
59 encryption_version INTEGER DEFAULT 0
60);
61
62CREATE TABLE IF NOT EXISTS repos (
63 user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
64 repo_root_cid TEXT NOT NULL,
65 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
66 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
67);
68
69CREATE TABLE IF NOT EXISTS blocks (
70 cid BYTEA PRIMARY KEY,
71 data BYTEA NOT NULL,
72 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
73);
74
75CREATE TABLE IF NOT EXISTS records (
76 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
77 repo_id UUID NOT NULL REFERENCES repos(user_id) ON DELETE CASCADE,
78 collection TEXT NOT NULL,
79 rkey TEXT NOT NULL,
80 record_cid TEXT NOT NULL,
81 takedown_ref TEXT,
82 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
83 UNIQUE(repo_id, collection, rkey)
84);
85
86CREATE TABLE IF NOT EXISTS blobs (
87 cid TEXT PRIMARY KEY,
88 mime_type TEXT NOT NULL,
89 size_bytes BIGINT NOT NULL,
90 created_by_user UUID NOT NULL REFERENCES users(id),
91 storage_key TEXT NOT NULL,
92 takedown_ref TEXT,
93 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
94);
95
96CREATE TABLE IF NOT EXISTS app_passwords (
97 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
98 user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
99 name TEXT NOT NULL,
100 password_hash TEXT NOT NULL,
101 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
102 privileged BOOLEAN NOT NULL DEFAULT FALSE,
103 UNIQUE(user_id, name)
104);
105
106CREATE TABLE reports (
107 id BIGINT PRIMARY KEY,
108 reason_type TEXT NOT NULL,
109 reason TEXT,
110 subject_json JSONB NOT NULL,
111 reported_by_did TEXT NOT NULL,
112 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
113);
114
115CREATE TABLE IF NOT EXISTS account_deletion_requests (
116 token TEXT PRIMARY KEY,
117 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
118 expires_at TIMESTAMPTZ NOT NULL,
119 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
120);
121
122CREATE TABLE IF NOT EXISTS notification_queue (
123 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
124 user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
125 channel notification_channel NOT NULL DEFAULT 'email',
126 notification_type notification_type NOT NULL,
127 status notification_status NOT NULL DEFAULT 'pending',
128 recipient TEXT NOT NULL,
129 subject TEXT,
130 body TEXT NOT NULL,
131 metadata JSONB,
132 attempts INT NOT NULL DEFAULT 0,
133 max_attempts INT NOT NULL DEFAULT 3,
134 last_error TEXT,
135 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
136 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
137 scheduled_for TIMESTAMPTZ NOT NULL DEFAULT NOW(),
138 processed_at TIMESTAMPTZ
139);
140
141CREATE INDEX idx_notification_queue_status_scheduled
142 ON notification_queue(status, scheduled_for)
143 WHERE status = 'pending';
144
145CREATE INDEX idx_notification_queue_user_id ON notification_queue(user_id);
146
147CREATE TABLE IF NOT EXISTS reserved_signing_keys (
148 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
149 did TEXT,
150 public_key_did_key TEXT NOT NULL,
151 private_key_bytes BYTEA NOT NULL,
152 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
153 expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '24 hours',
154 used_at TIMESTAMPTZ
155);
156
157CREATE INDEX IF NOT EXISTS idx_reserved_signing_keys_did ON reserved_signing_keys(did) WHERE did IS NOT NULL;
158CREATE INDEX IF NOT EXISTS idx_reserved_signing_keys_expires ON reserved_signing_keys(expires_at) WHERE used_at IS NULL;
159
160CREATE TABLE repo_seq (
161 seq BIGSERIAL PRIMARY KEY,
162 did TEXT NOT NULL,
163 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
164 event_type TEXT NOT NULL,
165 commit_cid TEXT,
166 prev_cid TEXT,
167 ops JSONB,
168 blobs TEXT[],
169 blocks_cids TEXT[]
170);
171
172CREATE INDEX idx_repo_seq_seq ON repo_seq(seq);
173CREATE INDEX idx_repo_seq_did ON repo_seq(did);
174
175CREATE TABLE IF NOT EXISTS session_tokens (
176 id SERIAL PRIMARY KEY,
177 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
178 access_jti TEXT NOT NULL UNIQUE,
179 refresh_jti TEXT NOT NULL UNIQUE,
180 access_expires_at TIMESTAMPTZ NOT NULL,
181 refresh_expires_at TIMESTAMPTZ NOT NULL,
182 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
183 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
184);
185
186CREATE INDEX idx_session_tokens_did ON session_tokens(did);
187CREATE INDEX idx_session_tokens_access_jti ON session_tokens(access_jti);
188CREATE INDEX idx_session_tokens_refresh_jti ON session_tokens(refresh_jti);
189
190CREATE TABLE IF NOT EXISTS used_refresh_tokens (
191 refresh_jti TEXT PRIMARY KEY,
192 session_id INTEGER NOT NULL REFERENCES session_tokens(id) ON DELETE CASCADE,
193 used_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
194);
195
196CREATE INDEX idx_used_refresh_tokens_session_id ON used_refresh_tokens(session_id);
197
198CREATE TABLE IF NOT EXISTS oauth_device (
199 id TEXT PRIMARY KEY,
200 session_id TEXT NOT NULL UNIQUE,
201 user_agent TEXT,
202 ip_address TEXT NOT NULL,
203 last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
204);
205
206CREATE TABLE IF NOT EXISTS oauth_authorization_request (
207 id TEXT PRIMARY KEY,
208 did TEXT REFERENCES users(did) ON DELETE CASCADE,
209 device_id TEXT REFERENCES oauth_device(id) ON DELETE SET NULL,
210 client_id TEXT NOT NULL,
211 client_auth JSONB,
212 parameters JSONB NOT NULL,
213 expires_at TIMESTAMPTZ NOT NULL,
214 code TEXT UNIQUE
215);
216
217CREATE INDEX idx_oauth_auth_request_expires ON oauth_authorization_request(expires_at);
218CREATE INDEX idx_oauth_auth_request_code ON oauth_authorization_request(code) WHERE code IS NOT NULL;
219
220CREATE TABLE IF NOT EXISTS oauth_token (
221 id SERIAL PRIMARY KEY,
222 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
223 token_id TEXT NOT NULL UNIQUE,
224 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
225 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
226 expires_at TIMESTAMPTZ NOT NULL,
227 client_id TEXT NOT NULL,
228 client_auth JSONB NOT NULL,
229 device_id TEXT REFERENCES oauth_device(id) ON DELETE SET NULL,
230 parameters JSONB NOT NULL,
231 details JSONB,
232 code TEXT UNIQUE,
233 current_refresh_token TEXT UNIQUE,
234 scope TEXT
235);
236
237CREATE INDEX idx_oauth_token_did ON oauth_token(did);
238CREATE INDEX idx_oauth_token_code ON oauth_token(code) WHERE code IS NOT NULL;
239
240CREATE TABLE IF NOT EXISTS oauth_account_device (
241 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
242 device_id TEXT NOT NULL REFERENCES oauth_device(id) ON DELETE CASCADE,
243 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
244 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
245 PRIMARY KEY (did, device_id)
246);
247
248CREATE TABLE IF NOT EXISTS oauth_authorized_client (
249 did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
250 client_id TEXT NOT NULL,
251 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
252 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
253 data JSONB NOT NULL,
254 PRIMARY KEY (did, client_id)
255);
256
257CREATE TABLE IF NOT EXISTS oauth_used_refresh_token (
258 refresh_token TEXT PRIMARY KEY,
259 token_id INTEGER NOT NULL REFERENCES oauth_token(id) ON DELETE CASCADE
260);
261
262CREATE TABLE oauth_dpop_jti (
263 jti TEXT PRIMARY KEY,
264 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
265);
266
267CREATE INDEX idx_oauth_dpop_jti_created_at ON oauth_dpop_jti(created_at);