Files
chat-server/ARCHITECTURE.md
T

156 lines
6.4 KiB
Markdown

# 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 `crypton` EC (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/join`
* `GET /.well-known/users/:username`, `GET /.well-known/verify/:userId`
* `GET /api/me`, `GET /api/channels`, `POST /api/channels`, `GET /api/channels/:id`
* `GET /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**.
1. **Stage (Local Client Action):** User selects multiple files. The client displays local thumbnails in the input area. The user can drag to reorder, toggle `spoiler` modifiers on individual files or the whole gallery, and add text. *No network requests are made during this phase.*
2. **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.
3. **Upload (Network Action):** The client initiates `POST /api/uploads` for the files.
4. **Publish (Network Action):** Once the server responds with the `FileId`s and dimensions, the client constructs the final `componentsJson` tree and calls `POST /api/messages`.
5. **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)
```dart
@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:**
```json
{
"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**
```json
{
"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).*
```json
{
"type": "gallery",
"modifiers": [],
"fallback": "",
"data": {
"layout": "grid",
"items":
}
}
```
**Type: Collapsible (Expandable Tile)**
```json
{
"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:
1. Parse `components`.
2. Extract all readable text to populate the `content` database column.
3. Validate any `fileIds` inside galleries. Mark those `File` entities as `isAttached = true`.
4. Save `Message` entity with `componentsJson`.
---
## 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 `embed` component asynchronously.
* **Garbage Collector:** A daily worker to purge unattached files from the disk.