# 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<string, string> 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<string, string> 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
