-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.sql
More file actions
136 lines (118 loc) · 6.77 KB
/
schema.sql
File metadata and controls
136 lines (118 loc) · 6.77 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
-- Subspace Database Schema
-- Designed for SQLite with future PostgreSQL migration in mind.
-- Avoids SQLite-only features; uses standard SQL types.
PRAGMA journal_mode = WAL;
PRAGMA foreign_keys = ON;
--------------------------------------------------------------------------------
-- Users
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY, -- UUID
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
avatar_url TEXT,
theme TEXT NOT NULL DEFAULT 'dark', -- 'light' | 'dark'
language TEXT NOT NULL DEFAULT 'en',
notifications_enabled INTEGER NOT NULL DEFAULT 1, -- boolean (0/1)
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
--------------------------------------------------------------------------------
-- Servers
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS servers (
id TEXT PRIMARY KEY, -- UUID
name TEXT NOT NULL,
icon_url TEXT,
owner_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
CREATE INDEX IF NOT EXISTS idx_servers_owner ON servers(owner_id);
--------------------------------------------------------------------------------
-- Server Members (many-to-many: users ↔ servers)
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS server_members (
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
server_id TEXT NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'member', -- 'owner' | 'admin' | 'member'
joined_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
PRIMARY KEY (user_id, server_id)
);
CREATE INDEX IF NOT EXISTS idx_server_members_server ON server_members(server_id);
--------------------------------------------------------------------------------
-- Channels (belong to a server; type = 'text' | 'voice')
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS channels (
id TEXT PRIMARY KEY, -- UUID
server_id TEXT NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
name TEXT NOT NULL,
type TEXT NOT NULL CHECK (type IN ('text', 'voice')),
position INTEGER NOT NULL DEFAULT 0, -- display ordering
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
CREATE INDEX IF NOT EXISTS idx_channels_server ON channels(server_id);
--------------------------------------------------------------------------------
-- Messages (belong to a text channel)
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS messages (
id TEXT PRIMARY KEY, -- UUID
channel_id TEXT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
author_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
content TEXT, -- markdown text (nullable for media-only)
pinned INTEGER NOT NULL DEFAULT 0, -- boolean
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
edited_at TEXT -- NULL until edited
);
CREATE INDEX IF NOT EXISTS idx_messages_channel ON messages(channel_id, created_at);
CREATE INDEX IF NOT EXISTS idx_messages_author ON messages(author_id);
--------------------------------------------------------------------------------
-- Message Attachments (images / videos uploaded with a message)
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS attachments (
id TEXT PRIMARY KEY, -- UUID
message_id TEXT NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
file_url TEXT NOT NULL,
file_name TEXT NOT NULL,
mime_type TEXT NOT NULL, -- e.g. 'image/png', 'video/mp4'
size_bytes INTEGER,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
CREATE INDEX IF NOT EXISTS idx_attachments_message ON attachments(message_id);
--------------------------------------------------------------------------------
-- Reactions (emoji reactions on messages)
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS reactions (
message_id TEXT NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
emoji TEXT NOT NULL, -- native Unicode emoji character(s)
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
PRIMARY KEY (message_id, user_id, emoji)
);
CREATE INDEX IF NOT EXISTS idx_reactions_message ON reactions(message_id);
--------------------------------------------------------------------------------
-- Mentions (tracks @user, @here, @everyone per message for notifications)
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mentions (
id TEXT PRIMARY KEY, -- UUID
message_id TEXT NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
type TEXT NOT NULL CHECK (type IN ('user', 'here', 'everyone')),
target_id TEXT REFERENCES users(id) ON DELETE CASCADE, -- NULL for @here/@everyone
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
CREATE INDEX IF NOT EXISTS idx_mentions_message ON mentions(message_id);
CREATE INDEX IF NOT EXISTS idx_mentions_target ON mentions(target_id);
--------------------------------------------------------------------------------
-- Voice State (ephemeral: who is in which voice channel right now)
-- Rows are inserted on join and deleted on leave.
--------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS voice_states (
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
channel_id TEXT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
muted INTEGER NOT NULL DEFAULT 0, -- self-mute
deafened INTEGER NOT NULL DEFAULT 0, -- self-deafen
joined_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
PRIMARY KEY (user_id, channel_id)
);
CREATE INDEX IF NOT EXISTS idx_voice_states_channel ON voice_states(channel_id);