270 lines
5.5 KiB
Markdown
270 lines
5.5 KiB
Markdown
|
|
# WebSocket API Specification v0.1
|
|
|
|
This document outlines the WebSocket protocol for the chat application. It defines the message envelope and all frame types for client-server communication.
|
|
|
|
## 0.1 — Protocol Specification
|
|
|
|
### Goal
|
|
Define the shared message envelope and all WebSocket frame types as a single source of truth that every client and the backend implement against.
|
|
|
|
### WebSocket Envelope Format
|
|
All messages sent over the WebSocket connection will be JSON objects conforming to the following structure:
|
|
|
|
```json
|
|
{
|
|
"type": "string",
|
|
"payload": "object",
|
|
"id": "string",
|
|
"timestamp": "string"
|
|
}
|
|
```
|
|
|
|
- `type`: The type of frame being sent. This determines the shape of the `payload` object.
|
|
- `payload`: A JSON object containing the data for the frame.
|
|
- `id`: A unique identifier for the message (e.g., a UUID).
|
|
- `timestamp`: An ISO 8601 formatted timestamp string indicating when the message was created.
|
|
|
|
---
|
|
|
|
### Client → Server Frame Types
|
|
|
|
#### `Authenticate`
|
|
Sent by the client to authenticate the WebSocket session upon connection.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"token": "string" // JWT token
|
|
}
|
|
```
|
|
|
|
#### `SendMessage`
|
|
Sent by the client to send a message to a conversation.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"client_message_id": "string", // UUID generated client-side for idempotency
|
|
"type": "string", // "text" | "image" | "audio" | "gif" | "sticker"
|
|
"body": "string", // Nullable
|
|
"media_ref": "string" // Nullable, reference to uploaded media
|
|
}
|
|
```
|
|
|
|
#### `TypingStart` / `TypingStop`
|
|
Sent by the client to indicate typing activity.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string"
|
|
}
|
|
```
|
|
|
|
#### `MarkRead`
|
|
Sent by the client to mark messages in a conversation as read up to a certain sequence number.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"sequence": "number"
|
|
}
|
|
```
|
|
|
|
#### `AckDelivery`
|
|
Sent by the client to acknowledge the delivery of a message.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"sequence": "number"
|
|
}
|
|
```
|
|
|
|
#### `Ping`
|
|
Sent by the client to check the connection status. The server will respond with a `Pong`.
|
|
|
|
**Payload:**
|
|
```json
|
|
{}
|
|
```
|
|
|
|
#### `Sync`
|
|
Sent by the client upon reconnection to sync missed messages.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversations": [
|
|
{
|
|
"id": "string",
|
|
"last_sequence": "number"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Server → Client Frame Types
|
|
|
|
#### `NewMessage`
|
|
Sent by the server when a new message is added to a conversation.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"sequence": "number",
|
|
"sender_id": "string",
|
|
"type": "string", // "text" | "image" | "audio" | "gif" | "sticker"
|
|
"body": "string", // Nullable
|
|
"media": "object", // Nullable Media metadata object
|
|
"timestamp": "string", // ISO 8601
|
|
"client_message_id": "string" // Echoed back from sender
|
|
}
|
|
```
|
|
|
|
#### `MessageDelivered`
|
|
Sent by the server to confirm a message has been delivered.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"sequence": "number",
|
|
"timestamp": "string" // ISO 8601
|
|
}
|
|
```
|
|
|
|
#### `MessageRead`
|
|
Sent by the server to indicate a message has been read by a recipient.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"sequence": "number",
|
|
"timestamp": "string" // ISO 8601
|
|
}
|
|
```
|
|
|
|
#### `TypingIndicator`
|
|
Sent by the server to show that a user is typing in a conversation.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"user_id": "string",
|
|
"active": "boolean"
|
|
}
|
|
```
|
|
|
|
#### `PresenceUpdate`
|
|
Sent by the server to update a user's presence status.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"user_id": "string",
|
|
"status": "string", // "online" | "offline"
|
|
"last_seen": "string" // ISO 8601
|
|
}
|
|
```
|
|
|
|
#### `MediaReady`
|
|
Sent by the server when media processing is complete and URLs are available.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"conversation_id": "string",
|
|
"sequence": "number",
|
|
"media": "object" // Full Media metadata object
|
|
}
|
|
```
|
|
|
|
#### `Error`
|
|
Sent by the server when an error occurs.
|
|
|
|
**Payload:**
|
|
```json
|
|
{
|
|
"code": "string", // See Error Code Enum
|
|
"message": "string",
|
|
"ref_id": "string" // Optional, correlates to the client request ID
|
|
}
|
|
```
|
|
|
|
#### `Pong`
|
|
Sent by the server in response to a client's `Ping`.
|
|
|
|
**Payload:**
|
|
```json
|
|
{}
|
|
```
|
|
|
|
---
|
|
|
|
### Media Metadata Object
|
|
|
|
This object contains metadata for media attachments.
|
|
|
|
```json
|
|
{
|
|
"original_url": "string",
|
|
"thumbnail_url": "string",
|
|
"preview_url": "string",
|
|
"width": "number",
|
|
"height": "number",
|
|
"duration_seconds": "number", // Nullable
|
|
"file_size_bytes": "number",
|
|
"mime_type": "string",
|
|
"blurhash": "string" // Nullable
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Error Code Enum
|
|
|
|
- `auth_failed`: Authentication failed.
|
|
- `rate_limited`: The client is sending messages too frequently.
|
|
- `invalid_payload`: The message payload is malformed or invalid.
|
|
- `conversation_not_found`: The specified conversation does not exist.
|
|
- `internal_server_error`: An unexpected error occurred on the server.
|
|
- `not_authorized`: The client is not authorized to perform the action.
|
|
|
|
---
|
|
|
|
### Reconnection Contract
|
|
|
|
If a client disconnects, it can attempt to reconnect and sync missed messages.
|
|
|
|
1. Client reconnects to the WebSocket.
|
|
2. Client sends a `Sync` message.
|
|
|
|
**`Sync` Frame (Client → Server):**
|
|
```json
|
|
{
|
|
"type": "Sync",
|
|
"payload": {
|
|
"conversations": [
|
|
{
|
|
"id": "string",
|
|
"last_sequence": "number"
|
|
}
|
|
]
|
|
},
|
|
"id": "string",
|
|
"timestamp": "string"
|
|
}
|
|
```
|
|
|
|
3. The server will respond with a batch of `NewMessage` frames for each conversation, containing all messages since the `last_sequence` number provided by the client.
|