# Feature Specification: User Presence & Status Tracking **ID:** PRESENCE-001 **Version:** 1.0 **Status:** Planned **Priority:** High ## Overview System for tracking online status, location (which channel users are in), and user availability information across the server. ## User Presence Model ### User Presence State ```protobuf message UserPresence { string user_id = 1; PresenceStatus status = 2; string current_channel_id = 3; // Which channel they're in (if any) int64 last_seen = 4; // Unix timestamp bool is_microphone_muted = 5; // Audio input status bool is_speaker_muted = 6; // Audio output status string client_version = 7; // Client app version string platform = 8; // Windows, Mac, Linux int64 connected_at = 9; // When user connected } enum PresenceStatus { OFFLINE = 0; ONLINE = 1; IDLE = 2; // No activity for 5+ minutes DO_NOT_DISTURB = 3; // User set status (future) AWAY = 4; // Inactive (future) } ``` ## Presence States ### Online - User is connected to server - User has active gRPC connection - Subscribed to events ### Idle - User is connected but inactive - No keyboard/mouse input for 5+ minutes - Still receives events but marked as idle - Returns to Online on activity ### Offline - User is not connected - Server has no active connection - User not visible in online user list ### Do Not Disturb (Future) - User explicitly set this status - Still marked as online - May suppress notifications ## Tracking Mechanism ### Connection Lifecycle ``` Client connects to server ↓ Server creates UserSession ↓ Server broadcasts UserOnline event ↓ All clients update online user list ↓ [User activity in channel] ↓ Client disconnects (graceful or timeout) ↓ Server marks user as offline ↓ Server broadcasts UserOffline event ↓ All clients update online user list ``` ### Session Management **User Session Object:** ```protobuf message UserSession { string user_id = 1; string session_id = 2; // Unique session ID string connection_id = 3; // gRPC connection ID int64 connected_at = 4; int64 last_activity = 5; string current_channel = 6; bool microphone_active = 7; bool speaker_active = 8; string client_version = 9; map metadata = 10; } ``` ### Idle Detection - Track last activity timestamp - Background task checks every 30 seconds - Mark users idle after 5 minutes no activity - Activity events: join/leave channel, toggle mute, send message (future) - Return to online on next activity ### Connection Timeout - If no heartbeat for 30 seconds: assume disconnected - Clean up session - Broadcast UserOffline - Remove from channel members list ## Presence Events ### Events Broadcast Across Server ```protobuf message UserOnlineEvent { UserPresence presence = 1; int64 timestamp = 2; } message UserOfflineEvent { string user_id = 1; int64 timestamp = 2; } message UserStatusChanged { string user_id = 1; PresenceStatus old_status = 2; PresenceStatus new_status = 3; int64 timestamp = 4; } message UserChannelChanged { string user_id = 1; string old_channel_id = 2; string new_channel_id = 3; int64 timestamp = 4; } message UserMuteStateChanged { string user_id = 1; bool microphone_muted = 2; bool speaker_muted = 3; int64 timestamp = 4; } ``` ### Event Distribution - UserOnline/Offline: Broadcast to all connected clients - UserChannelChanged: Broadcast to clients in both channels - UserMuteStateChanged: Broadcast to clients in same channel ## API Endpoints (gRPC) ### Presence Service ```protobuf service PresenceService { // Get current user's presence rpc GetMyPresence(GetPresenceRequest) returns (UserPresence); // Get another user's presence rpc GetUserPresence(GetPresenceRequest) returns (UserPresence); // List all online users rpc ListOnlineUsers(ListOnlineUsersRequest) returns (ListOnlineUsersResponse); // List users in specific channel rpc ListChannelMembers(ListChannelMembersRequest) returns (ListChannelMembersResponse); // Set/Update user status rpc SetPresenceStatus(SetPresenceStatusRequest) returns (UserPresence); // Subscribe to presence events (streaming) rpc SubscribePresenceEvents(PresenceSubscriptionRequest) returns (stream PresenceEvent); // Report user activity (heartbeat) rpc ReportActivity(ReportActivityRequest) returns (ActivityResponse); } ``` ## Mute Status Tracking ### Microphone Mute - User toggles microphone on/off - Status tracked in UserPresence - Broadcast to channel members - Voice packets not sent when muted - Visual indicator for other users ### Speaker Mute - User mutes speaker output - Audio packets received but discarded locally - No bandwidth saved (packets still transmitted) - Other users don't know user is speaker-muted ## Data Storage (Phase 2) Currently in-memory, future persistent storage: - User presence snapshots every 5 minutes - Activity history for audit/analytics - Login/logout timestamps - Channel visit history ## Configuration - Idle timeout: 5 minutes (configurable) - Heartbeat interval: 30 seconds - Presence update interval: When status changes - Max online users tracking: Unlimited initially - Presence event retention: None (real-time only) ## Scalability Considerations - In-memory presence map for fast lookups - Efficient pub/sub for event distribution - Goroutine per connection for heartbeat handling - Channel-scoped events to reduce broadcast traffic - Consider Redis for multi-server deployments (phase 2+) ## Error Handling - User not found: Return NotFound - Session expired: Return Unauthenticated - Invalid status transition: Return InvalidArgument - Broadcast failures: Log and continue ## Testing Strategy - Unit tests for idle detection - Unit tests for presence state transitions - Integration tests for session creation/destruction - Tests for event broadcasting to correct clients - Concurrency tests with many simultaneous connections - Tests for connection timeout detection - Performance tests with large number of online users