add docs, protocol, plugins, README, CHANGELOG
This commit is contained in:
parent
1d2209bfac
commit
f262da222b
44 changed files with 9269 additions and 0 deletions
669
docs/10-database.md
Normal file
669
docs/10-database.md
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
# Database Schema
|
||||
|
||||
Version: 1.0
|
||||
Status: Specification and implementation guide
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Vnox uses SQLite for local deployment and supports PostgreSQL for larger deployments.
|
||||
|
||||
Database schema defines storage for:
|
||||
- Users and identity
|
||||
- Guilds, channels, categories
|
||||
- Roles and permissions
|
||||
- Messages and history
|
||||
- Direct messages
|
||||
- Presence and online status
|
||||
- Audit logs
|
||||
|
||||
All tables use UUID for primary keys (no auto-increment) for federation compatibility.
|
||||
|
||||
---
|
||||
|
||||
## Core Tables
|
||||
|
||||
### users
|
||||
|
||||
Global user identity across all Vnox instances.
|
||||
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
identity_key TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_users_username ON users(username);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ------------ | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | UUID |
|
||||
| username | TEXT | NOT NULL | Display name |
|
||||
| identity_key | TEXT | NOT NULL | Ed25519 public key |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | NOT NULL | Last modification |
|
||||
|
||||
---
|
||||
|
||||
### sessions
|
||||
|
||||
Active user sessions on a gateway instance.
|
||||
|
||||
```sql
|
||||
CREATE TABLE sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
session_token TEXT NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_sessions_user ON sessions(user_id);
|
||||
CREATE INDEX idx_sessions_expires ON sessions(expires_at);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ------------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Session UUID |
|
||||
| user_id | TEXT | FK users | User owning session |
|
||||
| session_token | TEXT | UNIQUE | Auth token |
|
||||
| expires_at | TIMESTAMP | NOT NULL | Expiration time |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
|
||||
---
|
||||
|
||||
## Guild Tables
|
||||
|
||||
### guilds
|
||||
|
||||
Guild entities (communities/servers).
|
||||
|
||||
```sql
|
||||
CREATE TABLE guilds (
|
||||
id TEXT PRIMARY KEY,
|
||||
owner_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
icon TEXT,
|
||||
banner TEXT,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(owner_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_guilds_owner ON guilds(owner_id);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ----------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Guild UUID |
|
||||
| owner_id | TEXT | FK users | Guild owner |
|
||||
| name | TEXT | NOT NULL | Guild name |
|
||||
| description | TEXT | | Guild description |
|
||||
| icon | TEXT | | Asset ID |
|
||||
| banner | TEXT | | Asset ID |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | NOT NULL | Last modification |
|
||||
|
||||
---
|
||||
|
||||
### guild_members
|
||||
|
||||
Guild membership tracking.
|
||||
|
||||
```sql
|
||||
CREATE TABLE guild_members (
|
||||
guild_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
nickname TEXT,
|
||||
joined_at TIMESTAMP NOT NULL,
|
||||
timeout_until TIMESTAMP,
|
||||
PRIMARY KEY (guild_id, user_id),
|
||||
FOREIGN KEY(guild_id) REFERENCES guilds(id),
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_guild_members_user ON guild_members(user_id);
|
||||
CREATE INDEX idx_guild_members_joined ON guild_members(joined_at);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ------------- | --------- | -------------- | -------------------- |
|
||||
| guild_id | TEXT | PRIMARY KEY | Guild UUID |
|
||||
| user_id | TEXT | PRIMARY KEY | User UUID |
|
||||
| nickname | TEXT | | Guild-specific nick |
|
||||
| joined_at | TIMESTAMP | NOT NULL | Join time |
|
||||
| timeout_until | TIMESTAMP | | Moderation timeout |
|
||||
|
||||
---
|
||||
|
||||
### categories
|
||||
|
||||
Channel categories for organization.
|
||||
|
||||
```sql
|
||||
CREATE TABLE categories (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
position INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(guild_id) REFERENCES guilds(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_categories_guild ON categories(guild_id);
|
||||
CREATE INDEX idx_categories_position ON categories(guild_id, position);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ---------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Category UUID |
|
||||
| guild_id | TEXT | FK guilds | Parent guild |
|
||||
| name | TEXT | NOT NULL | Display name |
|
||||
| position | INTEGER | NOT NULL | Sort order |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | NOT NULL | Last modification |
|
||||
|
||||
---
|
||||
|
||||
### channels
|
||||
|
||||
Communication channels (text, voice, announcements).
|
||||
|
||||
```sql
|
||||
CREATE TABLE channels (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
category_id TEXT,
|
||||
type TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
topic TEXT,
|
||||
position INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(guild_id) REFERENCES guilds(id),
|
||||
FOREIGN KEY(category_id) REFERENCES categories(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_channels_guild ON channels(guild_id);
|
||||
CREATE INDEX idx_channels_category ON channels(category_id);
|
||||
CREATE INDEX idx_channels_position ON channels(guild_id, position);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ----------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Channel UUID |
|
||||
| guild_id | TEXT | FK guilds | Parent guild |
|
||||
| category_id | TEXT | FK categories | Parent category |
|
||||
| type | TEXT | NOT NULL | TEXT/VOICE/etc |
|
||||
| name | TEXT | NOT NULL | Display name |
|
||||
| topic | TEXT | | Channel description |
|
||||
| position | INTEGER | NOT NULL | Sort order |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | NOT NULL | Last modification |
|
||||
|
||||
---
|
||||
|
||||
## Role & Permission Tables
|
||||
|
||||
### roles
|
||||
|
||||
Guild roles with permission bitmasks.
|
||||
|
||||
```sql
|
||||
CREATE TABLE roles (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
color INTEGER NOT NULL DEFAULT 0,
|
||||
permissions INTEGER NOT NULL DEFAULT 0,
|
||||
position INTEGER NOT NULL DEFAULT 0,
|
||||
hoist INTEGER NOT NULL DEFAULT 0,
|
||||
mentionable INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(guild_id) REFERENCES guilds(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_roles_guild ON roles(guild_id);
|
||||
CREATE INDEX idx_roles_position ON roles(guild_id, position);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ------------ | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Role UUID |
|
||||
| guild_id | TEXT | FK guilds | Parent guild |
|
||||
| name | TEXT | NOT NULL | Display name |
|
||||
| color | INTEGER | NOT NULL | RGB color value |
|
||||
| permissions | INTEGER | NOT NULL | Bitmask (u128) |
|
||||
| position | INTEGER | NOT NULL | Hierarchy position |
|
||||
| hoist | INTEGER | NOT NULL | Display separately |
|
||||
| mentionable | INTEGER | NOT NULL | Can be @mentioned |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | NOT NULL | Last modification |
|
||||
|
||||
---
|
||||
|
||||
### member_roles
|
||||
|
||||
Many-to-many mapping of members to roles.
|
||||
|
||||
```sql
|
||||
CREATE TABLE member_roles (
|
||||
member_guild_id TEXT NOT NULL,
|
||||
member_user_id TEXT NOT NULL,
|
||||
role_id TEXT NOT NULL,
|
||||
PRIMARY KEY (member_guild_id, member_user_id, role_id),
|
||||
FOREIGN KEY(member_guild_id, member_user_id)
|
||||
REFERENCES guild_members(guild_id, user_id),
|
||||
FOREIGN KEY(role_id) REFERENCES roles(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_member_roles_role ON member_roles(role_id);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ---------------- | ---- | -------------- | -------------------- |
|
||||
| member_guild_id | TEXT | PRIMARY KEY | Guild UUID |
|
||||
| member_user_id | TEXT | PRIMARY KEY | User UUID |
|
||||
| role_id | TEXT | PRIMARY KEY | Role UUID |
|
||||
|
||||
---
|
||||
|
||||
### channel_overrides
|
||||
|
||||
Role and user permission overrides per channel.
|
||||
|
||||
```sql
|
||||
CREATE TABLE channel_overrides (
|
||||
id TEXT PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL,
|
||||
target_id TEXT NOT NULL,
|
||||
target_type TEXT NOT NULL,
|
||||
allow_mask INTEGER NOT NULL DEFAULT 0,
|
||||
deny_mask INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(channel_id) REFERENCES channels(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_channel_overrides_channel
|
||||
ON channel_overrides(channel_id);
|
||||
CREATE INDEX idx_channel_overrides_target
|
||||
ON channel_overrides(target_id, target_type);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ----------- | --------- | -------------- | ------------------------ |
|
||||
| id | TEXT | PRIMARY KEY | Override UUID |
|
||||
| channel_id | TEXT | FK channels | Channel |
|
||||
| target_id | TEXT | NOT NULL | Role or User UUID |
|
||||
| target_type | TEXT | NOT NULL | "ROLE" or "USER" |
|
||||
| allow_mask | INTEGER | NOT NULL | Allowed permissions |
|
||||
| deny_mask | INTEGER | NOT NULL | Denied permissions |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | NOT NULL | Last modification |
|
||||
|
||||
---
|
||||
|
||||
## Message Tables
|
||||
|
||||
### messages
|
||||
|
||||
Text messages in channels.
|
||||
|
||||
```sql
|
||||
CREATE TABLE messages (
|
||||
id TEXT PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL,
|
||||
sender_id TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP,
|
||||
deleted_at TIMESTAMP,
|
||||
FOREIGN KEY(channel_id) REFERENCES channels(id),
|
||||
FOREIGN KEY(sender_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_messages_channel ON messages(channel_id, created_at DESC);
|
||||
CREATE INDEX idx_messages_sender ON messages(sender_id);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ---------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Message UUID |
|
||||
| channel_id | TEXT | FK channels | Parent channel |
|
||||
| sender_id | TEXT | FK users | Message author |
|
||||
| content | TEXT | NOT NULL | Encrypted content |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | | Edit time |
|
||||
| deleted_at | TIMESTAMP | | Deletion time (soft) |
|
||||
|
||||
---
|
||||
|
||||
### message_reactions
|
||||
|
||||
Emoji reactions on messages.
|
||||
|
||||
```sql
|
||||
CREATE TABLE message_reactions (
|
||||
message_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
emoji TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (message_id, user_id, emoji),
|
||||
FOREIGN KEY(message_id) REFERENCES messages(id),
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_reactions_message ON message_reactions(message_id);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ---------- | --------- | -------------- | -------------------- |
|
||||
| message_id | TEXT | PRIMARY KEY | Message UUID |
|
||||
| user_id | TEXT | PRIMARY KEY | User UUID |
|
||||
| emoji | TEXT | PRIMARY KEY | Emoji character |
|
||||
| created_at | TIMESTAMP | NOT NULL | Reaction time |
|
||||
|
||||
---
|
||||
|
||||
## Direct Message Tables
|
||||
|
||||
### direct_messages
|
||||
|
||||
DM channel tracking (not per-guild).
|
||||
|
||||
```sql
|
||||
CREATE TABLE direct_messages (
|
||||
dm_id TEXT PRIMARY KEY,
|
||||
user_id_1 TEXT NOT NULL,
|
||||
user_id_2 TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(user_id_1) REFERENCES users(id),
|
||||
FOREIGN KEY(user_id_2) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_dm_users
|
||||
ON direct_messages(
|
||||
MIN(user_id_1, user_id_2),
|
||||
MAX(user_id_1, user_id_2)
|
||||
);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ---------- | --------- | -------------- | -------------------- |
|
||||
| dm_id | TEXT | PRIMARY KEY | DM UUID |
|
||||
| user_id_1 | TEXT | FK users | First user (lexicog) |
|
||||
| user_id_2 | TEXT | FK users | Second user |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
| updated_at | TIMESTAMP | NOT NULL | Last message time |
|
||||
|
||||
---
|
||||
|
||||
### dm_messages
|
||||
|
||||
Direct messages (archived).
|
||||
|
||||
```sql
|
||||
CREATE TABLE dm_messages (
|
||||
id TEXT PRIMARY KEY,
|
||||
dm_id TEXT NOT NULL,
|
||||
sender_id TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(dm_id) REFERENCES direct_messages(dm_id),
|
||||
FOREIGN KEY(sender_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_dm_messages_dm ON dm_messages(dm_id, created_at DESC);
|
||||
CREATE INDEX idx_dm_messages_sender ON dm_messages(sender_id);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ---------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Message UUID |
|
||||
| dm_id | TEXT | FK dm tables | Parent DM |
|
||||
| sender_id | TEXT | FK users | Message author |
|
||||
| content | TEXT | NOT NULL | Encrypted content |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
|
||||
---
|
||||
|
||||
## Invitation Tables
|
||||
|
||||
### invites
|
||||
|
||||
Guild invitations.
|
||||
|
||||
```sql
|
||||
CREATE TABLE invites (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
creator_id TEXT NOT NULL,
|
||||
code TEXT NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMP,
|
||||
max_uses INTEGER,
|
||||
uses INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(guild_id) REFERENCES guilds(id),
|
||||
FOREIGN KEY(creator_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_invites_guild ON invites(guild_id);
|
||||
CREATE INDEX idx_invites_code ON invites(code);
|
||||
CREATE INDEX idx_invites_expires ON invites(expires_at);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ---------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Invite UUID |
|
||||
| guild_id | TEXT | FK guilds | Target guild |
|
||||
| creator_id | TEXT | FK users | Creator |
|
||||
| code | TEXT | UNIQUE | Invite slug |
|
||||
| expires_at | TIMESTAMP | | Expiration time |
|
||||
| max_uses | INTEGER | | Use limit |
|
||||
| uses | INTEGER | NOT NULL | Current uses |
|
||||
| created_at | TIMESTAMP | NOT NULL | Creation time |
|
||||
|
||||
---
|
||||
|
||||
## Presence Tables
|
||||
|
||||
### presence
|
||||
|
||||
User online status and activity.
|
||||
|
||||
```sql
|
||||
CREATE TABLE presence (
|
||||
user_id TEXT PRIMARY KEY,
|
||||
status TEXT NOT NULL,
|
||||
activity_type TEXT,
|
||||
activity_text TEXT,
|
||||
last_seen TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_presence_status ON presence(status);
|
||||
CREATE INDEX idx_presence_last_seen ON presence(last_seen);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ------------- | --------- | -------------- | -------------------- |
|
||||
| user_id | TEXT | PRIMARY KEY | User UUID |
|
||||
| status | TEXT | NOT NULL | ONLINE/IDLE/etc |
|
||||
| activity_type | TEXT | | PLAYING/LISTENING |
|
||||
| activity_text | TEXT | | Activity description |
|
||||
| last_seen | TIMESTAMP | NOT NULL | Last activity time |
|
||||
|
||||
---
|
||||
|
||||
## Friendship Tables
|
||||
|
||||
### friends
|
||||
|
||||
User friendship relationships.
|
||||
|
||||
```sql
|
||||
CREATE TABLE friends (
|
||||
requester_id TEXT NOT NULL,
|
||||
target_id TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (requester_id, target_id),
|
||||
FOREIGN KEY(requester_id) REFERENCES users(id),
|
||||
FOREIGN KEY(target_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_friends_target ON friends(target_id, status);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ------------ | --------- | -------------- | ------------------------ |
|
||||
| requester_id | TEXT | PRIMARY KEY | Request originator |
|
||||
| target_id | TEXT | PRIMARY KEY | Request recipient |
|
||||
| status | TEXT | NOT NULL | pending/accepted/blocked |
|
||||
| created_at | TIMESTAMP | NOT NULL | Request time |
|
||||
|
||||
---
|
||||
|
||||
## Audit Log Table
|
||||
|
||||
### audit_logs
|
||||
|
||||
Moderation and administrative actions.
|
||||
|
||||
```sql
|
||||
CREATE TABLE audit_logs (
|
||||
id TEXT PRIMARY KEY,
|
||||
guild_id TEXT NOT NULL,
|
||||
actor_id TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
target_id TEXT,
|
||||
target_type TEXT,
|
||||
reason TEXT,
|
||||
changes TEXT,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(guild_id) REFERENCES guilds(id),
|
||||
FOREIGN KEY(actor_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_audit_logs_guild ON audit_logs(guild_id, created_at DESC);
|
||||
CREATE INDEX idx_audit_logs_actor ON audit_logs(actor_id);
|
||||
CREATE INDEX idx_audit_logs_target
|
||||
ON audit_logs(target_id, target_type);
|
||||
```
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
| ----------- | --------- | -------------- | -------------------- |
|
||||
| id | TEXT | PRIMARY KEY | Log UUID |
|
||||
| guild_id | TEXT | FK guilds | Guild context |
|
||||
| actor_id | TEXT | FK users | Admin/moderator |
|
||||
| action | TEXT | NOT NULL | ACTION_TYPE |
|
||||
| target_id | TEXT | | Affected entity |
|
||||
| target_type | TEXT | | Entity type |
|
||||
| reason | TEXT | | Reason for action |
|
||||
| changes | TEXT | | JSON of old/new |
|
||||
| created_at | TIMESTAMP | NOT NULL | Action time |
|
||||
|
||||
---
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1.1 (Current)
|
||||
|
||||
```sql
|
||||
-- Already exists
|
||||
CREATE TABLE users
|
||||
CREATE TABLE sessions
|
||||
CREATE TABLE channels
|
||||
CREATE TABLE messages
|
||||
CREATE TABLE direct_messages
|
||||
CREATE TABLE dm_messages
|
||||
```
|
||||
|
||||
### Phase 1.2
|
||||
|
||||
```sql
|
||||
-- Add guild system
|
||||
CREATE TABLE guilds
|
||||
CREATE TABLE guild_members
|
||||
CREATE TABLE categories
|
||||
CREATE TABLE roles
|
||||
CREATE TABLE member_roles
|
||||
CREATE TABLE channel_overrides
|
||||
CREATE TABLE invites
|
||||
CREATE TABLE presence
|
||||
CREATE TABLE friends
|
||||
CREATE TABLE audit_logs
|
||||
```
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
During transition to guilds:
|
||||
- Create a default guild per deployment
|
||||
- Migrate existing channels to default guild
|
||||
- Add all existing users as guild members
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Indexes
|
||||
|
||||
Key composite indexes:
|
||||
- `messages(channel_id, created_at DESC)` — range queries
|
||||
- `dm_messages(dm_id, created_at DESC)` — pagination
|
||||
- `presence(status, last_seen)` — online user queries
|
||||
- `guild_members(guild_id, joined_at)` — membership lists
|
||||
|
||||
### Query Patterns
|
||||
|
||||
Optimize for:
|
||||
- Message history fetch (paginated, DESC)
|
||||
- Channel member list
|
||||
- Permission resolution (cached)
|
||||
- Online presence broadcast
|
||||
- Recent DM threads
|
||||
|
||||
### Caching
|
||||
|
||||
Recommended client-side caches:
|
||||
- Guild data (invalidated on GUILD_UPDATE)
|
||||
- Channel list (invalidated on CHANNEL_CREATE/DELETE)
|
||||
- User presence (invalidated on PRESENCE_UPDATE)
|
||||
- Role permissions (cached by guild)
|
||||
|
||||
---
|
||||
|
||||
## PostgreSQL vs SQLite
|
||||
|
||||
### SQLite (Development, Single-Server)
|
||||
|
||||
```toml
|
||||
[database]
|
||||
type = "sqlite"
|
||||
path = "data/vnox.db"
|
||||
```
|
||||
|
||||
### PostgreSQL (Production, Distributed)
|
||||
|
||||
```toml
|
||||
[database]
|
||||
type = "postgres"
|
||||
url = "postgresql://user:pass@localhost/vnox"
|
||||
pool_size = 32
|
||||
```
|
||||
|
||||
Both use identical schema; driver handles translation of:
|
||||
- `INTEGER` ↔ `BIGINT`
|
||||
- `TEXT` ↔ `VARCHAR`
|
||||
- UUID handling
|
||||
Loading…
Add table
Add a link
Reference in a new issue