# Feature Specification: Protocol Definition (Protocol Buffers & gRPC) **ID:** PROTO-001 **Version:** 1.0 **Status:** Planned **Priority:** Critical ## Overview Protocol Buffers and gRPC service definitions for communication between client and server applications. ## Protocol Design Principles - **Efficient:** Binary format, fast serialization/deserialization - **Versioned:** Backwards compatible message changes - **Typed:** Strong typing prevents data corruption - **Language Agnostic:** Go server, potential clients in any language - **Streaming:** Support for voice packet streaming ## Protobuf File Structure ### File Organization ``` proto/ ├── common.proto # Shared message types ├── auth.proto # Authentication service ├── channel.proto # Channel management service ├── presence.proto # Presence & user status service └── voice.proto # Voice streaming service ``` ## Common Types (common.proto) ```protobuf syntax = "proto3"; package openspeak.v1; // Timestamp for consistency message Timestamp { int64 seconds = 1; // Unix timestamp int32 nanos = 2; } // Error details message Error { string code = 1; // Error code (e.g., "UNAUTHORIZED") string message = 2; // Human-readable message map details = 3; // Additional context } // Response status message Status { bool success = 1; Error error = 2; } // Pagination support message PaginationRequest { int32 page = 1; int32 page_size = 2; string sort_by = 3; } message PaginationResponse { int32 page = 1; int32 page_size = 2; int32 total_count = 3; int32 total_pages = 4; } ``` ## Authentication Service (auth.proto) ```protobuf syntax = "proto3"; package openspeak.v1; import "common.proto"; service AuthService { // Login with admin token rpc Login(LoginRequest) returns (LoginResponse); // Validate current session rpc ValidateToken(ValidateTokenRequest) returns (ValidateTokenResponse); // List permissions for current user rpc GetMyPermissions(GetMyPermissionsRequest) returns (GetMyPermissionsResponse); } message LoginRequest { string token = 1; } message LoginResponse { Status status = 1; string session_id = 2; // Server-assigned session ID string user_id = 3; repeated string permissions = 4; int64 expires_at = 5; // Unix timestamp } message ValidateTokenRequest { string token = 1; } message ValidateTokenResponse { bool valid = 1; string user_id = 2; repeated string permissions = 3; } message GetMyPermissionsRequest {} message GetMyPermissionsResponse { repeated string permissions = 1; string user_id = 2; } ``` ## Channel Service (channel.proto) ```protobuf syntax = "proto3"; package openspeak.v1; import "common.proto"; service ChannelService { // Create new channel rpc CreateChannel(CreateChannelRequest) returns (CreateChannelResponse); // Get channel details rpc GetChannel(GetChannelRequest) returns (Channel); // List all channels rpc ListChannels(ListChannelsRequest) returns (ListChannelsResponse); // Update channel settings rpc UpdateChannel(UpdateChannelRequest) returns (Channel); // Delete channel rpc DeleteChannel(DeleteChannelRequest) returns (Status); // Join channel rpc JoinChannel(JoinChannelRequest) returns (JoinChannelResponse); // Leave channel rpc LeaveChannel(LeaveChannelRequest) returns (Status); // List channel members rpc ListMembers(ListMembersRequest) returns (ListMembersResponse); // Subscribe to channel events rpc SubscribeChannelEvents(SubscribeChannelEventsRequest) returns (stream ChannelEvent); } message Channel { string id = 1; string name = 2; string description = 3; bool is_public = 4; string owner_id = 5; repeated string member_ids = 6; int32 max_users = 7; int64 created_at = 8; int64 updated_at = 9; ChannelStatus status = 10; } enum ChannelStatus { ACTIVE = 0; ARCHIVED = 1; DELETED = 2; } message CreateChannelRequest { string name = 1; string description = 2; bool is_public = 3; int32 max_users = 4; } message CreateChannelResponse { Status status = 1; Channel channel = 2; } message GetChannelRequest { string channel_id = 1; } message ListChannelsRequest { PaginationRequest pagination = 1; bool include_private = 2; // For non-admin users } message ListChannelsResponse { repeated Channel channels = 1; PaginationResponse pagination = 2; } message UpdateChannelRequest { string channel_id = 1; string name = 2; string description = 3; bool is_public = 4; int32 max_users = 5; } message DeleteChannelRequest { string channel_id = 1; bool hard_delete = 2; // true = hard delete, false = archive } message JoinChannelRequest { string channel_id = 1; } message JoinChannelResponse { Status status = 1; Channel channel = 2; repeated UserPresence members = 3; } message LeaveChannelRequest { string channel_id = 1; } message ListMembersRequest { string channel_id = 1; PaginationRequest pagination = 2; } message ListMembersResponse { repeated UserPresence members = 1; PaginationResponse pagination = 2; } message SubscribeChannelEventsRequest { string channel_id = 1; } message ChannelEvent { string channel_id = 1; string event_type = 2; // "user_joined", "user_left", "updated" int64 timestamp = 3; string user_id = 4; // For user-related events map data = 5; // Event-specific data } ``` ## Presence Service (presence.proto) ```protobuf syntax = "proto3"; package openspeak.v1; import "common.proto"; service PresenceService { // Get current user 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 members in channel rpc ListChannelMembers(ListChannelMembersRequest) returns (ListChannelMembersResponse); // Subscribe to presence events rpc SubscribePresenceEvents(SubscribePresenceRequest) returns (stream PresenceEvent); // Report activity/heartbeat rpc ReportActivity(ReportActivityRequest) returns (Status); // Update user status rpc SetPresenceStatus(SetPresenceStatusRequest) returns (UserPresence); // Update mute status rpc SetMuteStatus(SetMuteStatusRequest) returns (UserPresence); } message UserPresence { string user_id = 1; PresenceStatus status = 2; string current_channel_id = 3; int64 last_seen = 4; bool is_microphone_muted = 5; bool is_speaker_muted = 6; string client_version = 7; string platform = 8; int64 connected_at = 9; } enum PresenceStatus { OFFLINE = 0; ONLINE = 1; IDLE = 2; DO_NOT_DISTURB = 3; AWAY = 4; } message GetPresenceRequest { string user_id = 1; } message ListOnlineUsersRequest { PaginationRequest pagination = 1; } message ListOnlineUsersResponse { repeated UserPresence users = 1; PaginationResponse pagination = 2; } message ListChannelMembersRequest { string channel_id = 1; PaginationRequest pagination = 2; } message ListChannelMembersResponse { repeated UserPresence members = 1; PaginationResponse pagination = 2; } message SubscribePresenceRequest {} message PresenceEvent { string event_type = 1; // "user_online", "user_offline", "status_changed", "channel_changed" UserPresence presence = 2; int64 timestamp = 3; } message ReportActivityRequest { string user_id = 1; } message SetPresenceStatusRequest { PresenceStatus status = 1; } message SetMuteStatusRequest { bool microphone_muted = 1; bool speaker_muted = 2; } ``` ## Voice Service (voice.proto) ```protobuf syntax = "proto3"; package openspeak.v1; service VoiceService { // Publish voice packets to server rpc PublishVoiceStream(stream VoicePacket) returns (stream PublishVoiceResponse); // Subscribe to voice packets from channel rpc SubscribeVoiceStream(SubscribeVoiceRequest) returns (stream VoicePacket); } message VoicePacket { string source_user_id = 1; string channel_id = 2; uint32 sequence_number = 3; uint32 timestamp = 4; // RTP timestamp uint32 ssrc = 5; // Synchronization source bytes payload = 6; // Opus-encoded audio int32 payload_length = 7; // Redundant with len(payload), for verification int64 client_timestamp = 8; // When packet was created (ms) } message PublishVoiceResponse { bool success = 1; string error_message = 2; uint32 last_received_sequence = 3; // Server's last received seq } message SubscribeVoiceRequest { string channel_id = 1; } ``` ## Message Version Strategy - All messages include implicit version (package name `openspeak.v1`) - Field addition: Always add new fields with sequential numbers - Field removal: Never remove, just deprecate in comments - Field type change: Create new field, deprecate old one - Service method addition: Always safe - Service method removal: Deprecate first, remove in major version ## Example: Backwards Compatible Change ```protobuf // v1: Original message User { string id = 1; string name = 2; } // v2: New field added (safe) message User { string id = 1; string name = 2; string email = 3; // New field string avatar_url = 4; // New field } // Old clients: ignore email and avatar_url // New clients: work normally with all fields // Both versions work together! ``` ## Compilation ```bash # Install protoc compiler # Compile protos to Go protoc --go_out=. --go-grpc_out=. proto/*.proto # Output goes to: pkg/api/openspeak/v1/ ``` ## Testing Strategy - Protobuf message serialization/deserialization tests - Backwards compatibility tests with older message versions - gRPC client/server integration tests - Streaming tests for voice and presence services - Error message format consistency tests