# Reliquary Architecture & Protocol Reference ## 1. Project Overview **Reliquary** is a self-hosted, high-performance chat platform operating on the **Reliquary Protocol**. * **Philosophy:** Desktop-first, native performance, decentralized identity. * **Routing:** No server-to-server federation. The Client handles all routing. * **Identity:** Cryptographic keypairs (secp256k1). User ID: `user@home.server`. * **Push Notifications:** Explicitly out of scope for MVP. Desktop relies on background WebSockets; Android relies on Foreground Services. --- ## 2. Current System State *The following features are implemented or have a fixed specification.* ### ✅ Core Features * **Auth:** JWT-based. Register/Login returns encrypted keypair. * **Join Flow:** Cryptographic signature verification. * **REST API:** Basic CRUD for Channels and Text-only Messages. * **Gateway:** WebSocket server for event fanout (Specification defined in Section 4). ### 💾 Database Models (ObjectBox) * **User:** `userId`, `publicKey`, `passwordHash` (home only). * **Channel:** `id`, `name`, `createdAt`. * **Message:** `id`, `channelId`, `authorUserId`, `content`, `createdAt`. --- ## 3. Active Implementation Target: Component & File System *⚠️ THIS SECTION DESCRIBES NEW FEATURES TO BE CODED ⚠️* We are migrating from plain text to **Reliquary Components**. This allows rich media, embeds, and collapsible UIs. ### 3.1 UX Flow: Staged Uploads (Discord-Style) To ensure instant UI feedback and save server bandwidth: 1. **Stage (Client):** User picks files. Client shows local previews. User reorders/adds spoilers. *No network request yet.* 2. **Commit (Client):** User hits "Send". Client adds a "Dummy Message" to the UI with a progress bar. 3. **Upload (Network):** Client POSTs files to `/api/uploads`. 4. **Publish (Network):** Client gets `FileId`s, builds the `componentsJson`, and POSTs to `/api/messages`. 5. **Resolve (Network):** Server broadcasts the new message via Gateway. Client swaps "Dummy" for "Real". ### 3.2 New/Modified Database Models ```dart @Entity() class Message { // ... existing fields ... // Search Index (Server concatenates text from all components) String content; // Source of Truth (JSON List) String componentsJson; } @Entity() class File { int id; int uploaderId; String path; // /uploads/uuid.jpg String mimeType; int width; // CRITICAL for layout int height; int sizeBytes; bool isAttached; // False until linked to a Message DateTime createdAt; } ``` ### 3.3 Component JSON Schema All items in `componentsJson` must follow this structure. **Base Wrapper:** ```json { "type": "text | gallery | collapsible | embed", "modifiers":, // "spoiler" applies blur "fallback": "String for push notifs", "data": { ... } } ``` **Gallery Component (Images/Video):** ```json { "type": "gallery", "modifiers": [], "fallback": "Image", "data": { "items": } } ``` --- ## 4. Gateway Protocol Specification (WebSockets) *The server implements a WebSocket Gateway at `/gateway`.* ### Connection & Auth * **URL:** `ws://host:port/gateway` * **Auth:** `?token=` (Query param) or `Authorization: Bearer ` (Header). * **OpCode: Ready** (Server -> Client on connect): ```json { "op": "ready", "connectionId": "gw_1", "userId": "alice@home" } ``` ### Client -> Server Ops **Subscribe:** ```json { "op": "subscribe", "channelIds": [12, 13] } ``` **Unsubscribe:** ```json { "op": "unsubscribe", "channelIds": [12] } ``` **Heartbeat:** ```json { "op": "ping" } ``` ### Server -> Client Ops (Events) **Message Created:** ```json { "op": "event", "event": "message.created", "channelId": 12, "message": { "id": 101, "content": "Legacy text or fallback", "componentsJson": "[...]", "authorId": "alice@home", "createdAt": "..." } } ``` *(Also supports `message.updated` and `message.deleted`)* --- ## 5. API Reference: Pagination & Uploads ### GET /api/messages Used for initial load and history backfilling. * **Params:** * `channelId` (required) * `limit` (default 50) * `before` (Message ID) -> Load older messages. * `after` (Message ID) -> Load newer messages (catch-up). * **Response:** ```json { "messages": [], "hasMore": true, "nextBefore": 51, // Cursor for older "nextAfter": 100 // Cursor for newer } ``` ### POST /api/uploads (New) * **Format:** `multipart/form-data` * **Response:** ```json { "id": 505, "url": "/uploads/505.png", "width": 1920, "height": 1080, "mimeType": "image/png" } ```