feat: implement MLS lifecycle and multi-device support

Phase 5.3 (MLS lifecycle):
- Add group.proto with RemoveMember, UpdateGroupMetadata, ListGroupMembers, RotateKeys RPCs
- Add GroupService domain logic with metadata and membership persistence
- Add v2 RPC handlers for all 4 group management endpoints (method IDs 410-413)
- Add SDK functions: remove_member_from_group, leave_group, rotate_group_keys, set_group_metadata, get_group_members
- Add REPL commands: /group remove, /group rename, /group rotate-keys, /group leave
- Add 5 unit tests for GroupService (metadata CRUD, membership add/list/remove)

Phase 5.1 (multi-device):
- Wire device_id through SDK fetch/ack functions (fetch_for_device, ack)
- Add /devices list|add|remove REPL commands with tab completion
- Add clear_failed_outbox to ConversationStore
- Fix missing message_id/device_id fields in SDK proto struct initializers
This commit is contained in:
2026-03-04 20:20:55 +01:00
parent a90020fe89
commit b94248b3b6
7 changed files with 698 additions and 129 deletions

61
proto/qpq/v1/group.proto Normal file
View File

@@ -0,0 +1,61 @@
syntax = "proto3";
package qpq.v1;
// Group management (4 methods).
// Method IDs: 410-413.
// RemoveMember (410): Remove a member from a group.
message RemoveMemberRequest {
bytes group_id = 1;
bytes member_identity_key = 2;
}
message RemoveMemberResponse {
bytes commit = 1;
}
// UpdateGroupMetadata (411): Set group name, description, avatar.
message UpdateGroupMetadataRequest {
bytes group_id = 1;
string name = 2;
string description = 3;
bytes avatar_hash = 4;
}
message UpdateGroupMetadataResponse {
bool success = 1;
}
// ListGroupMembers (412): List members of a group.
message ListGroupMembersRequest {
bytes group_id = 1;
}
message ListGroupMembersResponse {
repeated GroupMemberInfo members = 1;
}
message GroupMemberInfo {
bytes identity_key = 1;
string username = 2;
uint64 joined_at = 3;
}
// RotateKeys (413): Trigger key rotation (Update proposal + Commit).
message RotateKeysRequest {
bytes group_id = 1;
}
message RotateKeysResponse {
bytes commit = 1;
}
// GroupMetadata stored server-side.
message GroupMetadata {
bytes group_id = 1;
string name = 2;
string description = 3;
bytes avatar_hash = 4;
bytes creator_key = 5;
uint64 created_at = 6;
}