diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
index 9fa77542c81c457d095244fbec6aceee8776c316..a538e28e2a409f08d7fc994b5716747813d6f493 100644
--- a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
+++ b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
@@ -11,6 +11,7 @@ public struct ChatComponent: ReducerProtocol {
   public struct State: Equatable, Identifiable {
     public enum ID: Equatable, Hashable {
       case contact(XXModels.Contact.ID)
+      case group(XXModels.Group.ID)
     }
 
     public struct Message: Equatable, Identifiable {
@@ -93,25 +94,33 @@ public struct ChatComponent: ReducerProtocol {
           let myContactId = try messenger.e2e.tryGet().getContact().getId()
           state.myContactId = myContactId
           let queryChat: XXModels.Message.Query.Chat
-          let receivedFileTransfersQuery: XXModels.FileTransfer.Query
-          let sentFileTransfersQuery: XXModels.FileTransfer.Query
+          let receivedFileTransfersPublisher: AnyPublisher<[XXModels.FileTransfer], Error>
+          let sentFileTransfersPublisher: AnyPublisher<[XXModels.FileTransfer], Error>
           switch state.id {
           case .contact(let contactId):
             queryChat = .direct(myContactId, contactId)
-            receivedFileTransfersQuery = .init(
+            receivedFileTransfersPublisher = try db().fetchFileTransfersPublisher(.init(
               contactId: contactId,
               isIncoming: true
-            )
-            sentFileTransfersQuery = .init(
+            ))
+            sentFileTransfersPublisher = try db().fetchFileTransfersPublisher(.init(
               contactId: myContactId,
               isIncoming: false
-            )
+            ))
+          case .group(let groupId):
+            queryChat = .group(groupId)
+            receivedFileTransfersPublisher = Just([])
+              .setFailureType(to: Error.self)
+              .eraseToAnyPublisher()
+            sentFileTransfersPublisher = Just([])
+              .setFailureType(to: Error.self)
+              .eraseToAnyPublisher()
           }
           let messagesQuery = XXModels.Message.Query(chat: queryChat)
           return Publishers.CombineLatest3(
             try db().fetchMessagesPublisher(messagesQuery),
-            try db().fetchFileTransfersPublisher(receivedFileTransfersQuery),
-            try db().fetchFileTransfersPublisher(sentFileTransfersQuery)
+            receivedFileTransfersPublisher,
+            sentFileTransfersPublisher
           )
           .map { messages, receivedFileTransfers, sentFileTransfers in
             (messages, receivedFileTransfers + sentFileTransfers)
@@ -163,6 +172,9 @@ public struct ChatComponent: ReducerProtocol {
                 subscriber.send(completion: .finished)
               }
             )
+          case .group(let groupId):
+            // TODO: send group message
+            fatalError()
           }
           return AnyCancellable {}
         }
@@ -175,21 +187,18 @@ public struct ChatComponent: ReducerProtocol {
         return .none
 
       case .imagePicked(let data):
-        let chatId = state.id
+        guard case .contact(let recipientId) = state.id else { return .none }
         return Effect.run { subscriber in
-          switch chatId {
-          case .contact(let recipientId):
-            sendImage(
-              data,
-              to: recipientId,
-              onError: { error in
-                subscriber.send(.sendFailed(error.localizedDescription))
-              },
-              completion: {
-                subscriber.send(completion: .finished)
-              }
-            )
-          }
+          sendImage(
+            data,
+            to: recipientId,
+            onError: { error in
+              subscriber.send(.sendFailed(error.localizedDescription))
+            },
+            completion: {
+              subscriber.send(completion: .finished)
+            }
+          )
           return AnyCancellable {}
         }
         .subscribe(on: bgQueue)
diff --git a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
index c8f5952864c6f77f04ec42b53b5875a317ee37a4..4303416c8a1635c917efeb5f99ecde246899f5fc 100644
--- a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
+++ b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
@@ -9,7 +9,7 @@ import XXModels
 @testable import ChatFeature
 
 final class ChatComponentTests: XCTestCase {
-  func testStart() {
+  func testStartDirectChat() {
     let contactId = "contact-id".data(using: .utf8)!
     let myContactId = "my-contact-id".data(using: .utf8)!
 
@@ -139,6 +139,112 @@ final class ChatComponentTests: XCTestCase {
     fileTransfersPublisher.send(completion: .finished)
   }
 
+  func testStartGroupChat() {
+    let groupId = "group-id".data(using: .utf8)!
+    let myContactId = "my-contact-id".data(using: .utf8)!
+    let firstMemberId = "member-1-id".data(using: .utf8)!
+    let secondMemberId = "member-2-id".data(using: .utf8)!
+
+    let store = TestStore(
+      initialState: ChatComponent.State(id: .group(groupId)),
+      reducer: ChatComponent()
+    )
+
+    var didFetchMessagesWithQuery: [XXModels.Message.Query] = []
+    let messagesPublisher = PassthroughSubject<[XXModels.Message], Error>()
+
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.messenger.e2e.get = {
+      var e2e: E2E = .unimplemented
+      e2e.getContact.run = {
+        var contact: XXClient.Contact = .unimplemented(Data())
+        contact.getIdFromContact.run = { _ in myContactId }
+        return contact
+      }
+      return e2e
+    }
+    store.dependencies.app.dbManager.getDB.run = {
+      var db: Database = .unimplemented
+      db.fetchMessagesPublisher.run = { query in
+        didFetchMessagesWithQuery.append(query)
+        return messagesPublisher.eraseToAnyPublisher()
+      }
+      return db
+    }
+
+    store.send(.start) {
+      $0.myContactId = myContactId
+    }
+
+    XCTAssertNoDifference(didFetchMessagesWithQuery, [
+      .init(chat: .group(groupId))
+    ])
+
+    messagesPublisher.send([
+      .init(
+        id: 0,
+        senderId: myContactId,
+        recipientId: nil,
+        groupId: groupId,
+        date: Date(timeIntervalSince1970: 0),
+        status: .sent,
+        isUnread: false,
+        text: "Message 0"
+      ),
+      .init(
+        id: 1,
+        senderId: firstMemberId,
+        recipientId: nil,
+        groupId: groupId,
+        date: Date(timeIntervalSince1970: 1),
+        status: .received,
+        isUnread: false,
+        text: "Message 1"
+      ),
+      .init(
+        id: 2,
+        senderId: secondMemberId,
+        recipientId: nil,
+        groupId: groupId,
+        date: Date(timeIntervalSince1970: 2),
+        status: .received,
+        isUnread: false,
+        text: "Message 2"
+      ),
+    ])
+
+    let expectedMessages = IdentifiedArrayOf<ChatComponent.State.Message>(uniqueElements: [
+      .init(
+        id: 0,
+        date: Date(timeIntervalSince1970: 0),
+        senderId: myContactId,
+        text: "Message 0",
+        status: .sent
+      ),
+      .init(
+        id: 1,
+        date: Date(timeIntervalSince1970: 1),
+        senderId: firstMemberId,
+        text: "Message 1",
+        status: .received
+      ),
+      .init(
+        id: 2,
+        date: Date(timeIntervalSince1970: 2),
+        senderId: secondMemberId,
+        text: "Message 2",
+        status: .received
+      ),
+    ])
+
+    store.receive(.didFetchMessages(expectedMessages)) {
+      $0.messages = expectedMessages
+    }
+
+    messagesPublisher.send(completion: .finished)
+  }
+
   func testStartFailure() {
     let store = TestStore(
       initialState: ChatComponent.State(id: .contact("contact-id".data(using: .utf8)!)),
@@ -165,7 +271,7 @@ final class ChatComponentTests: XCTestCase {
     }
   }
 
-  func testSend() {
+  func testSendDirectMessage() {
     struct SendMessageParams: Equatable {
       var text: String
       var recipientId: Data