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