added websocket/api specification
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
|
||||
# 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.
|
||||
Reference in New Issue
Block a user