diff --git a/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift b/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift
index 3b9b9a3d00ee09ec4dd23ddc24fec105f94946fe..36b604362e0f07c67b0a1e626a519241f692271c 100644
--- a/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift
+++ b/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift
@@ -1,8 +1,8 @@
 import ComposableArchitecture
 
 extension AlertState {
-  public static func confirmAccountDeletion() -> AlertState<HomeAction> {
-    AlertState<HomeAction>(
+  public static func confirmAccountDeletion() -> AlertState<HomeComponent.Action> {
+    AlertState<HomeComponent.Action>(
       title: TextState("Delete Account"),
       message: TextState("This will permanently delete your account and can't be undone."),
       buttons: [
@@ -12,8 +12,8 @@ extension AlertState {
     )
   }
 
-  public static func accountDeletionFailed(_ error: Error) -> AlertState<HomeAction> {
-    AlertState<HomeAction>(
+  public static func accountDeletionFailed(_ error: Error) -> AlertState<HomeComponent.Action> {
+    AlertState<HomeComponent.Action>(
       title: TextState("Error"),
       message: TextState(error.localizedDescription),
       buttons: []
diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeComponent.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeComponent.swift
new file mode 100644
index 0000000000000000000000000000000000000000..18212bf0ca916cffff86f5a4ee6cb09f4d220359
--- /dev/null
+++ b/Examples/xx-messenger/Sources/HomeFeature/HomeComponent.swift
@@ -0,0 +1,292 @@
+import AppCore
+import BackupFeature
+import Combine
+import ComposableArchitecture
+import ComposablePresentation
+import ContactsFeature
+import Foundation
+import RegisterFeature
+import UserSearchFeature
+import XCTestDynamicOverlay
+import XXClient
+import XXMessengerClient
+import XXModels
+
+public struct HomeComponent: ReducerProtocol {
+  public struct State: Equatable {
+    public init(
+      failure: String? = nil,
+      isNetworkHealthy: Bool? = nil,
+      networkNodesReport: NodeRegistrationReport? = nil,
+      isDeletingAccount: Bool = false,
+      alert: AlertState<Action>? = nil,
+      register: RegisterComponent.State? = nil,
+      contacts: ContactsComponent.State? = nil,
+      userSearch: UserSearchComponent.State? = nil,
+      backup: BackupComponent.State? = nil
+    ) {
+      self.failure = failure
+      self.isNetworkHealthy = isNetworkHealthy
+      self.isDeletingAccount = isDeletingAccount
+      self.alert = alert
+      self.register = register
+      self.contacts = contacts
+      self.userSearch = userSearch
+      self.backup = backup
+    }
+
+    public var failure: String?
+    public var isNetworkHealthy: Bool?
+    public var networkNodesReport: NodeRegistrationReport?
+    public var isDeletingAccount: Bool
+    public var alert: AlertState<Action>?
+    public var register: RegisterComponent.State?
+    public var contacts: ContactsComponent.State?
+    public var userSearch: UserSearchComponent.State?
+    public var backup: BackupComponent.State?
+  }
+
+  public enum Action: Equatable {
+    public enum Messenger: Equatable {
+      case start
+      case didStartRegistered
+      case didStartUnregistered
+      case failure(NSError)
+    }
+
+    public enum NetworkMonitor: Equatable {
+      case start
+      case stop
+      case health(Bool)
+      case nodes(NodeRegistrationReport)
+    }
+
+    public enum DeleteAccount: Equatable {
+      case buttonTapped
+      case confirmed
+      case success
+      case failure(NSError)
+    }
+
+    case messenger(Messenger)
+    case networkMonitor(NetworkMonitor)
+    case deleteAccount(DeleteAccount)
+    case didDismissAlert
+    case didDismissRegister
+    case userSearchButtonTapped
+    case didDismissUserSearch
+    case contactsButtonTapped
+    case didDismissContacts
+    case backupButtonTapped
+    case didDismissBackup
+    case register(RegisterComponent.Action)
+    case contacts(ContactsComponent.Action)
+    case userSearch(UserSearchComponent.Action)
+    case backup(BackupComponent.Action)
+  }
+
+  public init() {}
+
+  @Dependency(\.app.messenger) var messenger: Messenger
+  @Dependency(\.app.dbManager) var dbManager: DBManager
+  @Dependency(\.app.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
+  @Dependency(\.app.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>
+
+  public var body: some ReducerProtocol<State, Action> {
+    Reduce { state, action in
+      enum NetworkHealthEffectId {}
+      enum NetworkNodesEffectId {}
+
+      let messenger = self.messenger
+
+      switch action {
+      case .messenger(.start):
+        return .merge(
+          Effect(value: .networkMonitor(.stop)),
+          Effect.result {
+            do {
+              try messenger.start()
+
+              if messenger.isConnected() == false {
+                try messenger.connect()
+              }
+
+              if messenger.isListeningForMessages() == false {
+                try messenger.listenForMessages()
+              }
+
+              if messenger.isFileTransferRunning() == false {
+                try messenger.startFileTransfer()
+              }
+
+              if messenger.isLoggedIn() == false {
+                if try messenger.isRegistered() == false {
+                  return .success(.messenger(.didStartUnregistered))
+                }
+                try messenger.logIn()
+              }
+
+              if !messenger.isBackupRunning() {
+                try? messenger.resumeBackup()
+              }
+
+              return .success(.messenger(.didStartRegistered))
+            } catch {
+              return .success(.messenger(.failure(error as NSError)))
+            }
+          }
+        )
+        .subscribe(on: bgQueue)
+        .receive(on: mainQueue)
+        .eraseToEffect()
+
+      case .messenger(.didStartUnregistered):
+        state.register = RegisterComponent.State()
+        return .none
+
+      case .messenger(.didStartRegistered):
+        return Effect(value: .networkMonitor(.start))
+
+      case .messenger(.failure(let error)):
+        state.failure = error.localizedDescription
+        return .none
+
+      case .networkMonitor(.start):
+        return .merge(
+          Effect.run { subscriber in
+            let callback = HealthCallback { isHealthy in
+              subscriber.send(.networkMonitor(.health(isHealthy)))
+            }
+            let cancellable = messenger.cMix()?.addHealthCallback(callback)
+            return AnyCancellable { cancellable?.cancel() }
+          }
+            .cancellable(id: NetworkHealthEffectId.self, cancelInFlight: true),
+          Effect.timer(
+            id: NetworkNodesEffectId.self,
+            every: .seconds(2),
+            on: bgQueue
+          )
+          .compactMap { _ in try? messenger.cMix()?.getNodeRegistrationStatus() }
+            .map { Action.networkMonitor(.nodes($0)) }
+            .eraseToEffect()
+        )
+        .subscribe(on: bgQueue)
+        .receive(on: mainQueue)
+        .eraseToEffect()
+
+      case .networkMonitor(.stop):
+        state.isNetworkHealthy = nil
+        state.networkNodesReport = nil
+        return .merge(
+          .cancel(id: NetworkHealthEffectId.self),
+          .cancel(id: NetworkNodesEffectId.self)
+        )
+
+      case .networkMonitor(.health(let isHealthy)):
+        state.isNetworkHealthy = isHealthy
+        return .none
+
+      case .networkMonitor(.nodes(let report)):
+        state.networkNodesReport = report
+        return .none
+
+      case .deleteAccount(.buttonTapped):
+        state.alert = .confirmAccountDeletion()
+        return .none
+
+      case .deleteAccount(.confirmed):
+        state.isDeletingAccount = true
+        return .result {
+          do {
+            let contactId = try messenger.e2e.tryGet().getContact().getId()
+            let contact = try dbManager.getDB().fetchContacts(.init(id: [contactId])).first
+            if let username = contact?.username {
+              let ud = try messenger.ud.tryGet()
+              try ud.permanentDeleteAccount(username: Fact(type: .username, value: username))
+            }
+            try messenger.destroy()
+            try dbManager.removeDB()
+            return .success(.deleteAccount(.success))
+          } catch {
+            return .success(.deleteAccount(.failure(error as NSError)))
+          }
+        }
+        .subscribe(on: bgQueue)
+        .receive(on: mainQueue)
+        .eraseToEffect()
+
+      case .deleteAccount(.success):
+        state.isDeletingAccount = false
+        return .none
+
+      case .deleteAccount(.failure(let error)):
+        state.isDeletingAccount = false
+        state.alert = .accountDeletionFailed(error)
+        return .none
+
+      case .didDismissAlert:
+        state.alert = nil
+        return .none
+
+      case .didDismissRegister:
+        state.register = nil
+        return .none
+
+      case .userSearchButtonTapped:
+        state.userSearch = UserSearchComponent.State()
+        return .none
+
+      case .didDismissUserSearch:
+        state.userSearch = nil
+        return .none
+
+      case .contactsButtonTapped:
+        state.contacts = ContactsComponent.State()
+        return .none
+
+      case .didDismissContacts:
+        state.contacts = nil
+        return .none
+
+      case .register(.finished):
+        state.register = nil
+        return Effect(value: .messenger(.start))
+
+      case .backupButtonTapped:
+        state.backup = BackupComponent.State()
+        return .none
+
+      case .didDismissBackup:
+        state.backup = nil
+        return .none
+
+      case .register(_), .contacts(_), .userSearch(_), .backup(_):
+        return .none
+      }
+    }
+    .presenting(
+      state: .keyPath(\.register),
+      id: .notNil(),
+      action: /Action.register,
+      presented: { RegisterComponent() }
+    )
+    .presenting(
+      state: .keyPath(\.contacts),
+      id: .notNil(),
+      action: /Action.contacts,
+      presented: { ContactsComponent() }
+    )
+    .presenting(
+      state: .keyPath(\.userSearch),
+      id: .notNil(),
+      action: /Action.userSearch,
+      presented: { UserSearchComponent() }
+    )
+    .presenting(
+      state: .keyPath(\.backup),
+      id: .notNil(),
+      action: /Action.backup,
+      presented: { BackupComponent() }
+    )
+  }
+}
diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
deleted file mode 100644
index 6433dd330faac74045cad472798cd8c06a79cb40..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
+++ /dev/null
@@ -1,330 +0,0 @@
-import AppCore
-import BackupFeature
-import Combine
-import ComposableArchitecture
-import ComposablePresentation
-import ContactsFeature
-import Foundation
-import RegisterFeature
-import UserSearchFeature
-import XCTestDynamicOverlay
-import XXClient
-import XXMessengerClient
-import XXModels
-
-public struct HomeState: Equatable {
-  public init(
-    failure: String? = nil,
-    isNetworkHealthy: Bool? = nil,
-    networkNodesReport: NodeRegistrationReport? = nil,
-    isDeletingAccount: Bool = false,
-    alert: AlertState<HomeAction>? = nil,
-    register: RegisterState? = nil,
-    contacts: ContactsState? = nil,
-    userSearch: UserSearchState? = nil,
-    backup: BackupState? = nil
-  ) {
-    self.failure = failure
-    self.isNetworkHealthy = isNetworkHealthy
-    self.isDeletingAccount = isDeletingAccount
-    self.alert = alert
-    self.register = register
-    self.contacts = contacts
-    self.userSearch = userSearch
-    self.backup = backup
-  }
-
-  public var failure: String?
-  public var isNetworkHealthy: Bool?
-  public var networkNodesReport: NodeRegistrationReport?
-  public var isDeletingAccount: Bool
-  public var alert: AlertState<HomeAction>?
-  public var register: RegisterState?
-  public var contacts: ContactsState?
-  public var userSearch: UserSearchState?
-  public var backup: BackupState?
-}
-
-public enum HomeAction: Equatable {
-  public enum Messenger: Equatable {
-    case start
-    case didStartRegistered
-    case didStartUnregistered
-    case failure(NSError)
-  }
-
-  public enum NetworkMonitor: Equatable {
-    case start
-    case stop
-    case health(Bool)
-    case nodes(NodeRegistrationReport)
-  }
-
-  public enum DeleteAccount: Equatable {
-    case buttonTapped
-    case confirmed
-    case success
-    case failure(NSError)
-  }
-
-  case messenger(Messenger)
-  case networkMonitor(NetworkMonitor)
-  case deleteAccount(DeleteAccount)
-  case didDismissAlert
-  case didDismissRegister
-  case userSearchButtonTapped
-  case didDismissUserSearch
-  case contactsButtonTapped
-  case didDismissContacts
-  case backupButtonTapped
-  case didDismissBackup
-  case register(RegisterAction)
-  case contacts(ContactsAction)
-  case userSearch(UserSearchAction)
-  case backup(BackupAction)
-}
-
-public struct HomeEnvironment {
-  public init(
-    messenger: Messenger,
-    dbManager: DBManager,
-    mainQueue: AnySchedulerOf<DispatchQueue>,
-    bgQueue: AnySchedulerOf<DispatchQueue>,
-    register: @escaping () -> RegisterEnvironment,
-    contacts: @escaping () -> ContactsEnvironment,
-    userSearch: @escaping () -> UserSearchEnvironment,
-    backup: @escaping () -> BackupEnvironment
-  ) {
-    self.messenger = messenger
-    self.dbManager = dbManager
-    self.mainQueue = mainQueue
-    self.bgQueue = bgQueue
-    self.register = register
-    self.contacts = contacts
-    self.userSearch = userSearch
-    self.backup = backup
-  }
-
-  public var messenger: Messenger
-  public var dbManager: DBManager
-  public var mainQueue: AnySchedulerOf<DispatchQueue>
-  public var bgQueue: AnySchedulerOf<DispatchQueue>
-  public var register: () -> RegisterEnvironment
-  public var contacts: () -> ContactsEnvironment
-  public var userSearch: () -> UserSearchEnvironment
-  public var backup: () -> BackupEnvironment
-}
-
-#if DEBUG
-extension HomeEnvironment {
-  public static let unimplemented = HomeEnvironment(
-    messenger: .unimplemented,
-    dbManager: .unimplemented,
-    mainQueue: .unimplemented,
-    bgQueue: .unimplemented,
-    register: { .unimplemented },
-    contacts: { .unimplemented },
-    userSearch: { .unimplemented },
-    backup: { .unimplemented }
-  )
-}
-#endif
-
-public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
-{ state, action, env in
-  enum NetworkHealthEffectId {}
-  enum NetworkNodesEffectId {}
-
-  switch action {
-  case .messenger(.start):
-    return .merge(
-      Effect(value: .networkMonitor(.stop)),
-      Effect.result {
-        do {
-          try env.messenger.start()
-
-          if env.messenger.isConnected() == false {
-            try env.messenger.connect()
-          }
-
-          if env.messenger.isListeningForMessages() == false {
-            try env.messenger.listenForMessages()
-          }
-
-          if env.messenger.isFileTransferRunning() == false {
-            try env.messenger.startFileTransfer()
-          }
-
-          if env.messenger.isLoggedIn() == false {
-            if try env.messenger.isRegistered() == false {
-              return .success(.messenger(.didStartUnregistered))
-            }
-            try env.messenger.logIn()
-          }
-
-          if !env.messenger.isBackupRunning() {
-            try? env.messenger.resumeBackup()
-          }
-
-          return .success(.messenger(.didStartRegistered))
-        } catch {
-          return .success(.messenger(.failure(error as NSError)))
-        }
-      }
-    )
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .messenger(.didStartUnregistered):
-    state.register = RegisterState()
-    return .none
-
-  case .messenger(.didStartRegistered):
-    return Effect(value: .networkMonitor(.start))
-
-  case .messenger(.failure(let error)):
-    state.failure = error.localizedDescription
-    return .none
-
-  case .networkMonitor(.start):
-    return .merge(
-      Effect.run { subscriber in
-        let callback = HealthCallback { isHealthy in
-          subscriber.send(.networkMonitor(.health(isHealthy)))
-        }
-        let cancellable = env.messenger.cMix()?.addHealthCallback(callback)
-        return AnyCancellable { cancellable?.cancel() }
-      }
-        .cancellable(id: NetworkHealthEffectId.self, cancelInFlight: true),
-      Effect.timer(
-        id: NetworkNodesEffectId.self,
-        every: .seconds(2),
-        on: env.bgQueue
-      )
-      .compactMap { _ in try? env.messenger.cMix()?.getNodeRegistrationStatus() }
-        .map { HomeAction.networkMonitor(.nodes($0)) }
-        .eraseToEffect()
-    )
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .networkMonitor(.stop):
-    state.isNetworkHealthy = nil
-    state.networkNodesReport = nil
-    return .merge(
-      .cancel(id: NetworkHealthEffectId.self),
-      .cancel(id: NetworkNodesEffectId.self)
-    )
-
-  case .networkMonitor(.health(let isHealthy)):
-    state.isNetworkHealthy = isHealthy
-    return .none
-
-  case .networkMonitor(.nodes(let report)):
-    state.networkNodesReport = report
-    return .none
-
-  case .deleteAccount(.buttonTapped):
-    state.alert = .confirmAccountDeletion()
-    return .none
-
-  case .deleteAccount(.confirmed):
-    state.isDeletingAccount = true
-    return .result {
-      do {
-        let contactId = try env.messenger.e2e.tryGet().getContact().getId()
-        let contact = try env.dbManager.getDB().fetchContacts(.init(id: [contactId])).first
-        if let username = contact?.username {
-          let ud = try env.messenger.ud.tryGet()
-          try ud.permanentDeleteAccount(username: Fact(type: .username, value: username))
-        }
-        try env.messenger.destroy()
-        try env.dbManager.removeDB()
-        return .success(.deleteAccount(.success))
-      } catch {
-        return .success(.deleteAccount(.failure(error as NSError)))
-      }
-    }
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .deleteAccount(.success):
-    state.isDeletingAccount = false
-    return .none
-
-  case .deleteAccount(.failure(let error)):
-    state.isDeletingAccount = false
-    state.alert = .accountDeletionFailed(error)
-    return .none
-
-  case .didDismissAlert:
-    state.alert = nil
-    return .none
-
-  case .didDismissRegister:
-    state.register = nil
-    return .none
-
-  case .userSearchButtonTapped:
-    state.userSearch = UserSearchState()
-    return .none
-
-  case .didDismissUserSearch:
-    state.userSearch = nil
-    return .none
-
-  case .contactsButtonTapped:
-    state.contacts = ContactsState()
-    return .none
-
-  case .didDismissContacts:
-    state.contacts = nil
-    return .none
-
-  case .register(.finished):
-    state.register = nil
-    return Effect(value: .messenger(.start))
-
-  case .backupButtonTapped:
-    state.backup = BackupState()
-    return .none
-
-  case .didDismissBackup:
-    state.backup = nil
-    return .none
-
-  case .register(_), .contacts(_), .userSearch(_), .backup(_):
-    return .none
-  }
-}
-.presenting(
-  registerReducer,
-  state: .keyPath(\.register),
-  id: .notNil(),
-  action: /HomeAction.register,
-  environment: { $0.register() }
-)
-.presenting(
-  contactsReducer,
-  state: .keyPath(\.contacts),
-  id: .notNil(),
-  action: /HomeAction.contacts,
-  environment: { $0.contacts() }
-)
-.presenting(
-  userSearchReducer,
-  state: .keyPath(\.userSearch),
-  id: .notNil(),
-  action: /HomeAction.userSearch,
-  environment: { $0.userSearch() }
-)
-.presenting(
-  backupReducer,
-  state: .keyPath(\.backup),
-  id: .notNil(),
-  action: /HomeAction.backup,
-  environment: { $0.backup() }
-)
diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
index 8a1775d6a84ffdfc6b5ac1b2b816a8ee686b039c..d505100474cdd330d28afc81e126bbb0daf853b0 100644
--- a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
+++ b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
@@ -9,11 +9,11 @@ import UserSearchFeature
 import XXClient
 
 public struct HomeView: View {
-  public init(store: Store<HomeState, HomeAction>) {
+  public init(store: StoreOf<HomeComponent>) {
     self.store = store
   }
 
-  let store: Store<HomeState, HomeAction>
+  let store: StoreOf<HomeComponent>
 
   struct ViewState: Equatable {
     var failure: String?
@@ -21,7 +21,7 @@ public struct HomeView: View {
     var networkNodesReport: NodeRegistrationReport?
     var isDeletingAccount: Bool
 
-    init(state: HomeState) {
+    init(state: HomeComponent.State) {
       failure = state.failure
       isNetworkHealthy = state.isNetworkHealthy
       isDeletingAccount = state.isDeletingAccount
@@ -148,12 +148,12 @@ public struct HomeView: View {
         .navigationTitle("Home")
         .alert(
           store.scope(state: \.alert),
-          dismiss: HomeAction.didDismissAlert
+          dismiss: HomeComponent.Action.didDismissAlert
         )
         .background(NavigationLinkWithStore(
           store.scope(
             state: \.contacts,
-            action: HomeAction.contacts
+            action: HomeComponent.Action.contacts
           ),
           onDeactivate: {
             viewStore.send(.didDismissContacts)
@@ -163,7 +163,7 @@ public struct HomeView: View {
         .background(NavigationLinkWithStore(
           store.scope(
             state: \.userSearch,
-            action: HomeAction.userSearch
+            action: HomeComponent.Action.userSearch
           ),
           onDeactivate: {
             viewStore.send(.didDismissUserSearch)
@@ -173,7 +173,7 @@ public struct HomeView: View {
         .background(NavigationLinkWithStore(
           store.scope(
             state: \.backup,
-            action: HomeAction.backup
+            action: HomeComponent.Action.backup
           ),
           onDeactivate: {
             viewStore.send(.didDismissBackup)
@@ -186,7 +186,7 @@ public struct HomeView: View {
       .fullScreenCover(
         store.scope(
           state: \.register,
-          action: HomeAction.register
+          action: HomeComponent.Action.register
         ),
         onDismiss: {
           viewStore.send(.didDismissRegister)
@@ -201,9 +201,8 @@ public struct HomeView: View {
 public struct HomeView_Previews: PreviewProvider {
   public static var previews: some View {
     HomeView(store: Store(
-      initialState: HomeState(),
-      reducer: .empty,
-      environment: ()
+      initialState: HomeComponent.State(),
+      reducer: EmptyReducer()
     ))
   }
 }
diff --git a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeComponentTests.swift
similarity index 59%
rename from Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
rename to Examples/xx-messenger/Tests/HomeFeatureTests/HomeComponentTests.swift
index 6c23ff8b718191771ce8dbf30ef4777cfd7303f9..3bd49a4283b9b4e535c40fb8c9279a5482aa3d16 100644
--- a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeComponentTests.swift
@@ -11,12 +11,11 @@ import XXMessengerClient
 import XXModels
 @testable import HomeFeature
 
-final class HomeFeatureTests: XCTestCase {
+final class HomeComponentTests: XCTestCase {
   func testMessengerStartUnregistered() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     var messengerDidStartWithTimeout: [Int] = []
@@ -24,17 +23,17 @@ final class HomeFeatureTests: XCTestCase {
     var messengerDidListenForMessages = 0
     var messengerDidStartFileTransfer = 0
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
-    store.environment.messenger.isConnected.run = { false }
-    store.environment.messenger.connect.run = { messengerDidConnect += 1 }
-    store.environment.messenger.isListeningForMessages.run = { false }
-    store.environment.messenger.listenForMessages.run = { messengerDidListenForMessages += 1 }
-    store.environment.messenger.isFileTransferRunning.run = { false }
-    store.environment.messenger.startFileTransfer.run = { messengerDidStartFileTransfer += 1 }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { false }
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
+    store.dependencies.app.messenger.isConnected.run = { false }
+    store.dependencies.app.messenger.connect.run = { messengerDidConnect += 1 }
+    store.dependencies.app.messenger.isListeningForMessages.run = { false }
+    store.dependencies.app.messenger.listenForMessages.run = { messengerDidListenForMessages += 1 }
+    store.dependencies.app.messenger.isFileTransferRunning.run = { false }
+    store.dependencies.app.messenger.startFileTransfer.run = { messengerDidStartFileTransfer += 1 }
+    store.dependencies.app.messenger.isLoggedIn.run = { false }
+    store.dependencies.app.messenger.isRegistered.run = { false }
 
     store.send(.messenger(.start))
 
@@ -45,15 +44,14 @@ final class HomeFeatureTests: XCTestCase {
 
     store.receive(.networkMonitor(.stop))
     store.receive(.messenger(.didStartUnregistered)) {
-      $0.register = RegisterState()
+      $0.register = RegisterComponent.State()
     }
   }
 
   func testMessengerStartRegistered() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     var messengerDidStartWithTimeout: [Int] = []
@@ -63,21 +61,21 @@ final class HomeFeatureTests: XCTestCase {
     var messengerDidLogIn = 0
     var messengerDidResumeBackup = 0
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
-    store.environment.messenger.isConnected.run = { false }
-    store.environment.messenger.connect.run = { messengerDidConnect += 1 }
-    store.environment.messenger.isListeningForMessages.run = { false }
-    store.environment.messenger.listenForMessages.run = { messengerDidListenForMessages += 1 }
-    store.environment.messenger.isFileTransferRunning.run = { false }
-    store.environment.messenger.startFileTransfer.run = { messengerDidStartFileTransfer += 1 }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { true }
-    store.environment.messenger.logIn.run = { messengerDidLogIn += 1 }
-    store.environment.messenger.isBackupRunning.run = { false }
-    store.environment.messenger.resumeBackup.run = { messengerDidResumeBackup += 1 }
-    store.environment.messenger.cMix.get = {
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
+    store.dependencies.app.messenger.isConnected.run = { false }
+    store.dependencies.app.messenger.connect.run = { messengerDidConnect += 1 }
+    store.dependencies.app.messenger.isListeningForMessages.run = { false }
+    store.dependencies.app.messenger.listenForMessages.run = { messengerDidListenForMessages += 1 }
+    store.dependencies.app.messenger.isFileTransferRunning.run = { false }
+    store.dependencies.app.messenger.startFileTransfer.run = { messengerDidStartFileTransfer += 1 }
+    store.dependencies.app.messenger.isLoggedIn.run = { false }
+    store.dependencies.app.messenger.isRegistered.run = { true }
+    store.dependencies.app.messenger.logIn.run = { messengerDidLogIn += 1 }
+    store.dependencies.app.messenger.isBackupRunning.run = { false }
+    store.dependencies.app.messenger.resumeBackup.run = { messengerDidResumeBackup += 1 }
+    store.dependencies.app.messenger.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.addHealthCallback.run = { _ in Cancellable {} }
       cMix.getNodeRegistrationStatus.run = {
@@ -105,27 +103,26 @@ final class HomeFeatureTests: XCTestCase {
 
   func testRegisterFinished() {
     let store = TestStore(
-      initialState: HomeState(
-        register: RegisterState()
+      initialState: HomeComponent.State(
+        register: RegisterComponent.State()
       ),
-      reducer: homeReducer,
-      environment: .unimplemented
+      reducer: HomeComponent()
     )
 
     var messengerDidStartWithTimeout: [Int] = []
     var messengerDidLogIn = 0
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
-    store.environment.messenger.isConnected.run = { true }
-    store.environment.messenger.isListeningForMessages.run = { true }
-    store.environment.messenger.isFileTransferRunning.run = { true }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { true }
-    store.environment.messenger.logIn.run = { messengerDidLogIn += 1 }
-    store.environment.messenger.isBackupRunning.run = { true }
-    store.environment.messenger.cMix.get = {
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
+    store.dependencies.app.messenger.isConnected.run = { true }
+    store.dependencies.app.messenger.isListeningForMessages.run = { true }
+    store.dependencies.app.messenger.isFileTransferRunning.run = { true }
+    store.dependencies.app.messenger.isLoggedIn.run = { false }
+    store.dependencies.app.messenger.isRegistered.run = { true }
+    store.dependencies.app.messenger.logIn.run = { messengerDidLogIn += 1 }
+    store.dependencies.app.messenger.isBackupRunning.run = { true }
+    store.dependencies.app.messenger.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.addHealthCallback.run = { _ in Cancellable {} }
       cMix.getNodeRegistrationStatus.run = {
@@ -153,17 +150,16 @@ final class HomeFeatureTests: XCTestCase {
 
   func testMessengerStartFailure() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     struct Failure: Error {}
     let error = Failure()
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.start.run = { _ in throw error }
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.start.run = { _ in throw error }
 
     store.send(.messenger(.start))
 
@@ -175,19 +171,18 @@ final class HomeFeatureTests: XCTestCase {
 
   func testMessengerStartConnectFailure() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     struct Failure: Error {}
     let error = Failure()
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.start.run = { _ in }
-    store.environment.messenger.isConnected.run = { false }
-    store.environment.messenger.connect.run = { throw error }
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.start.run = { _ in }
+    store.dependencies.app.messenger.isConnected.run = { false }
+    store.dependencies.app.messenger.connect.run = { throw error }
 
     store.send(.messenger(.start))
 
@@ -199,22 +194,21 @@ final class HomeFeatureTests: XCTestCase {
 
   func testMessengerStartIsRegisteredFailure() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     struct Failure: Error {}
     let error = Failure()
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.start.run = { _ in }
-    store.environment.messenger.isConnected.run = { true }
-    store.environment.messenger.isListeningForMessages.run = { true }
-    store.environment.messenger.isFileTransferRunning.run = { true }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { throw error }
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.start.run = { _ in }
+    store.dependencies.app.messenger.isConnected.run = { true }
+    store.dependencies.app.messenger.isListeningForMessages.run = { true }
+    store.dependencies.app.messenger.isFileTransferRunning.run = { true }
+    store.dependencies.app.messenger.isLoggedIn.run = { false }
+    store.dependencies.app.messenger.isRegistered.run = { throw error }
 
     store.send(.messenger(.start))
 
@@ -226,23 +220,22 @@ final class HomeFeatureTests: XCTestCase {
 
   func testMessengerStartLogInFailure() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     struct Failure: Error {}
     let error = Failure()
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.start.run = { _ in }
-    store.environment.messenger.isConnected.run = { true }
-    store.environment.messenger.isListeningForMessages.run = { true }
-    store.environment.messenger.isFileTransferRunning.run = { true }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { true }
-    store.environment.messenger.logIn.run = { throw error }
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.start.run = { _ in }
+    store.dependencies.app.messenger.isConnected.run = { true }
+    store.dependencies.app.messenger.isListeningForMessages.run = { true }
+    store.dependencies.app.messenger.isFileTransferRunning.run = { true }
+    store.dependencies.app.messenger.isLoggedIn.run = { false }
+    store.dependencies.app.messenger.isRegistered.run = { true }
+    store.dependencies.app.messenger.logIn.run = { throw error }
 
     store.send(.messenger(.start))
 
@@ -254,9 +247,8 @@ final class HomeFeatureTests: XCTestCase {
 
   func testNetworkMonitorStart() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     let bgQueue = DispatchQueue.test
@@ -271,9 +263,9 @@ final class HomeFeatureTests: XCTestCase {
       .init(registered: 2, total: 12),
     ]
 
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.messenger.cMix.get = {
+    store.dependencies.app.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.dependencies.app.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.dependencies.app.messenger.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.addHealthCallback.run = { callback in
         cMixDidAddHealthCallback.append(callback)
@@ -339,9 +331,8 @@ final class HomeFeatureTests: XCTestCase {
 
   func testAccountDeletion() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     var dbDidFetchContacts: [XXModels.Contact.Query] = []
@@ -349,9 +340,9 @@ final class HomeFeatureTests: XCTestCase {
     var messengerDidDestroy = 0
     var didRemoveDB = 0
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.e2e.get = {
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getContact.run = {
         var contact = Contact.unimplemented("contact-data".data(using: .utf8)!)
@@ -360,7 +351,7 @@ final class HomeFeatureTests: XCTestCase {
       }
       return e2e
     }
-    store.environment.dbManager.getDB.run = {
+    store.dependencies.app.dbManager.getDB.run = {
       var db: Database = .unimplemented
       db.fetchContacts.run = { query in
         dbDidFetchContacts.append(query)
@@ -374,17 +365,17 @@ final class HomeFeatureTests: XCTestCase {
       }
       return db
     }
-    store.environment.dbManager.removeDB.run = {
+    store.dependencies.app.dbManager.removeDB.run = {
       didRemoveDB += 1
     }
-    store.environment.messenger.ud.get = {
+    store.dependencies.app.messenger.ud.get = {
       var ud: UserDiscovery = .unimplemented
       ud.permanentDeleteAccount.run = { usernameFact in
         udDidPermanentDeleteAccount.append(usernameFact)
       }
       return ud
     }
-    store.environment.messenger.destroy.run = {
+    store.dependencies.app.messenger.destroy.run = {
       messengerDidDestroy += 1
     }
 
@@ -412,17 +403,16 @@ final class HomeFeatureTests: XCTestCase {
 
   func testAccountDeletionFailure() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     struct Failure: Error {}
     let error = Failure()
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.e2e.get = {
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getContact.run = {
         var contact = Contact.unimplemented("contact-data".data(using: .utf8)!)
@@ -444,11 +434,10 @@ final class HomeFeatureTests: XCTestCase {
 
   func testDidDismissAlert() {
     let store = TestStore(
-      initialState: HomeState(
+      initialState: HomeComponent.State(
         alert: AlertState(title: TextState(""))
       ),
-      reducer: homeReducer,
-      environment: .unimplemented
+      reducer: HomeComponent()
     )
 
     store.send(.didDismissAlert) {
@@ -458,11 +447,10 @@ final class HomeFeatureTests: XCTestCase {
 
   func testDidDismissRegister() {
     let store = TestStore(
-      initialState: HomeState(
-        register: RegisterState()
+      initialState: HomeComponent.State(
+        register: RegisterComponent.State()
       ),
-      reducer: homeReducer,
-      environment: .unimplemented
+      reducer: HomeComponent()
     )
 
     store.send(.didDismissRegister) {
@@ -472,23 +460,21 @@ final class HomeFeatureTests: XCTestCase {
 
   func testUserSearchButtonTapped() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     store.send(.userSearchButtonTapped) {
-      $0.userSearch = UserSearchState()
+      $0.userSearch = UserSearchComponent.State()
     }
   }
 
   func testDidDismissUserSearch() {
     let store = TestStore(
-      initialState: HomeState(
-        userSearch: UserSearchState()
+      initialState: HomeComponent.State(
+        userSearch: UserSearchComponent.State()
       ),
-      reducer: homeReducer,
-      environment: .unimplemented
+      reducer: HomeComponent()
     )
 
     store.send(.didDismissUserSearch) {
@@ -498,23 +484,21 @@ final class HomeFeatureTests: XCTestCase {
 
   func testContactsButtonTapped() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     store.send(.contactsButtonTapped) {
-      $0.contacts = ContactsState()
+      $0.contacts = ContactsComponent.State()
     }
   }
 
   func testDidDismissContacts() {
     let store = TestStore(
-      initialState: HomeState(
-        contacts: ContactsState()
+      initialState: HomeComponent.State(
+        contacts: ContactsComponent.State()
       ),
-      reducer: homeReducer,
-      environment: .unimplemented
+      reducer: HomeComponent()
     )
 
     store.send(.didDismissContacts) {
@@ -524,23 +508,21 @@ final class HomeFeatureTests: XCTestCase {
 
   func testBackupButtonTapped() {
     let store = TestStore(
-      initialState: HomeState(),
-      reducer: homeReducer,
-      environment: .unimplemented
+      initialState: HomeComponent.State(),
+      reducer: HomeComponent()
     )
 
     store.send(.backupButtonTapped) {
-      $0.backup = BackupState()
+      $0.backup = BackupComponent.State()
     }
   }
 
   func testDidDismissBackup() {
     let store = TestStore(
-      initialState: HomeState(
-        backup: BackupState()
+      initialState: HomeComponent.State(
+        backup: BackupComponent.State()
       ),
-      reducer: homeReducer,
-      environment: .unimplemented
+      reducer: HomeComponent()
     )
 
     store.send(.didDismissBackup) {