6.4 KiB
Reliquary Server Architecture - Complete Reference
1. Project Overview & The Reliquary Protocol
Reliquary is a self-hosted, highly optimized Discord alternative for private communities. It operates on the Reliquary Protocol, a decentralized identity and routing model.
- Desktop-First & Native Performance: The primary target is Desktop and Web, followed by Android (using foreground services for background connectivity). iOS and centralized Push Notifications are explicitly out of scope for the MVP to avoid centralized infrastructure.
- No Server-to-Server Federation: Servers don't talk to each other. The client handles all cross-server fetching and syncing.
- Cryptographic Identity: Users have a "Home Server" storing their public key (
/.well-known/users/:username). They join "Guest Servers" using cryptographic signatures. No passwords are ever sent to Guest Servers.
2. Current State (What is already implemented)
✅ Implemented Features
- Identity System: secp256k1 keypair/signatures via
cryptonEC (Targeting Ed25519 migration later). - Auth Flow: Single Sign-On on Home Server (returns JWT + encrypted keypair).
- Cross-Server Join Flow: Signature-based verification. Guest servers fetch public keys from Home Servers via HTTP.
- Middleware: JWT authentication middleware.
- Basic CRUD: Channels and Messages (Text only) with author caching.
💾 Current Database Models (ObjectBox)
- User:
id,userId("alice@home.com"),publicKey,passwordHash(home only), etc. - Channel:
id,name,createdAt. - Message:
id,channelId,authorLocalId,authorUserId,content(currently simple text),createdAt.
🌐 Current REST APIs
POST /auth/register,POST /auth/login,POST /auth/joinGET /.well-known/users/:username,GET /.well-known/verify/:userIdGET /api/me,GET /api/channels,POST /api/channels,GET /api/channels/:idGET /api/messages,POST /api/messages,PUT /api/messages/:id,DELETE /api/messages/:id
3. Active Implementation Target: The Component & File System
⚠️ THIS IS THE IMMEDIATE NEXT STEP TO BE CODED. ⚠️
We are migrating from simple text strings to a Component-Based Message Structure (Reliquary Components) to support rich media, link embeds, and collapsible UIs natively.
3.1 UX Flow: Staged Uploads & Dummy Messages (Discord-Style)
To preserve server storage and bandwidth while maintaining a fast, non-blocking UI, Reliquary uses a Staged Upload Pipeline.
- Stage (Local Client Action): User selects multiple files. The client displays local thumbnails in the input area. The user can drag to reorder, toggle
spoilermodifiers on individual files or the whole gallery, and add text. No network requests are made during this phase. - Commit (Local Client Action): The user hits "Send". The client clears the input box so the user can keep typing, and inserts a "Dummy Message" into the local chat history. This dummy displays a file upload progress bar.
- Upload (Network Action): The client initiates
POST /api/uploadsfor the files. - Publish (Network Action): Once the server responds with the
FileIds and dimensions, the client constructs the finalcomponentsJsontree and callsPOST /api/messages. - Resolve: The server processes the message and broadcasts it back via WebSocket. The client silently swaps the "Dummy Message" with the finalized, permanent message.
3.2 Updated Database Models (To be modified/created)
@Entity()
class Message {
int id;
int channelId;
// 1. Search & Notifications (Server Generated)
// Server concatenates all text from components upon ingestion.
String content;
// 2. The Component Tree (Source of Truth for UI)
// JSON string representing List<Component>
String componentsJson;
// ... existing author and date fields ...
}
@Entity()
class File {
int id;
int uploaderId;
String path; // Relative storage path (/uploads/...)
String mimeType;
int sizeBytes;
// Safety Net Garbage Collection
// Because uploads and message creation are two separate API calls,
// if the client crashes in between step 3 and 4, the file is orphaned.
// A simple daily worker will delete files where isAttached == false and age > 24h.
bool isAttached; // False until used in a POST /api/messages
DateTime createdAt;
}
3.3 The Reliquary Component Schema (JSON)
All components stored in componentsJson must follow this base schema to prevent client crashes and layout shifts.
Base Schema:
{
"type": "string", // "text", "gallery", "code", "embed", "collapsible"
"modifiers":, // e.g., (client applies blur overlay)
"fallback": "string", // Plain text for older clients / notifications
"data": { } // Type-specific payload
}
Type: Text
{
"type": "text",
"modifiers":[],
"fallback": "Hello world",
"data": { "content": "Hello **world**", "format": "markdown" }
}
Type: Gallery (Images/Video) Must include aspect ratio or width/height to prevent Cumulative Layout Shift (CLS).
{
"type": "gallery",
"modifiers": [],
"fallback": "",
"data": {
"layout": "grid",
"items":
}
}
Type: Collapsible (Expandable Tile)
{
"type": "collapsible",
"modifiers": [],
"fallback": "",
"data": {
"summary": "Server Logs (Click to expand)",
"children":, "data": { "language": "bash", "content": "Error 500" } }
]
}
}
3.4 API Changes Required
1. New Endpoint: File Upload
POST /api/uploads(multipart/form-data)- Returns:
{ "id": 101, "url": "/files/101.jpg", "width": 1920, "height": 1080 }
2. Modify Endpoint: Send Message
POST /api/messages- Payload now expects:
{ "channelId": 1, "components": } - Server logic required:
- Parse
components. - Extract all readable text to populate the
contentdatabase column. - Validate any
fileIdsinside galleries. Mark thoseFileentities asisAttached = true. - Save
Messageentity withcomponentsJson.
- Parse
4. Future Roadmap (Do NOT implement yet)
- WebSocket Gateway: Real-time event fanout (
/gateway) with channel subscriptions. - Embedder Background Worker: A server-side queue that intercepts links in messages, fetches OpenGraph/yt-dlp data, and appends an
embedcomponent asynchronously. - Garbage Collector: A daily worker to purge unattached files from the disk.