diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9e87f241d5ee8ea1c5511bdca11093bb0e0ce5c4..10f45cd3ff6b3f9359973783412c08b883c300c3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,3 +1,8 @@
+before_script:
+  - for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts
+  - for ip in $(dig @8.8.8.8 git.xx.network +short); do ssh-keyscan git.xx.network,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts
+  - xcodebuild -version
+
 stages:
   - test
 
diff --git a/Examples/xx-messenger/.swiftpm/xcode/xcshareddata/xcschemes/LaunchFeature.xcscheme b/Examples/xx-messenger/.swiftpm/xcode/xcshareddata/xcschemes/LaunchFeature.xcscheme
deleted file mode 100644
index 0b5b716cb194f784d36c6cfe45d705107c4e6549..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/.swiftpm/xcode/xcshareddata/xcschemes/LaunchFeature.xcscheme
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1340"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "LaunchFeature"
-               BuildableName = "LaunchFeature"
-               BlueprintName = "LaunchFeature"
-               ReferencedContainer = "container:">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      codeCoverageEnabled = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "LaunchFeatureTests"
-               BuildableName = "LaunchFeatureTests"
-               BlueprintName = "LaunchFeatureTests"
-               ReferencedContainer = "container:">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "LaunchFeature"
-            BuildableName = "LaunchFeature"
-            BlueprintName = "LaunchFeature"
-            ReferencedContainer = "container:">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/Examples/xx-messenger/Package.swift b/Examples/xx-messenger/Package.swift
index 5eb7bede849b86baf218f969361cf911bd4a5907..f7e0d0399b2b67ef32c8bece58cfb102e76864a2 100644
--- a/Examples/xx-messenger/Package.swift
+++ b/Examples/xx-messenger/Package.swift
@@ -21,7 +21,6 @@ let package = Package(
     .library(name: "AppCore", targets: ["AppCore"]),
     .library(name: "AppFeature", targets: ["AppFeature"]),
     .library(name: "HomeFeature", targets: ["HomeFeature"]),
-    .library(name: "LaunchFeature", targets: ["LaunchFeature"]),
     .library(name: "RegisterFeature", targets: ["RegisterFeature"]),
     .library(name: "RestoreFeature", targets: ["RestoreFeature"]),
     .library(name: "WelcomeFeature", targets: ["WelcomeFeature"]),
@@ -69,7 +68,6 @@ let package = Package(
       dependencies: [
         .target(name: "AppCore"),
         .target(name: "HomeFeature"),
-        .target(name: "LaunchFeature"),
         .target(name: "RegisterFeature"),
         .target(name: "RestoreFeature"),
         .target(name: "WelcomeFeature"),
@@ -89,27 +87,9 @@ let package = Package(
     ),
     .target(
       name: "HomeFeature",
-      dependencies: [
-        .target(name: "AppCore"),
-        .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
-        .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .testTarget(
-      name: "HomeFeatureTests",
-      dependencies: [
-        .target(name: "HomeFeature"),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .target(
-      name: "LaunchFeature",
       dependencies: [
         .target(name: "AppCore"),
         .target(name: "RegisterFeature"),
-        .target(name: "RestoreFeature"),
-        .target(name: "WelcomeFeature"),
         .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
         .product(name: "ComposablePresentation", package: "swift-composable-presentation"),
         .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"),
@@ -117,9 +97,9 @@ let package = Package(
       swiftSettings: swiftSettings
     ),
     .testTarget(
-      name: "LaunchFeatureTests",
+      name: "HomeFeatureTests",
       dependencies: [
-        .target(name: "LaunchFeature"),
+        .target(name: "HomeFeature"),
       ],
       swiftSettings: swiftSettings
     ),
diff --git a/Examples/xx-messenger/Project/XXMessenger.xcodeproj/xcshareddata/xcschemes/XXMessenger.xcscheme b/Examples/xx-messenger/Project/XXMessenger.xcodeproj/xcshareddata/xcschemes/XXMessenger.xcscheme
index 9e83a72f3d20c49c9a5fec35e35ca64500fe5ebe..669debfc2ca857cae6de176b19f3caeb579e56e6 100644
--- a/Examples/xx-messenger/Project/XXMessenger.xcodeproj/xcshareddata/xcschemes/XXMessenger.xcscheme
+++ b/Examples/xx-messenger/Project/XXMessenger.xcodeproj/xcshareddata/xcschemes/XXMessenger.xcscheme
@@ -59,16 +59,6 @@
                ReferencedContainer = "container:..">
             </BuildableReference>
          </TestableReference>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "LaunchFeatureTests"
-               BuildableName = "LaunchFeatureTests"
-               BlueprintName = "LaunchFeatureTests"
-               ReferencedContainer = "container:..">
-            </BuildableReference>
-         </TestableReference>
          <TestableReference
             skipped = "NO">
             <BuildableReference
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
index ff97f80333da243e0dd39008f16d58587a094463..d3cc134a7dbca79b4d9e75472eb26697f08a455b 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
@@ -1,7 +1,6 @@
 import AppCore
 import Foundation
 import HomeFeature
-import LaunchFeature
 import RegisterFeature
 import RestoreFeature
 import WelcomeFeature
@@ -17,22 +16,25 @@ extension AppEnvironment {
     let bgQueue = DispatchQueue.global(qos: .background).eraseToAnyScheduler()
 
     return AppEnvironment(
-      launch: {
-        LaunchEnvironment(
-          dbManager: dbManager,
+      dbManager: dbManager,
+      messenger: messenger,
+      mainQueue: mainQueue,
+      bgQueue: bgQueue,
+      welcome: {
+        WelcomeEnvironment(
+          messenger: messenger,
+          mainQueue: mainQueue,
+          bgQueue: bgQueue
+        )
+      },
+      restore: {
+        RestoreEnvironment()
+      },
+      home: {
+        HomeEnvironment(
           messenger: messenger,
           mainQueue: mainQueue,
           bgQueue: bgQueue,
-          welcome: {
-            WelcomeEnvironment(
-              messenger: messenger,
-              mainQueue: mainQueue,
-              bgQueue: bgQueue
-            )
-          },
-          restore: {
-            RestoreEnvironment()
-          },
           register: {
             RegisterEnvironment(
               messenger: messenger,
@@ -41,13 +43,6 @@ extension AppEnvironment {
             )
           }
         )
-      },
-      home: {
-        HomeEnvironment(
-          messenger: messenger,
-          mainQueue: mainQueue,
-          bgQueue: bgQueue
-        )
       }
     )
   }
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift b/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
index 18927c0bc21af48ba57317be8b38c7c80ca27a0b..535d69fcbc3044d7698040497d5eba6020d5e426 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
@@ -1,21 +1,33 @@
+import AppCore
+import Combine
 import ComposableArchitecture
 import ComposablePresentation
+import Foundation
 import HomeFeature
-import LaunchFeature
+import RestoreFeature
+import WelcomeFeature
+import XXMessengerClient
 
 struct AppState: Equatable {
   enum Screen: Equatable {
-    case launch(LaunchState)
+    case loading
+    case welcome(WelcomeState)
+    case restore(RestoreState)
     case home(HomeState)
+    case failure(String)
   }
 
-  var screen: Screen = .launch(LaunchState())
+  @BindableState var screen: Screen = .loading
 }
 
 extension AppState.Screen {
-  var asLaunch: LaunchState? {
-    get { (/AppState.Screen.launch).extract(from: self) }
-    set { if let newValue = newValue { self = .launch(newValue) } }
+  var asWelcome: WelcomeState? {
+    get { (/AppState.Screen.welcome).extract(from: self) }
+    set { if let newValue = newValue { self = .welcome(newValue) } }
+  }
+  var asRestore: RestoreState? {
+    get { (/AppState.Screen.restore).extract(from: self) }
+    set { if let state = newValue { self = .restore(state) } }
   }
   var asHome: HomeState? {
     get { (/AppState.Screen.home).extract(from: self) }
@@ -23,19 +35,32 @@ extension AppState.Screen {
   }
 }
 
-enum AppAction: Equatable {
+enum AppAction: Equatable, BindableAction {
+  case start
+  case binding(BindingAction<AppState>)
+  case welcome(WelcomeAction)
+  case restore(RestoreAction)
   case home(HomeAction)
-  case launch(LaunchAction)
 }
 
 struct AppEnvironment {
-  var launch: () -> LaunchEnvironment
+  var dbManager: DBManager
+  var messenger: Messenger
+  var mainQueue: AnySchedulerOf<DispatchQueue>
+  var bgQueue: AnySchedulerOf<DispatchQueue>
+  var welcome: () -> WelcomeEnvironment
+  var restore: () -> RestoreEnvironment
   var home: () -> HomeEnvironment
 }
 
 extension AppEnvironment {
   static let unimplemented = AppEnvironment(
-    launch: { .unimplemented },
+    dbManager: .unimplemented,
+    messenger: .unimplemented,
+    mainQueue: .unimplemented,
+    bgQueue: .unimplemented,
+    welcome: { .unimplemented },
+    restore: { .unimplemented },
     home: { .unimplemented }
   )
 }
@@ -43,20 +68,60 @@ extension AppEnvironment {
 let appReducer = Reducer<AppState, AppAction, AppEnvironment>
 { state, action, env in
   switch action {
-  case .launch(.finished):
-    state.screen = .home(HomeState())
+  case .start, .welcome(.finished), .restore(.finished):
+    state.screen = .loading
+    return .run { subscriber in
+      do {
+        if env.dbManager.hasDB() == false {
+          try env.dbManager.makeDB()
+        }
+
+        if env.messenger.isLoaded() == false {
+          if env.messenger.isCreated() == false {
+            subscriber.send(.set(\.$screen, .welcome(WelcomeState())))
+            subscriber.send(completion: .finished)
+            return AnyCancellable {}
+          }
+          try env.messenger.load()
+        }
+
+        subscriber.send(.set(\.$screen, .home(HomeState())))
+      } catch {
+        subscriber.send(.set(\.$screen, .failure(error.localizedDescription)))
+      }
+      subscriber.send(completion: .finished)
+      return AnyCancellable {}
+    }
+    .subscribe(on: env.bgQueue)
+    .receive(on: env.mainQueue)
+    .eraseToEffect()
+
+  case .welcome(.restoreTapped):
+    state.screen = .restore(RestoreState())
     return .none
 
-  case .launch(_), .home(_):
+  case .welcome(.failed(let failure)):
+    state.screen = .failure(failure)
+    return .none
+
+  case .binding(_), .welcome(_), .restore(_), .home(_):
     return .none
   }
 }
+.binding()
+.presenting(
+  welcomeReducer,
+  state: .keyPath(\.screen.asWelcome),
+  id: .notNil(),
+  action: /AppAction.welcome,
+  environment: { $0.welcome() }
+)
 .presenting(
-  launchReducer,
-  state: .keyPath(\.screen.asLaunch),
+  restoreReducer,
+  state: .keyPath(\.screen.asRestore),
   id: .notNil(),
-  action: /AppAction.launch,
-  environment: { $0.launch() }
+  action: /AppAction.restore,
+  environment: { $0.restore() }
 )
 .presenting(
   homeReducer,
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppView.swift b/Examples/xx-messenger/Sources/AppFeature/AppView.swift
index 317560a3f749bd2b2eaa923318c7c4f4fc66fb1c..2af6d3521c4037f54c34400acd51103c9429451d 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppView.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppView.swift
@@ -1,19 +1,26 @@
 import ComposableArchitecture
-import SwiftUI
 import HomeFeature
-import LaunchFeature
+import RestoreFeature
+import SwiftUI
+import WelcomeFeature
 
 struct AppView: View {
   let store: Store<AppState, AppAction>
 
   enum ViewState: Equatable {
-    case launch
+    case loading
+    case welcome
+    case restore
     case home
+    case failure(String)
 
     init(_ state: AppState) {
       switch state.screen {
-      case .launch(_): self = .launch
+      case .loading: self = .loading
+      case .welcome(_): self = .welcome
+      case .restore(_): self = .restore
       case .home(_): self = .home
+      case .failure(let failure): self = .failure(failure)
       }
     }
   }
@@ -21,20 +28,53 @@ struct AppView: View {
   var body: some View {
     WithViewStore(store.scope(state: ViewState.init)) { viewStore in
       ZStack {
-        SwitchStore(store.scope(state: \.screen)) {
-          CaseLet(
-            state: /AppState.Screen.launch,
-            action: AppAction.launch,
+        switch viewStore.state {
+        case .loading:
+          ProgressView {
+            Text("Loading")
+          }
+          .controlSize(.large)
+          .frame(maxWidth: .infinity, maxHeight: .infinity)
+          .transition(.opacity)
+
+        case .welcome:
+          IfLetStore(
+            store.scope(
+              state: { (/AppState.Screen.welcome).extract(from: $0.screen) },
+              action: AppAction.welcome
+            ),
+            then: { store in
+              WelcomeView(store: store)
+                .frame(maxWidth: .infinity, maxHeight: .infinity)
+                .transition(.asymmetric(
+                  insertion: .move(edge: .trailing),
+                  removal: .opacity
+                ))
+            }
+          )
+
+        case .restore:
+          IfLetStore(
+            store.scope(
+              state: { (/AppState.Screen.restore).extract(from: $0.screen) },
+              action: AppAction.restore
+            ),
             then: { store in
-              LaunchView(store: store)
+              RestoreView(store: store)
                 .frame(maxWidth: .infinity, maxHeight: .infinity)
-                .transition(.opacity)
+                .transition(.asymmetric(
+                  insertion: .move(edge: .trailing),
+                  removal: .opacity
+                ))
             }
           )
 
-          CaseLet(
-            state: /AppState.Screen.home,
-            action: AppAction.home,
+        case .home:
+          IfLetStore(
+            store.scope(
+              state: { (/AppState.Screen.home).extract(from: $0.screen) },
+              action: AppAction.home
+            ),
             then: { store in
               HomeView(store: store)
                 .frame(maxWidth: .infinity, maxHeight: .infinity)
@@ -44,9 +84,40 @@ struct AppView: View {
                 ))
             }
           )
+
+        case .failure(let failure):
+          NavigationView {
+            VStack(spacing: 0) {
+              ScrollView {
+                Text(failure)
+                  .frame(maxWidth: .infinity, alignment: .leading)
+                  .padding()
+              }
+
+              Divider()
+
+              Button {
+                viewStore.send(.start)
+              } label: {
+                Text("Retry")
+                  .frame(maxWidth: .infinity)
+              }
+              .buttonStyle(.borderedProminent)
+              .controlSize(.large)
+              .padding()
+            }
+            .navigationTitle("Error")
+          }
+          .navigationViewStyle(.stack)
+          .frame(maxWidth: .infinity, maxHeight: .infinity)
+          .transition(.asymmetric(
+            insertion: .move(edge: .trailing),
+            removal: .opacity
+          ))
         }
       }
       .animation(.default, value: viewStore.state)
+      .task { viewStore.send(.start) }
     }
   }
 }
diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
index 6b61b0997c784eafc891d11cf46a15a22ba4549d..29abfb6ba9d977e0e87b0cb31bf7eca167b15886 100644
--- a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
+++ b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
@@ -1,36 +1,58 @@
+import Combine
 import ComposableArchitecture
+import ComposablePresentation
+import Foundation
+import RegisterFeature
 import XXClient
 import XXMessengerClient
 
 public struct HomeState: Equatable {
-  public init() {}
+  public init(
+    username: String? = nil,
+    failure: String? = nil,
+    register: RegisterState? = nil
+  ) {
+    self.username = username
+    self.failure = failure
+    self.register = register
+  }
+
+  @BindableState public var username: String?
+  @BindableState public var failure: String?
+  @BindableState public var register: RegisterState?
 }
 
-public enum HomeAction: Equatable {
+public enum HomeAction: Equatable, BindableAction {
   case start
+  case binding(BindingAction<HomeState>)
+  case register(RegisterAction)
 }
 
 public struct HomeEnvironment {
   public init(
     messenger: Messenger,
     mainQueue: AnySchedulerOf<DispatchQueue>,
-    bgQueue: AnySchedulerOf<DispatchQueue>
+    bgQueue: AnySchedulerOf<DispatchQueue>,
+    register: @escaping () -> RegisterEnvironment
   ) {
     self.messenger = messenger
     self.mainQueue = mainQueue
     self.bgQueue = bgQueue
+    self.register = register
   }
 
   public var messenger: Messenger
   public var mainQueue: AnySchedulerOf<DispatchQueue>
   public var bgQueue: AnySchedulerOf<DispatchQueue>
+  public var register: () -> RegisterEnvironment
 }
 
 extension HomeEnvironment {
   public static let unimplemented = HomeEnvironment(
     messenger: .unimplemented,
     mainQueue: .unimplemented,
-    bgQueue: .unimplemented
+    bgQueue: .unimplemented,
+    register: { .unimplemented }
   )
 }
 
@@ -38,6 +60,51 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
 { state, action, env in
   switch action {
   case .start:
+    return .run { subscriber in
+      do {
+        try env.messenger.start()
+
+        if env.messenger.isConnected() == false {
+          try env.messenger.connect()
+        }
+
+        if env.messenger.isLoggedIn() == false {
+          if try env.messenger.isRegistered() == false {
+            subscriber.send(.set(\.$register, RegisterState()))
+            subscriber.send(completion: .finished)
+            return AnyCancellable {}
+          }
+          try env.messenger.logIn()
+        }
+
+        if let contact = env.messenger.e2e()?.getContact(),
+           let facts = try? contact.getFacts(),
+           let username = facts.first(where: { $0.type == 0 })?.fact {
+          subscriber.send(.set(\.$username, username))
+        }
+      } catch {
+        subscriber.send(.set(\.$failure, error.localizedDescription))
+      }
+      subscriber.send(completion: .finished)
+      return AnyCancellable {}
+    }
+    .subscribe(on: env.bgQueue)
+    .receive(on: env.mainQueue)
+    .eraseToEffect()
+
+  case .register(.finished):
+    state.register = nil
+    return Effect(value: .start)
+
+  case .binding(_), .register(_):
     return .none
   }
 }
+.binding()
+.presenting(
+  registerReducer,
+  state: .keyPath(\.register),
+  id: .notNil(),
+  action: /HomeAction.register,
+  environment: { $0.register() }
+)
diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
index 0bda29bd8c2ea48b125337dd5a487e63334794f0..e40bb1db3982e1673ca2c77d6b8b0e72fa697da9 100644
--- a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
+++ b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
@@ -1,4 +1,6 @@
 import ComposableArchitecture
+import ComposablePresentation
+import RegisterFeature
 import SwiftUI
 
 public struct HomeView: View {
@@ -9,19 +11,54 @@ public struct HomeView: View {
   let store: Store<HomeState, HomeAction>
 
   struct ViewState: Equatable {
-    init(state: HomeState) {}
+    var username: String?
+    var failure: String?
+
+    init(state: HomeState) {
+      username = state.username
+      failure = state.failure
+    }
   }
 
   public var body: some View {
     WithViewStore(store.scope(state: ViewState.init)) { viewStore in
       NavigationView {
         Form {
+          if let username = viewStore.username {
+            Section {
+              Text(username)
+            } header: {
+              Text("Username")
+            }
+          }
 
+          if let failure = viewStore.failure {
+            Section {
+              Text(failure)
+              Button {
+                viewStore.send(.start)
+              } label: {
+                Text("Retry")
+              }
+            } header: {
+              Text("Error")
+            }
+          }
         }
         .navigationTitle("Home")
       }
       .navigationViewStyle(.stack)
       .task { viewStore.send(.start) }
+      .fullScreenCover(
+        store.scope(
+          state: \.register,
+          action: HomeAction.register
+        ),
+        onDismiss: {
+          viewStore.send(.set(\.$register, nil))
+        },
+        content: RegisterView.init(store:)
+      )
     }
   }
 }
diff --git a/Examples/xx-messenger/Sources/LaunchFeature/LaunchErrorView.swift b/Examples/xx-messenger/Sources/LaunchFeature/LaunchErrorView.swift
deleted file mode 100644
index 893492c0b9670af7389e341713527346eb6e4d26..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/Sources/LaunchFeature/LaunchErrorView.swift
+++ /dev/null
@@ -1,44 +0,0 @@
-import ComposableArchitecture
-import SwiftUI
-
-struct LaunchErrorView: View {
-  var failure: String
-  var onRetry: () -> Void
-
-  var body: some View {
-    NavigationView {
-      VStack(spacing: 0) {
-        ScrollView {
-          Text(failure)
-            .frame(maxWidth: .infinity, alignment: .leading)
-            .padding()
-        }
-
-        Divider()
-
-        Button {
-          onRetry()
-        } label: {
-          Text("Retry")
-            .frame(maxWidth: .infinity)
-        }
-        .buttonStyle(.borderedProminent)
-        .controlSize(.large)
-        .padding()
-      }
-      .navigationTitle("Error")
-    }
-    .navigationViewStyle(.stack)
-  }
-}
-
-#if DEBUG
-struct LaunchErrorView_Previews: PreviewProvider {
-  static var previews: some View {
-    LaunchErrorView(
-      failure: "Something went wrong...",
-      onRetry: {}
-    )
-  }
-}
-#endif
diff --git a/Examples/xx-messenger/Sources/LaunchFeature/LaunchFeature.swift b/Examples/xx-messenger/Sources/LaunchFeature/LaunchFeature.swift
deleted file mode 100644
index 39e3efdf0c70780ccd3f2343f17a0fc138fdab57..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/Sources/LaunchFeature/LaunchFeature.swift
+++ /dev/null
@@ -1,172 +0,0 @@
-import AppCore
-import Combine
-import ComposableArchitecture
-import ComposablePresentation
-import RegisterFeature
-import RestoreFeature
-import WelcomeFeature
-import XXMessengerClient
-import XXModels
-
-public struct LaunchState: Equatable {
-  public enum Screen: Equatable {
-    case loading
-    case welcome(WelcomeState)
-    case restore(RestoreState)
-    case register(RegisterState)
-    case failure(String)
-  }
-
-  public init(
-    screen: Screen = .loading
-  ) {
-    self.screen = screen
-  }
-
-  @BindableState public var screen: Screen
-}
-
-extension LaunchState.Screen {
-  var asWelcome: WelcomeState? {
-    get { (/LaunchState.Screen.welcome).extract(from: self) }
-    set { if let state = newValue { self = .welcome(state) } }
-  }
-  var asRestore: RestoreState? {
-    get { (/LaunchState.Screen.restore).extract(from: self) }
-    set { if let state = newValue { self = .restore(state) } }
-  }
-  var asRegister: RegisterState? {
-    get { (/LaunchState.Screen.register).extract(from: self) }
-    set { if let state = newValue { self = .register(state) } }
-  }
-}
-
-public enum LaunchAction: Equatable, BindableAction {
-  case start
-  case finished
-  case binding(BindingAction<LaunchState>)
-  case welcome(WelcomeAction)
-  case restore(RestoreAction)
-  case register(RegisterAction)
-}
-
-public struct LaunchEnvironment {
-  public init(
-    dbManager: DBManager,
-    messenger: Messenger,
-    mainQueue: AnySchedulerOf<DispatchQueue>,
-    bgQueue: AnySchedulerOf<DispatchQueue>,
-    welcome: @escaping () -> WelcomeEnvironment,
-    restore: @escaping () -> RestoreEnvironment,
-    register: @escaping () -> RegisterEnvironment
-  ) {
-    self.dbManager = dbManager
-    self.messenger = messenger
-    self.mainQueue = mainQueue
-    self.bgQueue = bgQueue
-    self.welcome = welcome
-    self.restore = restore
-    self.register = register
-  }
-
-  public var dbManager: DBManager
-  public var messenger: Messenger
-  public var mainQueue: AnySchedulerOf<DispatchQueue>
-  public var bgQueue: AnySchedulerOf<DispatchQueue>
-  public var welcome: () -> WelcomeEnvironment
-  public var restore: () -> RestoreEnvironment
-  public var register: () -> RegisterEnvironment
-}
-
-extension LaunchEnvironment {
-  public static let unimplemented = LaunchEnvironment(
-    dbManager: .unimplemented,
-    messenger: .unimplemented,
-    mainQueue: .unimplemented,
-    bgQueue: .unimplemented,
-    welcome: { .unimplemented },
-    restore: { .unimplemented },
-    register: { .unimplemented }
-  )
-}
-
-public let launchReducer = Reducer<LaunchState, LaunchAction, LaunchEnvironment>
-{ state, action, env in
-  switch action {
-  case .start, .welcome(.finished), .restore(.finished), .register(.finished):
-    state.screen = .loading
-    return .future { fulfill in
-      do {
-        if env.dbManager.hasDB() == false {
-          try env.dbManager.makeDB()
-        }
-
-        if env.messenger.isLoaded() == false {
-          if env.messenger.isCreated() == false {
-            fulfill(.success(.set(\.$screen, .welcome(WelcomeState()))))
-            return
-          }
-          try env.messenger.load()
-        }
-
-        try env.messenger.start()
-
-        if env.messenger.isConnected() == false {
-          try env.messenger.connect()
-        }
-
-        if env.messenger.isLoggedIn() == false {
-          if try env.messenger.isRegistered() == false {
-            fulfill(.success(.set(\.$screen, .register(RegisterState()))))
-            return
-          }
-          try env.messenger.logIn()
-        }
-
-        fulfill(.success(.finished))
-      }
-      catch {
-        fulfill(.success(.set(\.$screen, .failure(error.localizedDescription))))
-      }
-    }
-    .subscribe(on: env.bgQueue)
-    .receive(on: env.mainQueue)
-    .eraseToEffect()
-
-  case .finished:
-    return .none
-
-  case .welcome(.restoreTapped):
-    state.screen = .restore(RestoreState())
-    return .none
-
-  case .welcome(.failed(let failure)):
-    state.screen = .failure(failure)
-    return .none
-
-  case .binding(_), .welcome(_), .restore(_), .register(_):
-    return .none
-  }
-}
-.binding()
-.presenting(
-  welcomeReducer,
-  state: .keyPath(\.screen.asWelcome),
-  id: .notNil(),
-  action: /LaunchAction.welcome,
-  environment: { $0.welcome() }
-)
-.presenting(
-  restoreReducer,
-  state: .keyPath(\.screen.asRestore),
-  id: .notNil(),
-  action: /LaunchAction.restore,
-  environment: { $0.restore() }
-)
-.presenting(
-  registerReducer,
-  state: .keyPath(\.screen.asRegister),
-  id: .notNil(),
-  action: /LaunchAction.register,
-  environment: { $0.register() }
-)
diff --git a/Examples/xx-messenger/Sources/LaunchFeature/LaunchView.swift b/Examples/xx-messenger/Sources/LaunchFeature/LaunchView.swift
deleted file mode 100644
index ed110302f45ff390664f9af2e939571c9bbb2646..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/Sources/LaunchFeature/LaunchView.swift
+++ /dev/null
@@ -1,118 +0,0 @@
-import ComposableArchitecture
-import RegisterFeature
-import RestoreFeature
-import SwiftUI
-import WelcomeFeature
-
-public struct LaunchView: View {
-  public init(store: Store<LaunchState, LaunchAction>) {
-    self.store = store
-  }
-
-  struct ViewState: Equatable {
-    enum Screen: Equatable {
-      case loading
-      case welcome
-      case restore
-      case register
-      case failure(String)
-    }
-
-    init(_ state: LaunchState) {
-      switch state.screen {
-      case .loading: screen = .loading
-      case .welcome(_): screen = .welcome
-      case .restore(_): screen = .restore
-      case .register(_): screen = .register
-      case .failure(let failure): screen = .failure(failure)
-      }
-    }
-
-    var screen: Screen
-  }
-
-  let store: Store<LaunchState, LaunchAction>
-
-  public var body: some View {
-    WithViewStore(store.scope(state: ViewState.init)) { viewStore in
-      ZStack {
-        switch viewStore.screen {
-        case .loading:
-          ProgressView {
-            Text("Loading")
-          }
-          .controlSize(.large)
-          .frame(maxWidth: .infinity, maxHeight: .infinity)
-          .transition(.opacity)
-
-        case .welcome:
-          IfLetStore(
-            store.scope(
-              state: { (/LaunchState.Screen.welcome).extract(from: $0.screen) },
-              action: LaunchAction.welcome
-            ),
-            then: WelcomeView.init(store:)
-          )
-          .frame(maxWidth: .infinity, maxHeight: .infinity)
-          .transition(.asymmetric(
-            insertion: .move(edge: .trailing),
-            removal: .opacity
-          ))
-
-        case .restore:
-          IfLetStore(
-            store.scope(
-              state: { (/LaunchState.Screen.restore).extract(from: $0.screen) },
-              action: LaunchAction.restore
-            ),
-            then: RestoreView.init(store:)
-          )
-          .frame(maxWidth: .infinity, maxHeight: .infinity)
-          .transition(.asymmetric(
-            insertion: .move(edge: .trailing),
-            removal: .opacity
-          ))
-
-        case .register:
-          IfLetStore(
-            store.scope(
-              state: { (/LaunchState.Screen.register).extract(from: $0.screen) },
-              action: LaunchAction.register
-            ),
-            then: RegisterView.init(store:)
-          )
-          .frame(maxWidth: .infinity, maxHeight: .infinity)
-          .transition(.asymmetric(
-            insertion: .move(edge: .trailing),
-            removal: .opacity
-          ))
-
-        case .failure(let failure):
-          LaunchErrorView(
-            failure: failure,
-            onRetry: { viewStore.send(.start) }
-          )
-          .frame(maxWidth: .infinity, maxHeight: .infinity)
-          .transition(.asymmetric(
-            insertion: .move(edge: .trailing),
-            removal: .opacity
-          ))
-        }
-      }
-      .animation(.default, value: viewStore.screen)
-      .task { viewStore.send(.start) }
-    }
-  }
-}
-
-#if DEBUG
-public struct LaunchView_Previews: PreviewProvider {
-  public static var previews: some View {
-    LaunchView(store: Store(
-      initialState: LaunchState(),
-      reducer: .empty,
-      environment: ()
-    ))
-  }
-}
-#endif
diff --git a/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift b/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
index 6563da86bb1d74e25b4cb0c551c7314c20542792..5f0554922106e525c5f6c151c958b602dd8f5552 100644
--- a/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
@@ -1,19 +1,219 @@
 import ComposableArchitecture
 import HomeFeature
+import RestoreFeature
+import WelcomeFeature
 import XCTest
 @testable import AppFeature
 
-@MainActor
 final class AppFeatureTests: XCTestCase {
-  func testLaunchFinished() async throws {
+  func testStartWithoutMessengerCreated() {
     let store = TestStore(
       initialState: AppState(),
       reducer: appReducer,
       environment: .unimplemented
     )
 
-    await store.send(.launch(.finished)) {
+    let mainQueue = DispatchQueue.test
+    let bgQueue = DispatchQueue.test
+    var didMakeDB = 0
+
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.dbManager.hasDB.run = { false }
+    store.environment.dbManager.makeDB.run = { didMakeDB += 1 }
+    store.environment.messenger.isLoaded.run = { false }
+    store.environment.messenger.isCreated.run = { false }
+
+    store.send(.start)
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(didMakeDB, 1)
+
+    mainQueue.advance()
+
+    store.receive(.set(\.$screen, .welcome(WelcomeState()))) {
+      $0.screen = .welcome(WelcomeState())
+    }
+  }
+
+  func testStartWithMessengerCreated() {
+    let store = TestStore(
+      initialState: AppState(),
+      reducer: appReducer,
+      environment: .unimplemented
+    )
+
+    let mainQueue = DispatchQueue.test
+    let bgQueue = DispatchQueue.test
+    var didMakeDB = 0
+    var messengerDidLoad = 0
+
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.dbManager.hasDB.run = { false }
+    store.environment.dbManager.makeDB.run = { didMakeDB += 1 }
+    store.environment.messenger.isLoaded.run = { false }
+    store.environment.messenger.isCreated.run = { true }
+    store.environment.messenger.load.run = { messengerDidLoad += 1 }
+
+    store.send(.start)
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(didMakeDB, 1)
+    XCTAssertNoDifference(messengerDidLoad, 1)
+
+    mainQueue.advance()
+
+    store.receive(.set(\.$screen, .home(HomeState()))) {
+      $0.screen = .home(HomeState())
+    }
+  }
+
+  func testWelcomeFinished() {
+    let store = TestStore(
+      initialState: AppState(
+        screen: .welcome(WelcomeState())
+      ),
+      reducer: appReducer,
+      environment: .unimplemented
+    )
+
+    let mainQueue = DispatchQueue.test
+    let bgQueue = DispatchQueue.test
+    var messengerDidLoad = 0
+
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.dbManager.hasDB.run = { true }
+    store.environment.messenger.isLoaded.run = { false }
+    store.environment.messenger.isCreated.run = { true }
+    store.environment.messenger.load.run = { messengerDidLoad += 1 }
+
+    store.send(.welcome(.finished)) {
+      $0.screen = .loading
+    }
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(messengerDidLoad, 1)
+
+    mainQueue.advance()
+
+    store.receive(.set(\.$screen, .home(HomeState()))) {
+      $0.screen = .home(HomeState())
+    }
+  }
+
+  func testRestoreFinished() {
+    let store = TestStore(
+      initialState: AppState(
+        screen: .restore(RestoreState())
+      ),
+      reducer: appReducer,
+      environment: .unimplemented
+    )
+
+    let mainQueue = DispatchQueue.test
+    let bgQueue = DispatchQueue.test
+    var messengerDidLoad = 0
+
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.dbManager.hasDB.run = { true }
+    store.environment.messenger.isLoaded.run = { false }
+    store.environment.messenger.isCreated.run = { true }
+    store.environment.messenger.load.run = { messengerDidLoad += 1 }
+
+    store.send(.restore(.finished)) {
+      $0.screen = .loading
+    }
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(messengerDidLoad, 1)
+
+    mainQueue.advance()
+
+    store.receive(.set(\.$screen, .home(HomeState()))) {
       $0.screen = .home(HomeState())
     }
   }
+
+  func testWelcomeRestoreTapped() {
+    let store = TestStore(
+      initialState: AppState(
+        screen: .welcome(WelcomeState())
+      ),
+      reducer: appReducer,
+      environment: .unimplemented
+    )
+
+    store.send(.welcome(.restoreTapped)) {
+      $0.screen = .restore(RestoreState())
+    }
+  }
+
+  func testWelcomeFailed() {
+    let store = TestStore(
+      initialState: AppState(
+        screen: .welcome(WelcomeState())
+      ),
+      reducer: appReducer,
+      environment: .unimplemented
+    )
+
+    let failure = "Something went wrong"
+
+    store.send(.welcome(.failed(failure))) {
+      $0.screen = .failure(failure)
+    }
+  }
+
+  func testStartDatabaseMakeFailure() {
+    let store = TestStore(
+      initialState: AppState(),
+      reducer: appReducer,
+      environment: .unimplemented
+    )
+
+    struct Failure: Error {}
+    let error = Failure()
+
+    store.environment.mainQueue = .immediate
+    store.environment.bgQueue = .immediate
+    store.environment.dbManager.hasDB.run = { false }
+    store.environment.dbManager.makeDB.run = { throw error }
+
+    store.send(.start)
+
+    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
+      $0.screen = .failure(error.localizedDescription)
+    }
+  }
+
+  func testStartMessengerLoadFailure() {
+    let store = TestStore(
+      initialState: AppState(),
+      reducer: appReducer,
+      environment: .unimplemented
+    )
+
+    struct Failure: Error {}
+    let error = Failure()
+
+    store.environment.mainQueue = .immediate
+    store.environment.bgQueue = .immediate
+    store.environment.dbManager.hasDB.run = { true }
+    store.environment.messenger.isLoaded.run = { false }
+    store.environment.messenger.isCreated.run = { true }
+    store.environment.messenger.load.run = { throw error }
+
+    store.send(.start)
+
+    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
+      $0.screen = .failure(error.localizedDescription)
+    }
+  }
 }
diff --git a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
index 21a25bb641274dced7d7dd83ebc49f073ada4420..efdd867ff247317e7dd6dc379f38edfbc5ba7b3b 100644
--- a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
@@ -1,16 +1,232 @@
 import ComposableArchitecture
+import RegisterFeature
 import XCTest
+import XXClient
+import XXMessengerClient
 @testable import HomeFeature
 
-@MainActor
 final class HomeFeatureTests: XCTestCase {
-  func testStart() async throws {
+  func testStartUnregistered() {
     let store = TestStore(
       initialState: HomeState(),
       reducer: homeReducer,
       environment: .unimplemented
     )
 
-    await store.send(.start)
+    let bgQueue = DispatchQueue.test
+    let mainQueue = DispatchQueue.test
+    var messengerDidStartWithTimeout: [Int] = []
+    var messengerDidConnect = 0
+
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
+    store.environment.messenger.isConnected.run = { false }
+    store.environment.messenger.connect.run = { messengerDidConnect += 1 }
+    store.environment.messenger.isLoggedIn.run = { false }
+    store.environment.messenger.isRegistered.run = { false }
+
+    store.send(.start)
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
+    XCTAssertNoDifference(messengerDidConnect, 1)
+
+    mainQueue.advance()
+
+    store.receive(.set(\.$register, RegisterState())) {
+      $0.register = RegisterState()
+    }
+  }
+
+  func testStartRegistered() {
+    let store = TestStore(
+      initialState: HomeState(),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    let username = "test_username"
+    let bgQueue = DispatchQueue.test
+    let mainQueue = DispatchQueue.test
+    var messengerDidStartWithTimeout: [Int] = []
+    var messengerDidConnect = 0
+    var messengerDidLogIn = 0
+
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
+    store.environment.messenger.isConnected.run = { false }
+    store.environment.messenger.connect.run = { messengerDidConnect += 1 }
+    store.environment.messenger.isLoggedIn.run = { false }
+    store.environment.messenger.isRegistered.run = { true }
+    store.environment.messenger.logIn.run = { messengerDidLogIn += 1 }
+    store.environment.messenger.e2e.get = {
+      var e2e = E2E.unimplemented
+      e2e.getContact.run = {
+        var contact = Contact.unimplemented(Data())
+        contact.getFactsFromContact.run = { _ in [Fact(fact: username, type: 0)] }
+        return contact
+      }
+      return e2e
+    }
+
+    store.send(.start)
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
+    XCTAssertNoDifference(messengerDidConnect, 1)
+    XCTAssertNoDifference(messengerDidLogIn, 1)
+
+    mainQueue.advance()
+
+    store.receive(.set(\.$username, username)) {
+      $0.username = username
+    }
+  }
+
+  func testRegisterFinished() {
+    let store = TestStore(
+      initialState: HomeState(
+        register: RegisterState()
+      ),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    let username = "test_username"
+    let bgQueue = DispatchQueue.test
+    let mainQueue = DispatchQueue.test
+    var messengerDidStartWithTimeout: [Int] = []
+    var messengerDidLogIn = 0
+
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
+    store.environment.messenger.isConnected.run = { true }
+    store.environment.messenger.isLoggedIn.run = { false }
+    store.environment.messenger.isRegistered.run = { true }
+    store.environment.messenger.logIn.run = { messengerDidLogIn += 1 }
+    store.environment.messenger.e2e.get = {
+      var e2e = E2E.unimplemented
+      e2e.getContact.run = {
+        var contact = Contact.unimplemented(Data())
+        contact.getFactsFromContact.run = { _ in [Fact(fact: username, type: 0)] }
+        return contact
+      }
+      return e2e
+    }
+
+    store.send(.register(.finished)) {
+      $0.register = nil
+    }
+
+    store.receive(.start)
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
+    XCTAssertNoDifference(messengerDidLogIn, 1)
+
+    mainQueue.advance()
+
+    store.receive(.set(\.$username, username)) {
+      $0.username = username
+    }
+  }
+
+  func testStartMessengerStartFailure() {
+    let store = TestStore(
+      initialState: HomeState(),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    struct Failure: Error {}
+    let error = Failure()
+
+    store.environment.bgQueue = .immediate
+    store.environment.mainQueue = .immediate
+    store.environment.messenger.start.run = { _ in throw error }
+
+    store.send(.start)
+
+    store.receive(.set(\.$failure, error.localizedDescription)) {
+      $0.failure = error.localizedDescription
+    }
+  }
+
+  func testStartMessengerConnectFailure() {
+    let store = TestStore(
+      initialState: HomeState(),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    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.send(.start)
+
+    store.receive(.set(\.$failure, error.localizedDescription)) {
+      $0.failure = error.localizedDescription
+    }
+  }
+
+  func testStartMessengerIsRegisteredFailure() {
+    let store = TestStore(
+      initialState: HomeState(),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    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.isLoggedIn.run = { false }
+    store.environment.messenger.isRegistered.run = { throw error }
+
+    store.send(.start)
+
+    store.receive(.set(\.$failure, error.localizedDescription)) {
+      $0.failure = error.localizedDescription
+    }
+  }
+
+  func testStartMessengerLogInFailure() {
+    let store = TestStore(
+      initialState: HomeState(),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    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.isLoggedIn.run = { false }
+    store.environment.messenger.isRegistered.run = { true }
+    store.environment.messenger.logIn.run = { throw error }
+
+    store.send(.start)
+
+    store.receive(.set(\.$failure, error.localizedDescription)) {
+      $0.failure = error.localizedDescription
+    }
   }
 }
diff --git a/Examples/xx-messenger/Tests/LaunchFeatureTests/LaunchFeatureTests.swift b/Examples/xx-messenger/Tests/LaunchFeatureTests/LaunchFeatureTests.swift
deleted file mode 100644
index b2b3f856f79260ef652664f9c9892382296ede95..0000000000000000000000000000000000000000
--- a/Examples/xx-messenger/Tests/LaunchFeatureTests/LaunchFeatureTests.swift
+++ /dev/null
@@ -1,327 +0,0 @@
-import AppCore
-import ComposableArchitecture
-import RegisterFeature
-import RestoreFeature
-import WelcomeFeature
-import XCTest
-import XXModels
-@testable import LaunchFeature
-
-@MainActor
-final class LaunchFeatureTests: XCTestCase {
-  func testStart() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-    var didMakeDB = 0
-    var messengerDidLoad = 0
-    var messengerDidStart = 0
-    var messengerDidConnect = 0
-    var messengerDidLogIn = 0
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { false }
-    store.environment.dbManager.makeDB.run = { didMakeDB += 1 }
-    store.environment.messenger.isLoaded.run = { false }
-    store.environment.messenger.isCreated.run = { true }
-    store.environment.messenger.load.run = { messengerDidLoad += 1 }
-    store.environment.messenger.start.run = { _ in messengerDidStart += 1 }
-    store.environment.messenger.isConnected.run = { false }
-    store.environment.messenger.connect.run = { messengerDidConnect += 1 }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { true }
-    store.environment.messenger.logIn.run = { messengerDidLogIn += 1 }
-
-    store.send(.start)
-
-    bgQueue.advance()
-
-    XCTAssertNoDifference(didMakeDB, 1)
-    XCTAssertNoDifference(messengerDidLoad, 1)
-    XCTAssertNoDifference(messengerDidStart, 1)
-    XCTAssertNoDifference(messengerDidConnect, 1)
-    XCTAssertNoDifference(messengerDidLogIn, 1)
-
-    mainQueue.advance()
-
-    store.receive(.finished)
-  }
-
-  func testStartWithoutMessengerCreated() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { true }
-    store.environment.messenger.isLoaded.run = { false }
-    store.environment.messenger.isCreated.run = { false }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .welcome(WelcomeState()))) {
-      $0.screen = .welcome(WelcomeState())
-    }
-  }
-
-  func testStartUnregistered() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { true }
-    store.environment.messenger.isLoaded.run = { true }
-    store.environment.messenger.start.run = { _ in }
-    store.environment.messenger.isConnected.run = { true }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { false }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .register(RegisterState()))) {
-      $0.screen = .register(RegisterState())
-    }
-  }
-
-  func testStartMakeDBFailure() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-    struct Error: Swift.Error {}
-    let error = Error()
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { false }
-    store.environment.dbManager.makeDB.run = { throw error }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
-      $0.screen = .failure(error.localizedDescription)
-    }
-  }
-
-  func testStartMessengerLoadFailure() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-    struct Error: Swift.Error {}
-    let error = Error()
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { true }
-    store.environment.messenger.isLoaded.run = { false }
-    store.environment.messenger.isCreated.run = { true }
-    store.environment.messenger.load.run = { throw error }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
-      $0.screen = .failure(error.localizedDescription)
-    }
-  }
-
-  func testStartMessengerStartFailure() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-    struct Error: Swift.Error {}
-    let error = Error()
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { true }
-    store.environment.messenger.isLoaded.run = { true }
-    store.environment.messenger.start.run = { _ in throw error }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
-      $0.screen = .failure(error.localizedDescription)
-    }
-  }
-
-  func testStartMessengerConnectFailure() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-    struct Error: Swift.Error {}
-    let error = Error()
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { true }
-    store.environment.messenger.isLoaded.run = { true }
-    store.environment.messenger.start.run = { _ in }
-    store.environment.messenger.isConnected.run = { false }
-    store.environment.messenger.connect.run = { throw error }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
-      $0.screen = .failure(error.localizedDescription)
-    }
-  }
-
-  func testStartMessengerIsRegisteredFailure() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-    struct Error: Swift.Error {}
-    let error = Error()
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { true }
-    store.environment.messenger.isLoaded.run = { true }
-    store.environment.messenger.start.run = { _ in }
-    store.environment.messenger.isConnected.run = { true }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { throw error }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
-      $0.screen = .failure(error.localizedDescription)
-    }
-  }
-
-  func testStartMessengerLogInFailure() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let mainQueue = DispatchQueue.test
-    let bgQueue = DispatchQueue.test
-    struct Error: Swift.Error {}
-    let error = Error()
-
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.dbManager.hasDB.run = { true }
-    store.environment.messenger.isLoaded.run = { true }
-    store.environment.messenger.start.run = { _ in }
-    store.environment.messenger.isConnected.run = { true }
-    store.environment.messenger.isLoggedIn.run = { false }
-    store.environment.messenger.isRegistered.run = { true }
-    store.environment.messenger.logIn.run = { throw error }
-
-    store.send(.start)
-
-    bgQueue.advance()
-    mainQueue.advance()
-
-    store.receive(.set(\.$screen, .failure(error.localizedDescription))) {
-      $0.screen = .failure(error.localizedDescription)
-    }
-  }
-
-  func testWelcomeRestoreTapped() {
-    let store = TestStore(
-      initialState: LaunchState(
-        screen: .welcome(WelcomeState())
-      ),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    store.send(.welcome(.restoreTapped)) {
-      $0.screen = .restore(RestoreState())
-    }
-  }
-
-  func testWelcomeFailed() {
-    let store = TestStore(
-      initialState: LaunchState(
-        screen: .welcome(WelcomeState())
-      ),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    let failure = "Something went wrong"
-
-    store.send(.welcome(.failed(failure))) {
-      $0.screen = .failure(failure)
-    }
-  }
-
-  func testFinished() {
-    let store = TestStore(
-      initialState: LaunchState(),
-      reducer: launchReducer,
-      environment: .unimplemented
-    )
-
-    store.send(.finished)
-  }
-}
diff --git a/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved
index c330aa9448492ecb8f33d3b05ee260fe3897d417..b9909a307686e48727475bb07420e0efc4cd13cd 100644
--- a/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Examples/xx-messenger/XXMessenger.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -14,8 +14,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/pointfreeco/combine-schedulers",
       "state" : {
-        "revision" : "8fee20f993e64bbbf22bc3e3f444758ac2d05692",
-        "version" : "0.7.2"
+        "revision" : "9e42b4b0453da417a44daa17174103e7d1c5be07",
+        "version" : "0.7.3"
       }
     },
     {
@@ -59,8 +59,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/pointfreeco/swift-composable-architecture.git",
       "state" : {
-        "revision" : "108e3a536fcebb16c4f247ef92c2d7326baf9fe3",
-        "version" : "0.39.0"
+        "revision" : "a518935116b2bada7234f47073159b433d432af1",
+        "version" : "0.39.1"
       }
     },
     {
@@ -68,8 +68,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/darrarski/swift-composable-presentation.git",
       "state" : {
-        "revision" : "1f4d17fae1f7ed41cbed17929083190fd9a78ee6",
-        "version" : "0.5.2"
+        "revision" : "bdb7df9476cf29e8379fc50aa03848dd6c8033d9",
+        "version" : "0.5.3"
       }
     },
     {
diff --git a/run-tests.sh b/run-tests.sh
index 1f9d60c4075a3a06dd1bce6e6f0fb82fc647530a..1a87f661803af51200586db33dac341407cc7e78 100755
--- a/run-tests.sh
+++ b/run-tests.sh
@@ -1,9 +1,6 @@
 #!/bin/sh
 set -e
 
-echo "\n\033[1;32mâ–¶ Xcode version\033[0m"
-xcodebuild -version
-
 if [ "$1" = "macos" ]; then
 
   echo "\n\033[1;32mâ–¶ Running package tests on macOS...\033[0m"