# Gateway Events System Version: 1.0 Status: Specification for Phase 1.2+ --- ## Overview The Gateway Events system is the real-time synchronization layer for Vnox. All state changes (messages, user status, channel creation, etc.) are broadcast as events to interested clients. Events follow a standard structure and allow clients to: - Stay synchronized without polling - React to user actions in real-time - Build responsive UIs - Implement typing indicators and read receipts --- ## Event Structure ### Standard Packet Format ```json { "op": 0, "event": "MESSAGE_CREATE", "data": { "message_id": "...", "channel_id": "...", "sender_id": "...", "content": "...", "timestamp": "..." } } ``` ### Fields | Field | Type | Description | | ----- | ------ | ------------------------------------ | | op | u32 | Opcode (0=event, 1=command response) | | event | String | Event type name | | data | Object | Event-specific payload | --- ## Message Events Events related to text messages in channels. ### MESSAGE_CREATE Sent when a message is posted. **Payload:** ```json { "message_id": "uuid", "channel_id": "uuid", "sender_id": "uuid", "sender_name": "string", "content": "string", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Everyone with `VIEW_CHANNEL` permission --- ### MESSAGE_UPDATE Sent when a message is edited. **Payload:** ```json { "message_id": "uuid", "channel_id": "uuid", "content": "string (new content)", "edited_at": "2026-06-05T12:35:00Z" } ``` **Broadcast:** Everyone with `VIEW_CHANNEL` permission --- ### MESSAGE_DELETE Sent when a message is deleted. **Payload:** ```json { "message_id": "uuid", "channel_id": "uuid", "deleted_at": "2026-06-05T12:36:00Z" } ``` **Broadcast:** Everyone with `VIEW_CHANNEL` permission --- ### MESSAGE_REACTION_ADD Sent when a user adds an emoji reaction. **Payload:** ```json { "message_id": "uuid", "channel_id": "uuid", "reactor_id": "uuid", "emoji": "👍" } ``` **Broadcast:** Everyone with `VIEW_CHANNEL` permission --- ### MESSAGE_REACTION_REMOVE Sent when a user removes an emoji reaction. **Payload:** ```json { "message_id": "uuid", "channel_id": "uuid", "reactor_id": "uuid", "emoji": "👍" } ``` **Broadcast:** Everyone with `VIEW_CHANNEL` permission --- ## Typing Events ### TYPING_START Sent when a user begins typing. **Payload:** ```json { "channel_id": "uuid", "user_id": "uuid", "user_name": "string", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Everyone with `VIEW_CHANNEL` permission **Note:** Sender must stop sending after 5-10 seconds of inactivity. --- ### TYPING_STOP Sent when a user stops typing. **Payload:** ```json { "channel_id": "uuid", "user_id": "uuid" } ``` **Broadcast:** Everyone with `VIEW_CHANNEL` permission --- ## Read Receipt Events ### MESSAGE_ACK Sent when a user reads up to a certain message. **Payload:** ```json { "channel_id": "uuid", "user_id": "uuid", "message_id": "uuid (last read)", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Sender and channel members --- ## Guild Events ### GUILD_CREATE Sent when a new guild is created. **Payload:** ```json { "guild_id": "uuid", "owner_id": "uuid", "name": "string", "description": "string", "icon": "asset_id (nullable)", "created_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All guild members on login --- ### GUILD_UPDATE Sent when guild settings change. **Payload:** ```json { "guild_id": "uuid", "changes": { "name": "new name", "description": "new description", "icon": "asset_id (nullable)" }, "updated_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All guild members --- ### GUILD_DELETE Sent when a guild is deleted. **Payload:** ```json { "guild_id": "uuid", "deleted_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All former members --- ## Category Events ### CATEGORY_CREATE Sent when a category is created. **Payload:** ```json { "category_id": "uuid", "guild_id": "uuid", "name": "string", "position": 0, "created_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `VIEW_CHANNEL` permission --- ### CATEGORY_UPDATE Sent when category properties change. **Payload:** ```json { "category_id": "uuid", "guild_id": "uuid", "changes": { "name": "new name", "position": 1 }, "updated_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `VIEW_CHANNEL` permission --- ### CATEGORY_DELETE Sent when a category is deleted. **Payload:** ```json { "category_id": "uuid", "guild_id": "uuid", "deleted_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `VIEW_CHANNEL` permission --- ## Channel Events ### CHANNEL_CREATE Sent when a channel is created. **Payload:** ```json { "channel_id": "uuid", "guild_id": "uuid", "category_id": "uuid (nullable)", "type": "TEXT | VOICE | ANNOUNCEMENT | STAGE", "name": "string", "topic": "string (nullable)", "position": 0, "created_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `VIEW_CHANNEL` permission --- ### CHANNEL_UPDATE Sent when channel properties change. **Payload:** ```json { "channel_id": "uuid", "guild_id": "uuid", "changes": { "name": "new name", "topic": "new topic", "position": 2 }, "updated_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `VIEW_CHANNEL` permission --- ### CHANNEL_DELETE Sent when a channel is deleted. **Payload:** ```json { "channel_id": "uuid", "guild_id": "uuid", "deleted_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `VIEW_CHANNEL` permission --- ## Role Events ### ROLE_CREATE Sent when a new role is created. **Payload:** ```json { "role_id": "uuid", "guild_id": "uuid", "name": "string", "color": 16711680, "permissions": 0, "position": 5, "hoist": false, "mentionable": true, "created_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `MANAGE_ROLES` permission --- ### ROLE_UPDATE Sent when role settings change. **Payload:** ```json { "role_id": "uuid", "guild_id": "uuid", "changes": { "name": "new name", "color": 16711680, "permissions": 1024, "position": 6 }, "updated_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `MANAGE_ROLES` permission --- ### ROLE_DELETE Sent when a role is deleted. **Payload:** ```json { "role_id": "uuid", "guild_id": "uuid", "deleted_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `MANAGE_ROLES` permission --- ## Invite Events ### INVITE_CREATE Sent when a new invite is generated. **Payload:** ```json { "invite_id": "uuid", "guild_id": "uuid", "code": "string", "creator_id": "uuid", "expires_at": "2026-06-10T12:34:56Z (nullable)", "max_uses": 10, "uses": 0, "created_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `MANAGE_INVITES` permission --- ### INVITE_DELETE Sent when an invite is revoked. **Payload:** ```json { "invite_id": "uuid", "guild_id": "uuid", "code": "string", "deleted_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members with `MANAGE_INVITES` permission --- ## Member Events ### MEMBER_JOIN Sent when a user joins a guild. **Payload:** ```json { "guild_id": "uuid", "user_id": "uuid", "user_name": "string", "nickname": "string (nullable)", "joined_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All guild members --- ### MEMBER_UPDATE Sent when member data changes (roles, nickname, timeout). **Payload:** ```json { "guild_id": "uuid", "user_id": "uuid", "changes": { "nickname": "new nickname", "roles": ["role_id_1", "role_id_2"], "timeout_until": "2026-06-05T13:34:56Z (nullable)" }, "updated_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All guild members with `MANAGE_MEMBERS` permission --- ### MEMBER_LEAVE Sent when a user leaves a guild. **Payload:** ```json { "guild_id": "uuid", "user_id": "uuid", "left_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All remaining guild members --- ## Voice Events ### VOICE_STATE_UPDATE Sent when a user's voice state changes (connect, disconnect, mute, deafen). **Payload:** ```json { "user_id": "uuid", "user_name": "string", "guild_id": "uuid", "channel_id": "uuid (nullable, null = disconnect)", "muted": false, "deafened": false, "self_muted": false, "self_deafened": false, "speaking": false, "volume_level": 0.8, "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All members of the voice channel and moderators --- ## Presence Events ### PRESENCE_UPDATE Sent when a user's presence (online status, activity) changes. **Payload:** ```json { "user_id": "uuid", "status": "ONLINE | IDLE | DO_NOT_DISTURB | OFFLINE | INVISIBLE", "activity_type": "PLAYING | LISTENING | WATCHING | STREAMING | CUSTOM (nullable)", "activity_text": "string (nullable)", "last_seen": "2026-06-05T12:34:56Z" } ``` **Broadcast:** All connected clients of mutual friends/guild members --- ## Direct Message Events ### DM_CREATE Sent when a new DM channel is opened. **Payload:** ```json { "dm_id": "uuid", "user_id": "uuid", "recipient_id": "uuid", "recipient_name": "string", "created_at": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Both participants --- ### DM_MESSAGE Sent when a direct message is received. **Payload:** ```json { "dm_id": "uuid", "message_id": "uuid", "sender_id": "uuid", "content": "string", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Both participants --- ### DM_TYPING Sent when a user types in a DM. **Payload:** ```json { "dm_id": "uuid", "user_id": "uuid", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Recipient only --- ## Friend Events ### FRIEND_REQUEST Sent when a friend request is received. **Payload:** ```json { "requester_id": "uuid", "requester_name": "string", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Recipient only --- ### FRIEND_ACCEPT Sent when a friend request is accepted. **Payload:** ```json { "friend_id": "uuid", "friend_name": "string", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Both parties --- ### FRIEND_REMOVE Sent when a friendship is ended. **Payload:** ```json { "friend_id": "uuid", "timestamp": "2026-06-05T12:34:56Z" } ``` **Broadcast:** Both parties --- ## Implementation Notes ### Permission Checks The gateway should verify permissions before broadcasting: ``` if event_requires_permission: for client in subscribers: if client.has_permission(event.required_permission): send(client, event) ``` ### Ordering Guarantees Events within a single session are in causal order: - Messages from the same user appear in send order - Role changes before member updates using that role ### Event Deduplication Clients should handle duplicate events gracefully. Use `message_id` or unique event identifiers to deduplicate. ### Backpressure If a client falls behind, the gateway should: 1. Queue up to N events in memory 2. If queue exceeds N, force reconnect (replay full state) 3. Implement exponential backoff for slow clients --- ## Design Goals ✓ Real-time synchronization without polling ✓ Bandwidth efficient (only changed state) ✓ Permissible (respect channel and role visibility) ✓ Ordered causally (maintain consistency) ✓ Extensible (easy to add new event types) ✓ Compatible with federation (events can be bridged)