diff --git a/Examples/xx-messenger/Sources/RestoreFeature/RestoreComponent.swift b/Examples/xx-messenger/Sources/RestoreFeature/RestoreComponent.swift
new file mode 100644
index 0000000000000000000000000000000000000000..5a7ef06de236b757cfc82ebbab07b1829ba45822
--- /dev/null
+++ b/Examples/xx-messenger/Sources/RestoreFeature/RestoreComponent.swift
@@ -0,0 +1,155 @@
+import AppCore
+import Combine
+import ComposableArchitecture
+import Foundation
+import XCTestDynamicOverlay
+import XXMessengerClient
+import XXModels
+
+public struct RestoreComponent: ReducerProtocol {
+  public struct State: Equatable {
+    public enum Field: String, Hashable {
+      case passphrase
+    }
+
+    public struct File: Equatable {
+      public init(name: String, data: Data) {
+        self.name = name
+        self.data = data
+      }
+
+      public var name: String
+      public var data: Data
+    }
+
+    public init(
+      file: File? = nil,
+      fileImportFailure: String? = nil,
+      restoreFailures: [String] = [],
+      focusedField: Field? = nil,
+      isImportingFile: Bool = false,
+      passphrase: String = "",
+      isRestoring: Bool = false
+    ) {
+      self.file = file
+      self.fileImportFailure = fileImportFailure
+      self.restoreFailures = restoreFailures
+      self.focusedField = focusedField
+      self.isImportingFile = isImportingFile
+      self.passphrase = passphrase
+      self.isRestoring = isRestoring
+    }
+
+    public var file: File?
+    public var fileImportFailure: String?
+    public var restoreFailures: [String]
+    @BindableState public var focusedField: Field?
+    @BindableState public var isImportingFile: Bool
+    @BindableState public var passphrase: String
+    @BindableState public var isRestoring: Bool
+  }
+
+  public enum Action: Equatable, BindableAction {
+    case importFileTapped
+    case fileImport(Result<URL, NSError>)
+    case restoreTapped
+    case finished
+    case failed([NSError])
+    case binding(BindingAction<State>)
+  }
+
+  public init() {}
+
+  @Dependency(\.app.messenger) var messenger: Messenger
+  @Dependency(\.app.dbManager.getDB) var db: DBManagerGetDB
+  @Dependency(\.app.loadData) var loadData: URLDataLoader
+  @Dependency(\.app.now) var now: () -> Date
+  @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
+      switch action {
+      case .importFileTapped:
+        state.isImportingFile = true
+        state.fileImportFailure = nil
+        return .none
+
+      case .fileImport(.success(let url)):
+        state.isImportingFile = false
+        do {
+          state.file = .init(
+            name: url.lastPathComponent,
+            data: try loadData(url)
+          )
+          state.fileImportFailure = nil
+        } catch {
+          state.file = nil
+          state.fileImportFailure = error.localizedDescription
+        }
+        return .none
+
+      case .fileImport(.failure(let error)):
+        state.isImportingFile = false
+        state.file = nil
+        state.fileImportFailure = error.localizedDescription
+        return .none
+
+      case .restoreTapped:
+        guard let backupData = state.file?.data, backupData.count > 0 else { return .none }
+        let backupPassphrase = state.passphrase
+        state.isRestoring = true
+        state.restoreFailures = []
+        return Effect.result {
+          do {
+            let result = try messenger.restoreBackup(
+              backupData: backupData,
+              backupPassphrase: backupPassphrase
+            )
+            let facts = try messenger.ud.tryGet().getFacts()
+            try db().saveContact(Contact(
+              id: try messenger.e2e.tryGet().getContact().getId(),
+              username: facts.get(.username)?.value,
+              email: facts.get(.email)?.value,
+              phone: facts.get(.phone)?.value,
+              createdAt: now()
+            ))
+            try result.restoredContacts.forEach { contactId in
+              if try db().fetchContacts(.init(id: [contactId])).isEmpty {
+                try db().saveContact(Contact(
+                  id: contactId,
+                  createdAt: now()
+                ))
+              }
+            }
+            return .success(.finished)
+          } catch {
+            var errors = [error as NSError]
+            do {
+              try messenger.destroy()
+            } catch {
+              errors.append(error as NSError)
+            }
+            return .success(.failed(errors))
+          }
+        }
+        .subscribe(on: bgQueue)
+        .receive(on: mainQueue)
+        .eraseToEffect()
+
+      case .finished:
+        state.isRestoring = false
+        return .none
+
+      case .failed(let errors):
+        state.isRestoring = false
+        state.restoreFailures = errors.map(\.localizedDescription)
+        return .none
+
+      case .binding(_):
+        return .none
+      }
+    }
+  }
+}
diff --git a/Examples/xx-messenger/Sources/RestoreFeature/RestoreFeature.swift b/Examples/xx-messenger/Sources/RestoreFeature/RestoreFeature.swift
deleted file mode 100644
index 6b3d61d340a7932b6367f71894a0efd707ae81d2..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/Sources/RestoreFeature/RestoreFeature.swift
+++ /dev/null
@@ -1,181 +0,0 @@
-import AppCore
-import Combine
-import ComposableArchitecture
-import Foundation
-import XCTestDynamicOverlay
-import XXMessengerClient
-import XXModels
-
-public struct RestoreState: Equatable {
-  public enum Field: String, Hashable {
-    case passphrase
-  }
-
-  public struct File: Equatable {
-    public init(name: String, data: Data) {
-      self.name = name
-      self.data = data
-    }
-
-    public var name: String
-    public var data: Data
-  }
-
-  public init(
-    file: File? = nil,
-    fileImportFailure: String? = nil,
-    restoreFailures: [String] = [],
-    focusedField: Field? = nil,
-    isImportingFile: Bool = false,
-    passphrase: String = "",
-    isRestoring: Bool = false
-  ) {
-    self.file = file
-    self.fileImportFailure = fileImportFailure
-    self.restoreFailures = restoreFailures
-    self.focusedField = focusedField
-    self.isImportingFile = isImportingFile
-    self.passphrase = passphrase
-    self.isRestoring = isRestoring
-  }
-
-  public var file: File?
-  public var fileImportFailure: String?
-  public var restoreFailures: [String]
-  @BindableState public var focusedField: Field?
-  @BindableState public var isImportingFile: Bool
-  @BindableState public var passphrase: String
-  @BindableState public var isRestoring: Bool
-}
-
-public enum RestoreAction: Equatable, BindableAction {
-  case importFileTapped
-  case fileImport(Result<URL, NSError>)
-  case restoreTapped
-  case finished
-  case failed([NSError])
-  case binding(BindingAction<RestoreState>)
-}
-
-public struct RestoreEnvironment {
-  public init(
-    messenger: Messenger,
-    db: DBManagerGetDB,
-    loadData: URLDataLoader,
-    now: @escaping () -> Date,
-    mainQueue: AnySchedulerOf<DispatchQueue>,
-    bgQueue: AnySchedulerOf<DispatchQueue>
-  ) {
-    self.messenger = messenger
-    self.db = db
-    self.loadData = loadData
-    self.now = now
-    self.mainQueue = mainQueue
-    self.bgQueue = bgQueue
-  }
-
-  public var messenger: Messenger
-  public var db: DBManagerGetDB
-  public var loadData: URLDataLoader
-  public var now: () -> Date
-  public var mainQueue: AnySchedulerOf<DispatchQueue>
-  public var bgQueue: AnySchedulerOf<DispatchQueue>
-}
-
-#if DEBUG
-extension RestoreEnvironment {
-  public static let unimplemented = RestoreEnvironment(
-    messenger: .unimplemented,
-    db: .unimplemented,
-    loadData: .unimplemented,
-    now: XCTUnimplemented("\(Self.self).now"),
-    mainQueue: .unimplemented,
-    bgQueue: .unimplemented
-  )
-}
-#endif
-
-public let restoreReducer = Reducer<RestoreState, RestoreAction, RestoreEnvironment>
-{ state, action, env in
-  switch action {
-  case .importFileTapped:
-    state.isImportingFile = true
-    state.fileImportFailure = nil
-    return .none
-
-  case .fileImport(.success(let url)):
-    state.isImportingFile = false
-    do {
-      state.file = .init(
-        name: url.lastPathComponent,
-        data: try env.loadData(url)
-      )
-      state.fileImportFailure = nil
-    } catch {
-      state.file = nil
-      state.fileImportFailure = error.localizedDescription
-    }
-    return .none
-
-  case .fileImport(.failure(let error)):
-    state.isImportingFile = false
-    state.file = nil
-    state.fileImportFailure = error.localizedDescription
-    return .none
-
-  case .restoreTapped:
-    guard let backupData = state.file?.data, backupData.count > 0 else { return .none }
-    let backupPassphrase = state.passphrase
-    state.isRestoring = true
-    state.restoreFailures = []
-    return Effect.result {
-      do {
-        let result = try env.messenger.restoreBackup(
-          backupData: backupData,
-          backupPassphrase: backupPassphrase
-        )
-        let facts = try env.messenger.ud.tryGet().getFacts()
-        try env.db().saveContact(Contact(
-          id: try env.messenger.e2e.tryGet().getContact().getId(),
-          username: facts.get(.username)?.value,
-          email: facts.get(.email)?.value,
-          phone: facts.get(.phone)?.value,
-          createdAt: env.now()
-        ))
-        try result.restoredContacts.forEach { contactId in
-          if try env.db().fetchContacts(.init(id: [contactId])).isEmpty {
-            try env.db().saveContact(Contact(
-              id: contactId,
-              createdAt: env.now()
-            ))
-          }
-        }
-        return .success(.finished)
-      } catch {
-        var errors = [error as NSError]
-        do {
-          try env.messenger.destroy()
-        } catch {
-          errors.append(error as NSError)
-        }
-        return .success(.failed(errors))
-      }
-    }
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .finished:
-    state.isRestoring = false
-    return .none
-
-  case .failed(let errors):
-    state.isRestoring = false
-    state.restoreFailures = errors.map(\.localizedDescription)
-    return .none
-
-  case .binding(_):
-    return .none
-  }
-}
-.binding()
diff --git a/Examples/xx-messenger/Sources/RestoreFeature/RestoreView.swift b/Examples/xx-messenger/Sources/RestoreFeature/RestoreView.swift
index 281f3f061e4a3ff5ccc1913bb45e45a03cff6576..503b868d44a587b19fb89728b2e9c7e713606301 100644
--- a/Examples/xx-messenger/Sources/RestoreFeature/RestoreView.swift
+++ b/Examples/xx-messenger/Sources/RestoreFeature/RestoreView.swift
@@ -2,12 +2,12 @@ import ComposableArchitecture
 import SwiftUI
 
 public struct RestoreView: View {
-  public init(store: Store<RestoreState, RestoreAction>) {
+  public init(store: StoreOf<RestoreComponent>) {
     self.store = store
   }
 
-  let store: Store<RestoreState, RestoreAction>
-  @FocusState var focusedField: RestoreState.Field?
+  let store: StoreOf<RestoreComponent>
+  @FocusState var focusedField: RestoreComponent.State.Field?
 
   struct ViewState: Equatable {
     struct File: Equatable {
@@ -19,11 +19,11 @@ public struct RestoreView: View {
     var isImportingFile: Bool
     var passphrase: String
     var isRestoring: Bool
-    var focusedField: RestoreState.Field?
+    var focusedField: RestoreComponent.State.Field?
     var fileImportFailure: String?
     var restoreFailures: [String]
 
-    init(state: RestoreState) {
+    init(state: RestoreComponent.State) {
       file = state.file.map { .init(name: $0.name, size: $0.data.count) }
       isImportingFile = state.isImportingFile
       passphrase = state.passphrase
@@ -61,7 +61,7 @@ public struct RestoreView: View {
     }
   }
 
-  @ViewBuilder func fileSection(_ viewStore: ViewStore<ViewState, RestoreAction>) -> some View {
+  @ViewBuilder func fileSection(_ viewStore: ViewStore<ViewState, RestoreComponent.Action>) -> some View {
     Section {
       if let file = viewStore.file {
         HStack(alignment: .bottom) {
@@ -100,7 +100,7 @@ public struct RestoreView: View {
     }
   }
 
-  @ViewBuilder func restoreSection(_ viewStore: ViewStore<ViewState, RestoreAction>) -> some View {
+  @ViewBuilder func restoreSection(_ viewStore: ViewStore<ViewState, RestoreComponent.Action>) -> some View {
     Section {
       SecureField("Passphrase", text: viewStore.binding(
         get: \.passphrase,
@@ -152,7 +152,7 @@ public struct RestoreView: View {
 public struct RestoreView_Previews: PreviewProvider {
   public static var previews: some View {
     RestoreView(store: Store(
-      initialState: RestoreState(
+      initialState: RestoreComponent.State(
         file: .init(name: "preview", data: Data()),
         fileImportFailure: nil,
         restoreFailures: [
@@ -165,8 +165,7 @@ public struct RestoreView_Previews: PreviewProvider {
         passphrase: "",
         isRestoring: true
       ),
-      reducer: .empty,
-      environment: ()
+      reducer: EmptyReducer()
     ))
   }
 }
diff --git a/Examples/xx-messenger/Tests/RestoreFeatureTests/RestoreFeatureTests.swift b/Examples/xx-messenger/Tests/RestoreFeatureTests/RestoreComponentTests.swift
similarity index 79%
rename from Examples/xx-messenger/Tests/RestoreFeatureTests/RestoreFeatureTests.swift
rename to Examples/xx-messenger/Tests/RestoreFeatureTests/RestoreComponentTests.swift
index 716d7650255b277cad37fb40ad5a73c4aee5bace..8a15fb747fb0124bd972593a8a81233d38c4c89c 100644
--- a/Examples/xx-messenger/Tests/RestoreFeatureTests/RestoreFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/RestoreFeatureTests/RestoreComponentTests.swift
@@ -6,19 +6,18 @@ import XXMessengerClient
 import XXModels
 @testable import RestoreFeature
 
-final class RestoreFeatureTests: XCTestCase {
+final class RestoreComponentTests: XCTestCase {
   func testFileImport() {
     let fileURL = URL(string: "file-url")!
     var didLoadDataFromURL: [URL] = []
     let dataFromURL = "data-from-url".data(using: .utf8)!
 
     let store = TestStore(
-      initialState: RestoreState(),
-      reducer: restoreReducer,
-      environment: .unimplemented
+      initialState: RestoreComponent.State(),
+      reducer: RestoreComponent()
     )
 
-    store.environment.loadData.load = { url in
+    store.dependencies.app.loadData.load = { url in
       didLoadDataFromURL.append(url)
       return dataFromURL
     }
@@ -41,11 +40,10 @@ final class RestoreFeatureTests: XCTestCase {
     let failure = Failure()
 
     let store = TestStore(
-      initialState: RestoreState(
+      initialState: RestoreComponent.State(
         isImportingFile: true
       ),
-      reducer: restoreReducer,
-      environment: .unimplemented
+      reducer: RestoreComponent()
     )
 
     store.send(.fileImport(.failure(failure as NSError))) {
@@ -60,14 +58,13 @@ final class RestoreFeatureTests: XCTestCase {
     let failure = Failure()
 
     let store = TestStore(
-      initialState: RestoreState(
+      initialState: RestoreComponent.State(
         isImportingFile: true
       ),
-      reducer: restoreReducer,
-      environment: .unimplemented
+      reducer: RestoreComponent()
     )
 
-    store.environment.loadData.load = { _ in throw failure }
+    store.dependencies.app.loadData.load = { _ in throw failure }
 
     store.send(.fileImport(.success(URL(string: "test")!))) {
       $0.isImportingFile = false
@@ -102,23 +99,22 @@ final class RestoreFeatureTests: XCTestCase {
     var didSaveContact: [XXModels.Contact] = []
 
     let store = TestStore(
-      initialState: RestoreState(
+      initialState: RestoreComponent.State(
         file: .init(name: "file-name", data: backupData)
       ),
-      reducer: restoreReducer,
-      environment: .unimplemented
+      reducer: RestoreComponent()
     )
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.now = { now }
-    store.environment.messenger.restoreBackup.run = { data, passphrase in
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.now = { now }
+    store.dependencies.app.messenger.restoreBackup.run = { data, passphrase in
       didRestoreWithData.append(data)
       didRestoreWithPassphrase.append(passphrase)
       udFacts = restoredFacts
       return restoreResult
     }
-    store.environment.messenger.e2e.get = {
+    store.dependencies.app.messenger.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getContact.run = {
         var contact: XXClient.Contact = .unimplemented(Data())
@@ -127,12 +123,12 @@ final class RestoreFeatureTests: XCTestCase {
       }
       return e2e
     }
-    store.environment.messenger.ud.get = {
+    store.dependencies.app.messenger.ud.get = {
       var ud: UserDiscovery = .unimplemented
       ud.getFacts.run = { udFacts }
       return ud
     }
-    store.environment.db.run = {
+    store.dependencies.app.dbManager.getDB.run = {
       var db: Database = .unimplemented
       db.fetchContacts.run = { query in
         didFetchContacts.append(query)
@@ -189,11 +185,10 @@ final class RestoreFeatureTests: XCTestCase {
 
   func testRestoreWithoutFile() {
     let store = TestStore(
-      initialState: RestoreState(
+      initialState: RestoreComponent.State(
         file: nil
       ),
-      reducer: restoreReducer,
-      environment: .unimplemented
+      reducer: RestoreComponent()
     )
 
     store.send(.restoreTapped)
@@ -206,17 +201,16 @@ final class RestoreFeatureTests: XCTestCase {
     }
 
     let store = TestStore(
-      initialState: RestoreState(
+      initialState: RestoreComponent.State(
         file: .init(name: "name", data: "data".data(using: .utf8)!)
       ),
-      reducer: restoreReducer,
-      environment: .unimplemented
+      reducer: RestoreComponent()
     )
 
-    store.environment.bgQueue = .immediate
-    store.environment.mainQueue = .immediate
-    store.environment.messenger.restoreBackup.run = { _, _ in throw Failure.restore }
-    store.environment.messenger.destroy.run = { throw Failure.destroy }
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.messenger.restoreBackup.run = { _, _ in throw Failure.restore }
+    store.dependencies.app.messenger.destroy.run = { throw Failure.destroy }
 
     store.send(.restoreTapped) {
       $0.isRestoring = true