mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
Add all specification files (CHATSERVER, PROTOCOL, SCHEMA, API, SETUP), Claude Code config, and skill definitions for the OwnCord chat platform.
9.1 KiB
9.1 KiB
Database Schema (SQLite)
Single file: data/chatserver.db. WAL mode enabled. Migrations run automatically on server startup.
Users
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE COLLATE NOCASE,
password TEXT NOT NULL, -- bcrypt hash
avatar TEXT, -- filename in uploads/ or NULL
role_id INTEGER NOT NULL DEFAULT 4 REFERENCES roles(id),
totp_secret TEXT, -- encrypted TOTP secret or NULL if 2FA disabled
status TEXT NOT NULL DEFAULT 'offline', -- online, idle, dnd, offline
created_at TEXT NOT NULL DEFAULT (datetime('now')),
last_seen TEXT,
banned INTEGER NOT NULL DEFAULT 0,
ban_reason TEXT,
ban_expires TEXT -- NULL = permanent, datetime = temp ban
);
Sessions
CREATE TABLE sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token TEXT NOT NULL UNIQUE, -- 256-bit random, hex encoded
device TEXT, -- user-agent or client identifier
ip_address TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
last_used TEXT NOT NULL DEFAULT (datetime('now')),
expires_at TEXT NOT NULL -- 30 days from creation
);
CREATE INDEX idx_sessions_token ON sessions(token);
CREATE INDEX idx_sessions_user ON sessions(user_id);
Roles
CREATE TABLE roles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
color TEXT, -- hex color e.g. #E74C3C, NULL for default
permissions INTEGER NOT NULL DEFAULT 0, -- bitfield
position INTEGER NOT NULL DEFAULT 0, -- hierarchy: higher = more power
is_default INTEGER NOT NULL DEFAULT 0 -- 1 = assigned to new users
);
-- Default roles (inserted on first run)
-- Owner: permissions = 0x7FFFFFFF (all bits set)
-- Admin: permissions = 0x3FFFFFFF
-- Moderator: permissions = 0x000FFFFF
-- Member: permissions = 0x00100601
Permission Bitfield
Bit 0: SEND_MESSAGES (0x1)
Bit 1: READ_MESSAGES (0x2)
Bit 5: ATTACH_FILES (0x20)
Bit 6: ADD_REACTIONS (0x40)
Bit 8: USE_SOUNDBOARD (0x100)
Bit 9: CONNECT_VOICE (0x200)
Bit 10: SPEAK_VOICE (0x400)
Bit 11: USE_VIDEO (0x800)
Bit 12: SHARE_SCREEN (0x1000)
Bit 16: MANAGE_MESSAGES (0x10000) -- delete others' messages, pin
Bit 17: MANAGE_CHANNELS (0x20000)
Bit 18: KICK_MEMBERS (0x40000)
Bit 19: BAN_MEMBERS (0x80000)
Bit 20: MUTE_MEMBERS (0x100000) -- server mute/deafen
Bit 24: MANAGE_ROLES (0x1000000)
Bit 25: MANAGE_SERVER (0x2000000)
Bit 26: MANAGE_INVITES (0x4000000)
Bit 27: VIEW_AUDIT_LOG (0x8000000)
Bit 30: ADMINISTRATOR (0x40000000) -- bypasses all checks
Channels
CREATE TABLE channels (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
type TEXT NOT NULL DEFAULT 'text', -- text, voice, announcement
category TEXT, -- category name for grouping
topic TEXT, -- channel description
position INTEGER NOT NULL DEFAULT 0,
slow_mode INTEGER NOT NULL DEFAULT 0, -- seconds between messages, 0 = off
archived INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
Channel Permission Overrides
CREATE TABLE channel_overrides (
id INTEGER PRIMARY KEY AUTOINCREMENT,
channel_id INTEGER NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
role_id INTEGER NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
allow INTEGER NOT NULL DEFAULT 0, -- permission bits to grant
deny INTEGER NOT NULL DEFAULT 0, -- permission bits to revoke
UNIQUE(channel_id, role_id)
);
Messages
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
channel_id INTEGER NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users(id),
content TEXT NOT NULL,
reply_to INTEGER REFERENCES messages(id) ON DELETE SET NULL,
edited_at TEXT,
deleted INTEGER NOT NULL DEFAULT 0, -- 1 = soft deleted
pinned INTEGER NOT NULL DEFAULT 0,
timestamp TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_messages_channel ON messages(channel_id, id DESC);
CREATE INDEX idx_messages_user ON messages(user_id);
Message Full-Text Search
CREATE VIRTUAL TABLE messages_fts USING fts5(
content,
content='messages',
content_rowid='id'
);
-- Triggers to keep FTS in sync
CREATE TRIGGER messages_ai AFTER INSERT ON messages BEGIN
INSERT INTO messages_fts(rowid, content) VALUES (new.id, new.content);
END;
CREATE TRIGGER messages_ad AFTER DELETE ON messages BEGIN
INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', old.id, old.content);
END;
CREATE TRIGGER messages_au AFTER UPDATE ON messages BEGIN
INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', old.id, old.content);
INSERT INTO messages_fts(rowid, content) VALUES (new.id, new.content);
END;
Attachments
CREATE TABLE attachments (
id TEXT PRIMARY KEY, -- UUID
message_id INTEGER REFERENCES messages(id) ON DELETE CASCADE,
filename TEXT NOT NULL, -- original filename
stored_as TEXT NOT NULL, -- UUID filename on disk
mime_type TEXT NOT NULL,
size INTEGER NOT NULL, -- bytes
uploaded_at TEXT NOT NULL DEFAULT (datetime('now'))
);
Reactions
CREATE TABLE reactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
emoji TEXT NOT NULL,
UNIQUE(message_id, user_id, emoji)
);
Invites
CREATE TABLE invites (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT NOT NULL UNIQUE, -- random token
created_by INTEGER NOT NULL REFERENCES users(id),
redeemed_by INTEGER REFERENCES users(id),
max_uses INTEGER, -- NULL = unlimited
use_count INTEGER NOT NULL DEFAULT 0,
expires_at TEXT, -- NULL = never
created_at TEXT NOT NULL DEFAULT (datetime('now')),
revoked INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX idx_invites_code ON invites(code);
Read State (unread tracking)
CREATE TABLE read_states (
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
channel_id INTEGER NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
last_message_id INTEGER NOT NULL DEFAULT 0,
mention_count INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (user_id, channel_id)
);
Audit Log
CREATE TABLE audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER REFERENCES users(id),
action TEXT NOT NULL, -- e.g. user_ban, channel_create, message_delete, role_update
target_type TEXT, -- user, channel, message, role, invite
target_id INTEGER,
details TEXT, -- JSON with extra context
timestamp TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_audit_timestamp ON audit_log(timestamp DESC);
Login Attempts (rate limiting)
CREATE TABLE login_attempts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip_address TEXT NOT NULL,
username TEXT,
success INTEGER NOT NULL DEFAULT 0,
timestamp TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_login_ip ON login_attempts(ip_address, timestamp);
Server Settings (key-value)
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
-- Default settings inserted on first run:
-- server_name, server_icon, motd, max_upload_bytes, voice_quality,
-- require_2fa, registration_open (always 0), backup_schedule, backup_retention
Custom Emoji
CREATE TABLE emoji (
id INTEGER PRIMARY KEY AUTOINCREMENT,
shortcode TEXT NOT NULL UNIQUE, -- e.g. :pepe:
filename TEXT NOT NULL, -- stored in uploads/emoji/
uploaded_by INTEGER NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
Soundboard
CREATE TABLE sounds (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
filename TEXT NOT NULL, -- stored in uploads/sounds/
duration_ms INTEGER NOT NULL,
uploaded_by INTEGER NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
Notes
- All datetimes stored as ISO 8601 UTC strings.
- Enable WAL mode on connection:
PRAGMA journal_mode=WAL; - Enable foreign keys:
PRAGMA foreign_keys=ON; - Use
modernc.org/sqlite(pure Go, no CGO needed). - Migrations: store schema version in
settingstable, apply incremental SQL on startup.