diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
new file mode 100644
index 0000000000000000000000000000000000000000..6c71789dbbb201122cfda709999ac36984363b55
--- /dev/null
+++ b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
@@ -0,0 +1,208 @@
+import AppCore
+import Combine
+import ComposableArchitecture
+import Foundation
+import XCTestDynamicOverlay
+import XXClient
+import XXMessengerClient
+import XXModels
+
+public struct ChatComponent: ReducerProtocol {
+  public struct State: Equatable, Identifiable {
+    public enum ID: Equatable, Hashable {
+      case contact(Data)
+    }
+
+    public struct Message: Equatable, Identifiable {
+      public init(
+        id: Int64,
+        date: Date,
+        senderId: Data,
+        text: String,
+        status: XXModels.Message.Status,
+        fileTransfer: XXModels.FileTransfer? = nil
+      ) {
+        self.id = id
+        self.date = date
+        self.senderId = senderId
+        self.text = text
+        self.status = status
+        self.fileTransfer = fileTransfer
+      }
+
+      public var id: Int64
+      public var date: Date
+      public var senderId: Data
+      public var text: String
+      public var status: XXModels.Message.Status
+      public var fileTransfer: XXModels.FileTransfer?
+    }
+
+    public init(
+      id: ID,
+      myContactId: Data? = nil,
+      messages: IdentifiedArrayOf<Message> = [],
+      failure: String? = nil,
+      sendFailure: String? = nil,
+      text: String = ""
+    ) {
+      self.id = id
+      self.myContactId = myContactId
+      self.messages = messages
+      self.failure = failure
+      self.sendFailure = sendFailure
+      self.text = text
+    }
+
+    public var id: ID
+    public var myContactId: Data?
+    public var messages: IdentifiedArrayOf<Message>
+    public var failure: String?
+    public var sendFailure: String?
+    @BindableState public var text: String
+  }
+
+  public enum Action: Equatable, BindableAction {
+    case start
+    case didFetchMessages(IdentifiedArrayOf<State.Message>)
+    case sendTapped
+    case sendFailed(String)
+    case imagePicked(Data)
+    case dismissSendFailureTapped
+    case binding(BindingAction<State>)
+  }
+
+  public init() {}
+
+  @Dependency(\.app.messenger) var messenger: Messenger
+  @Dependency(\.app.dbManager.getDB) var db: DBManagerGetDB
+  @Dependency(\.app.sendMessage) var sendMessage: SendMessage
+  @Dependency(\.app.sendImage) var sendImage: SendImage
+  @Dependency(\.app.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
+  @Dependency(\.app.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>
+
+  public var body: some ReducerProtocol<State, Action> {
+    BindingReducer()
+    Reduce { state, action in
+      enum FetchEffectId {}
+
+      switch action {
+      case .start:
+        state.failure = nil
+        do {
+          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
+          switch state.id {
+          case .contact(let contactId):
+            queryChat = .direct(myContactId, contactId)
+            receivedFileTransfersQuery = .init(
+              contactId: contactId,
+              isIncoming: true
+            )
+            sentFileTransfersQuery = .init(
+              contactId: myContactId,
+              isIncoming: false
+            )
+          }
+          let messagesQuery = XXModels.Message.Query(chat: queryChat)
+          return Publishers.CombineLatest3(
+            try db().fetchMessagesPublisher(messagesQuery),
+            try db().fetchFileTransfersPublisher(receivedFileTransfersQuery),
+            try db().fetchFileTransfersPublisher(sentFileTransfersQuery)
+          )
+          .map { messages, receivedFileTransfers, sentFileTransfers in
+            (messages, receivedFileTransfers + sentFileTransfers)
+          }
+          .assertNoFailure()
+          .map { messages, fileTransfers in
+            messages.compactMap { message in
+              guard let id = message.id else { return nil }
+              return State.Message(
+                id: id,
+                date: message.date,
+                senderId: message.senderId,
+                text: message.text,
+                status: message.status,
+                fileTransfer: fileTransfers.first { $0.id == message.fileTransferId }
+              )
+            }
+          }
+          .removeDuplicates()
+          .map { IdentifiedArrayOf<State.Message>(uniqueElements: $0) }
+          .map(Action.didFetchMessages)
+          .subscribe(on: bgQueue)
+          .receive(on: mainQueue)
+          .eraseToEffect()
+          .cancellable(id: FetchEffectId.self, cancelInFlight: true)
+        } catch {
+          state.failure = error.localizedDescription
+          return .none
+        }
+
+      case .didFetchMessages(let messages):
+        state.messages = messages
+        return .none
+
+      case .sendTapped:
+        let text = state.text
+        let chatId = state.id
+        state.text = ""
+        return Effect.run { subscriber in
+          switch chatId {
+          case .contact(let recipientId):
+            sendMessage(
+              text: text,
+              to: recipientId,
+              onError: { error in
+                subscriber.send(.sendFailed(error.localizedDescription))
+              },
+              completion: {
+                subscriber.send(completion: .finished)
+              }
+            )
+          }
+          return AnyCancellable {}
+        }
+        .subscribe(on: bgQueue)
+        .receive(on: mainQueue)
+        .eraseToEffect()
+
+      case .sendFailed(let failure):
+        state.sendFailure = failure
+        return .none
+
+      case .imagePicked(let data):
+        let chatId = state.id
+        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)
+              }
+            )
+          }
+          return AnyCancellable {}
+        }
+        .subscribe(on: bgQueue)
+        .receive(on: mainQueue)
+        .eraseToEffect()
+
+      case .dismissSendFailureTapped:
+        state.sendFailure = nil
+        return .none
+
+      case .binding(_):
+        return .none
+      }
+    }
+  }
+}
diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatFeature.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatFeature.swift
deleted file mode 100644
index 3538bc2536f23e493a298f2761fd3614711f77da..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/Sources/ChatFeature/ChatFeature.swift
+++ /dev/null
@@ -1,234 +0,0 @@
-import AppCore
-import Combine
-import ComposableArchitecture
-import Foundation
-import XCTestDynamicOverlay
-import XXClient
-import XXMessengerClient
-import XXModels
-
-public struct ChatState: Equatable, Identifiable {
-  public enum ID: Equatable, Hashable {
-    case contact(Data)
-  }
-
-  public struct Message: Equatable, Identifiable {
-    public init(
-      id: Int64,
-      date: Date,
-      senderId: Data,
-      text: String,
-      status: XXModels.Message.Status,
-      fileTransfer: XXModels.FileTransfer? = nil
-    ) {
-      self.id = id
-      self.date = date
-      self.senderId = senderId
-      self.text = text
-      self.status = status
-      self.fileTransfer = fileTransfer
-    }
-
-    public var id: Int64
-    public var date: Date
-    public var senderId: Data
-    public var text: String
-    public var status: XXModels.Message.Status
-    public var fileTransfer: XXModels.FileTransfer?
-  }
-
-  public init(
-    id: ID,
-    myContactId: Data? = nil,
-    messages: IdentifiedArrayOf<Message> = [],
-    failure: String? = nil,
-    sendFailure: String? = nil,
-    text: String = ""
-  ) {
-    self.id = id
-    self.myContactId = myContactId
-    self.messages = messages
-    self.failure = failure
-    self.sendFailure = sendFailure
-    self.text = text
-  }
-
-  public var id: ID
-  public var myContactId: Data?
-  public var messages: IdentifiedArrayOf<Message>
-  public var failure: String?
-  public var sendFailure: String?
-  @BindableState public var text: String
-}
-
-public enum ChatAction: Equatable, BindableAction {
-  case start
-  case didFetchMessages(IdentifiedArrayOf<ChatState.Message>)
-  case sendTapped
-  case sendFailed(String)
-  case imagePicked(Data)
-  case dismissSendFailureTapped
-  case binding(BindingAction<ChatState>)
-}
-
-public struct ChatEnvironment {
-  public init(
-    messenger: Messenger,
-    db: DBManagerGetDB,
-    sendMessage: SendMessage,
-    sendImage: SendImage,
-    mainQueue: AnySchedulerOf<DispatchQueue>,
-    bgQueue: AnySchedulerOf<DispatchQueue>
-  ) {
-    self.messenger = messenger
-    self.db = db
-    self.sendMessage = sendMessage
-    self.sendImage = sendImage
-    self.mainQueue = mainQueue
-    self.bgQueue = bgQueue
-  }
-
-  public var messenger: Messenger
-  public var db: DBManagerGetDB
-  public var sendMessage: SendMessage
-  public var sendImage: SendImage
-  public var mainQueue: AnySchedulerOf<DispatchQueue>
-  public var bgQueue: AnySchedulerOf<DispatchQueue>
-}
-
-#if DEBUG
-extension ChatEnvironment {
-  public static let unimplemented = ChatEnvironment(
-    messenger: .unimplemented,
-    db: .unimplemented,
-    sendMessage: .unimplemented,
-    sendImage: .unimplemented,
-    mainQueue: .unimplemented,
-    bgQueue: .unimplemented
-  )
-}
-#endif
-
-public let chatReducer = Reducer<ChatState, ChatAction, ChatEnvironment>
-{ state, action, env in
-  enum FetchEffectId {}
-
-  switch action {
-  case .start:
-    state.failure = nil
-    do {
-      let myContactId = try env.messenger.e2e.tryGet().getContact().getId()
-      state.myContactId = myContactId
-      let queryChat: XXModels.Message.Query.Chat
-      let receivedFileTransfersQuery: XXModels.FileTransfer.Query
-      let sentFileTransfersQuery: XXModels.FileTransfer.Query
-      switch state.id {
-      case .contact(let contactId):
-        queryChat = .direct(myContactId, contactId)
-        receivedFileTransfersQuery = .init(
-          contactId: contactId,
-          isIncoming: true
-        )
-        sentFileTransfersQuery = .init(
-          contactId: myContactId,
-          isIncoming: false
-        )
-      }
-      let messagesQuery = XXModels.Message.Query(chat: queryChat)
-      return Publishers.CombineLatest3(
-        try env.db().fetchMessagesPublisher(messagesQuery),
-        try env.db().fetchFileTransfersPublisher(receivedFileTransfersQuery),
-        try env.db().fetchFileTransfersPublisher(sentFileTransfersQuery)
-      )
-      .map { messages, receivedFileTransfers, sentFileTransfers in
-        (messages, receivedFileTransfers + sentFileTransfers)
-      }
-      .assertNoFailure()
-      .map { messages, fileTransfers in
-        messages.compactMap { message in
-          guard let id = message.id else { return nil }
-          return ChatState.Message(
-            id: id,
-            date: message.date,
-            senderId: message.senderId,
-            text: message.text,
-            status: message.status,
-            fileTransfer: fileTransfers.first { $0.id == message.fileTransferId }
-          )
-        }
-      }
-      .removeDuplicates()
-      .map { IdentifiedArrayOf<ChatState.Message>(uniqueElements: $0) }
-      .map(ChatAction.didFetchMessages)
-      .subscribe(on: env.bgQueue)
-      .receive(on: env.mainQueue)
-      .eraseToEffect()
-      .cancellable(id: FetchEffectId.self, cancelInFlight: true)
-    } catch {
-      state.failure = error.localizedDescription
-      return .none
-    }
-
-  case .didFetchMessages(let messages):
-    state.messages = messages
-    return .none
-
-  case .sendTapped:
-    let text = state.text
-    let chatId = state.id
-    state.text = ""
-    return Effect.run { subscriber in
-      switch chatId {
-      case .contact(let recipientId):
-        env.sendMessage(
-          text: text,
-          to: recipientId,
-          onError: { error in
-            subscriber.send(.sendFailed(error.localizedDescription))
-          },
-          completion: {
-            subscriber.send(completion: .finished)
-          }
-        )
-      }
-      return AnyCancellable {}
-    }
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .sendFailed(let failure):
-    state.sendFailure = failure
-    return .none
-
-  case .imagePicked(let data):
-    let chatId = state.id
-    return Effect.run { subscriber in
-      switch chatId {
-      case .contact(let recipientId):
-        env.sendImage(
-          data,
-          to: recipientId,
-          onError: { error in
-            subscriber.send(.sendFailed(error.localizedDescription))
-          },
-          completion: {
-            subscriber.send(completion: .finished)
-          }
-        )
-      }
-      return AnyCancellable {}
-    }
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .dismissSendFailureTapped:
-    state.sendFailure = nil
-    return .none
-
-  case .binding(_):
-    return .none
-  }
-}
-.binding()
diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift
index 6058b61bc86fe9c54f25483e7de2a05c5a35dc9d..7ac107f479b1bf8dee80c566043997caa7644cb0 100644
--- a/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift
+++ b/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift
@@ -3,21 +3,21 @@ import ComposableArchitecture
 import SwiftUI
 
 public struct ChatView: View {
-  public init(store: Store<ChatState, ChatAction>) {
+  public init(store: StoreOf<ChatComponent>) {
     self.store = store
   }
 
-  let store: Store<ChatState, ChatAction>
+  let store: StoreOf<ChatComponent>
   @State var isPresentingImagePicker = false
 
   struct ViewState: Equatable {
     var myContactId: Data?
-    var messages: IdentifiedArrayOf<ChatState.Message>
+    var messages: IdentifiedArrayOf<ChatComponent.State.Message>
     var failure: String?
     var sendFailure: String?
     var text: String
 
-    init(state: ChatState) {
+    init(state: ChatComponent.State) {
       myContactId = state.myContactId
       messages = state.messages
       failure = state.failure
@@ -84,7 +84,7 @@ public struct ChatView: View {
           HStack {
             TextField("Text", text: viewStore.binding(
               get: \.text,
-              send: { ChatAction.set(\.$text, $0) }
+              send: { ChatComponent.Action.set(\.$text, $0) }
             ))
             .textFieldStyle(.roundedBorder)
 
@@ -122,7 +122,7 @@ public struct ChatView: View {
   }
 
   struct MessageView: View {
-    var message: ChatState.Message
+    var message: ChatComponent.State.Message
     var myContactId: Data?
 
     var alignment: Alignment {
@@ -199,7 +199,7 @@ public struct ChatView_Previews: PreviewProvider {
   public static var previews: some View {
     NavigationView {
       ChatView(store: Store(
-        initialState: ChatState(
+        initialState: ChatComponent.State(
           id: .contact("contact-id".data(using: .utf8)!),
           myContactId: "my-contact-id".data(using: .utf8)!,
           messages: [
@@ -262,8 +262,7 @@ public struct ChatView_Previews: PreviewProvider {
           failure: "Something went wrong when fetching messages from database.",
           sendFailure: "Something went wrong when sending message."
         ),
-        reducer: .empty,
-        environment: ()
+        reducer: EmptyReducer()
       ))
     }
   }
diff --git a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatFeatureTests.swift b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
similarity index 79%
rename from Examples/xx-messenger/Tests/ChatFeatureTests/ChatFeatureTests.swift
rename to Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
index 01d0ed8faa3c37b0a2005ace0b7c98d13b2e6590..c8f5952864c6f77f04ec42b53b5875a317ee37a4 100644
--- a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
@@ -8,15 +8,14 @@ import XXMessengerClient
 import XXModels
 @testable import ChatFeature
 
-final class ChatFeatureTests: XCTestCase {
+final class ChatComponentTests: XCTestCase {
   func testStart() {
     let contactId = "contact-id".data(using: .utf8)!
     let myContactId = "my-contact-id".data(using: .utf8)!
 
     let store = TestStore(
-      initialState: ChatState(id: .contact(contactId)),
-      reducer: chatReducer,
-      environment: .unimplemented
+      initialState: ChatComponent.State(id: .contact(contactId)),
+      reducer: ChatComponent()
     )
 
     var didFetchMessagesWithQuery: [XXModels.Message.Query] = []
@@ -24,9 +23,9 @@ final class ChatFeatureTests: XCTestCase {
     var didFetchFileTransfersWithQuery: [XXModels.FileTransfer.Query] = []
     let fileTransfersPublisher = PassthroughSubject<[XXModels.FileTransfer], Error>()
 
-    store.environment.mainQueue = .immediate
-    store.environment.bgQueue = .immediate
-    store.environment.messenger.e2e.get = {
+    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())
@@ -35,7 +34,7 @@ final class ChatFeatureTests: XCTestCase {
       }
       return e2e
     }
-    store.environment.db.run = {
+    store.dependencies.app.dbManager.getDB.run = {
       var db: Database = .unimplemented
       db.fetchMessagesPublisher.run = { query in
         didFetchMessagesWithQuery.append(query)
@@ -113,7 +112,7 @@ final class ChatFeatureTests: XCTestCase {
       sentFileTransfer,
     ])
 
-    let expectedMessages = IdentifiedArrayOf<ChatState.Message>(uniqueElements: [
+    let expectedMessages = IdentifiedArrayOf<ChatComponent.State.Message>(uniqueElements: [
       .init(
         id: 1,
         date: Date(timeIntervalSince1970: 1),
@@ -142,17 +141,16 @@ final class ChatFeatureTests: XCTestCase {
 
   func testStartFailure() {
     let store = TestStore(
-      initialState: ChatState(id: .contact("contact-id".data(using: .utf8)!)),
-      reducer: chatReducer,
-      environment: .unimplemented
+      initialState: ChatComponent.State(id: .contact("contact-id".data(using: .utf8)!)),
+      reducer: ChatComponent()
     )
 
     struct Failure: Error {}
     let error = Failure()
 
-    store.environment.mainQueue = .immediate
-    store.environment.bgQueue = .immediate
-    store.environment.messenger.e2e.get = {
+    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())
@@ -176,14 +174,13 @@ final class ChatFeatureTests: XCTestCase {
     var sendMessageCompletion: SendMessage.Completion?
 
     let store = TestStore(
-      initialState: ChatState(id: .contact("contact-id".data(using: .utf8)!)),
-      reducer: chatReducer,
-      environment: .unimplemented
+      initialState: ChatComponent.State(id: .contact("contact-id".data(using: .utf8)!)),
+      reducer: ChatComponent()
     )
 
-    store.environment.mainQueue = .immediate
-    store.environment.bgQueue = .immediate
-    store.environment.sendMessage.run = { text, recipientId, _, completion in
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.sendMessage.run = { text, recipientId, _, completion in
       didSendMessageWithParams.append(.init(text: text, recipientId: recipientId))
       sendMessageCompletion = completion
     }
@@ -208,17 +205,16 @@ final class ChatFeatureTests: XCTestCase {
     var sendMessageCompletion: SendMessage.Completion?
 
     let store = TestStore(
-      initialState: ChatState(
+      initialState: ChatComponent.State(
         id: .contact("contact-id".data(using: .utf8)!),
         text: "Hello"
       ),
-      reducer: chatReducer,
-      environment: .unimplemented
+      reducer: ChatComponent()
     )
 
-    store.environment.mainQueue = .immediate
-    store.environment.bgQueue = .immediate
-    store.environment.sendMessage.run = { _, _, onError, completion in
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.sendMessage.run = { _, _, onError, completion in
       sendMessageOnError = onError
       sendMessageCompletion = completion
     }
@@ -250,14 +246,13 @@ final class ChatFeatureTests: XCTestCase {
     var sendImageCompletion: SendImage.Completion?
 
     let store = TestStore(
-      initialState: ChatState(id: .contact("contact-id".data(using: .utf8)!)),
-      reducer: chatReducer,
-      environment: .unimplemented
+      initialState: ChatComponent.State(id: .contact("contact-id".data(using: .utf8)!)),
+      reducer: ChatComponent()
     )
 
-    store.environment.mainQueue = .immediate
-    store.environment.bgQueue = .immediate
-    store.environment.sendImage.run = { image, recipientId, _, completion in
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.sendImage.run = { image, recipientId, _, completion in
       didSendImageWithParams.append(.init(image: image, recipientId: recipientId))
       sendImageCompletion = completion
     }
@@ -277,16 +272,15 @@ final class ChatFeatureTests: XCTestCase {
     var sendImageCompletion: SendImage.Completion?
 
     let store = TestStore(
-      initialState: ChatState(
+      initialState: ChatComponent.State(
         id: .contact("contact-id".data(using: .utf8)!)
       ),
-      reducer: chatReducer,
-      environment: .unimplemented
+      reducer: ChatComponent()
     )
 
-    store.environment.mainQueue = .immediate
-    store.environment.bgQueue = .immediate
-    store.environment.sendImage.run = { _, _, onError, completion in
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.sendImage.run = { _, _, onError, completion in
       sendImageOnError = onError
       sendImageCompletion = completion
     }