From 33138382bdb4477853aa357d83f7b7013ed852d8 Mon Sep 17 00:00:00 2001
From: appflowy <annie@appflowy.io>
Date: Tue, 31 Aug 2021 23:01:46 +0800
Subject: [PATCH] rename struct

---
 .../flowy_sdk/lib/dispatch/code_gen.dart      |   4 +-
 .../lib/protobuf/flowy-user/auth.pb.dart      |  47 ---
 .../lib/protobuf/flowy-user/auth.pbjson.dart  |  10 -
 .../protobuf/flowy-user/errors.pbenum.dart    |   2 +
 .../protobuf/flowy-user/errors.pbjson.dart    |   3 +-
 .../lib/protobuf/flowy-user/event.pbenum.dart |   4 +-
 .../lib/protobuf/flowy-user/event.pbjson.dart |   4 +-
 .../protobuf/flowy-user/user_detail.pb.dart   |  26 +-
 .../flowy-user/user_detail.pbjson.dart        |  10 +-
 backend/src/application.rs                    |   7 +-
 backend/src/user_service/auth.rs              |  11 +-
 backend/src/user_service/mod.rs               |   2 -
 backend/src/user_service/profile.rs           |   0
 backend/src/user_service/router.rs            |   6 +-
 backend/tests/api/auth.rs                     |  16 +-
 backend/tests/api/helper.rs                   |   4 +-
 .../src/derive_cache/derive_cache.rs          |   3 +-
 .../flowy-document/tests/editor/helper.rs     |  10 +-
 rust-lib/flowy-infra/Cargo.toml               |   4 +-
 .../{flowy-net => flowy-infra}/src/future.rs  |   0
 rust-lib/flowy-infra/src/lib.rs               |   1 +
 rust-lib/flowy-net/Cargo.toml                 |   1 +
 rust-lib/flowy-net/src/config.rs              |   2 +
 rust-lib/flowy-net/src/lib.rs                 |   1 -
 rust-lib/flowy-sdk/src/deps_resolve/mod.rs    |   2 -
 .../src/deps_resolve/user_deps_impl.rs        |   4 -
 rust-lib/flowy-sdk/src/module.rs              |   7 +-
 rust-lib/flowy-sqlite/src/database.rs         |  10 +-
 rust-lib/flowy-test/src/builder.rs            |  24 +-
 rust-lib/flowy-test/src/helper.rs             |   2 +-
 rust-lib/flowy-test/src/tester.rs             |   8 +-
 rust-lib/flowy-user/Cargo.toml                |   5 +-
 rust-lib/flowy-user/src/entities/auth.rs      |   6 -
 .../flowy-user/src/entities/user_detail.rs    |   2 +-
 rust-lib/flowy-user/src/errors.rs             |  12 +
 rust-lib/flowy-user/src/event.rs              |  12 +-
 .../flowy-user/src/handlers/user_handler.rs   |  21 +-
 rust-lib/flowy-user/src/lib.rs                |   5 +-
 rust-lib/flowy-user/src/module.rs             |   4 +-
 .../flowy-user/src/protobuf/model/auth.rs     | 281 ++++--------------
 .../flowy-user/src/protobuf/model/errors.rs   | 147 ++++-----
 .../flowy-user/src/protobuf/model/event.rs    |  38 +--
 .../src/protobuf/model/user_detail.rs         | 179 ++++++-----
 .../flowy-user/src/protobuf/proto/auth.proto  |   3 -
 .../src/protobuf/proto/errors.proto           |   1 +
 .../flowy-user/src/protobuf/proto/event.proto |   2 +-
 .../src/protobuf/proto/user_detail.proto      |   2 +-
 rust-lib/flowy-user/src/services/mod.rs       |   2 +-
 .../flowy-user/src/services/server/mod.rs     |  13 +
 .../user_server => server}/server_api.rs      |  31 +-
 .../user_server => server}/server_api_mock.rs |  10 +-
 .../flowy-user/src/services/user/builder.rs   |  12 +-
 .../flowy-user/src/services/user/database.rs  |  13 +-
 rust-lib/flowy-user/src/services/user/mod.rs  |   4 +-
 .../src/services/user/user_server/mod.rs      |  20 --
 .../src/services/user/user_session.rs         |  69 +++--
 .../src/services/workspace/action.rs          |   1 -
 .../flowy-user/src/services/workspace/mod.rs  |   3 -
 rust-lib/flowy-user/tests/event/helper.rs     |   4 +-
 rust-lib/flowy-user/tests/event/main.rs       |   2 +-
 .../flowy-user/tests/event/sign_in_test.rs    |  10 +-
 .../flowy-user/tests/event/sign_up_test.rs    |  10 +-
 ...ser_status_test.rs => user_detail_test.rs} |  16 +-
 .../tests/event/user_update_test.rs           |  78 ++---
 .../flowy-workspace/tests/event/helper.rs     |  20 +-
 .../tests/event/workspace_test.rs             |   6 +-
 66 files changed, 529 insertions(+), 750 deletions(-)
 delete mode 100644 backend/src/user_service/profile.rs
 rename rust-lib/{flowy-net => flowy-infra}/src/future.rs (100%)
 delete mode 100644 rust-lib/flowy-sdk/src/deps_resolve/user_deps_impl.rs
 create mode 100644 rust-lib/flowy-user/src/services/server/mod.rs
 rename rust-lib/flowy-user/src/services/{user/user_server => server}/server_api.rs (66%)
 rename rust-lib/flowy-user/src/services/{user/user_server => server}/server_api_mock.rs (82%)
 delete mode 100644 rust-lib/flowy-user/src/services/user/user_server/mod.rs
 delete mode 100644 rust-lib/flowy-user/src/services/workspace/action.rs
 delete mode 100644 rust-lib/flowy-user/src/services/workspace/mod.rs
 rename rust-lib/flowy-user/tests/event/{user_status_test.rs => user_detail_test.rs} (60%)

diff --git a/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart b/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
index 3530e3146a..dc548bffb7 100644
--- a/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
+++ b/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
@@ -354,14 +354,14 @@ class UserEventUpdateUser {
      UpdateUserRequest request;
      UserEventUpdateUser(this.request);
 
-    Future<Either<UserDetail, UserError>> send() {
+    Future<Either<Unit, UserError>> send() {
     final request = FFIRequest.create()
           ..event = UserEvent.UpdateUser.toString()
           ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(UserDetail.fromBuffer(okBytes)),
+           (bytes) => left(unit),
            (errBytes) => right(UserError.fromBuffer(errBytes)),
         ));
     }
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pb.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pb.dart
index 50f0cd3ddf..10f1f7e092 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pb.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pb.dart
@@ -459,50 +459,3 @@ class SignUpResponse extends $pb.GeneratedMessage {
   void clearToken() => clearField(4);
 }
 
-class SignOutParams extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SignOutParams', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'token')
-    ..hasRequiredFields = false
-  ;
-
-  SignOutParams._() : super();
-  factory SignOutParams({
-    $core.String? token,
-  }) {
-    final _result = create();
-    if (token != null) {
-      _result.token = token;
-    }
-    return _result;
-  }
-  factory SignOutParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory SignOutParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
-  'Will be removed in next major version')
-  SignOutParams clone() => SignOutParams()..mergeFromMessage(this);
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-  'Will be removed in next major version')
-  SignOutParams copyWith(void Function(SignOutParams) updates) => super.copyWith((message) => updates(message as SignOutParams)) as SignOutParams; // ignore: deprecated_member_use
-  $pb.BuilderInfo get info_ => _i;
-  @$core.pragma('dart2js:noInline')
-  static SignOutParams create() => SignOutParams._();
-  SignOutParams createEmptyInstance() => create();
-  static $pb.PbList<SignOutParams> createRepeated() => $pb.PbList<SignOutParams>();
-  @$core.pragma('dart2js:noInline')
-  static SignOutParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SignOutParams>(create);
-  static SignOutParams? _defaultInstance;
-
-  @$pb.TagNumber(1)
-  $core.String get token => $_getSZ(0);
-  @$pb.TagNumber(1)
-  set token($core.String v) { $_setString(0, v); }
-  @$pb.TagNumber(1)
-  $core.bool hasToken() => $_has(0);
-  @$pb.TagNumber(1)
-  void clearToken() => clearField(1);
-}
-
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pbjson.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pbjson.dart
index b9abb7a5d3..0d52df9163 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pbjson.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pbjson.dart
@@ -80,13 +80,3 @@ const SignUpResponse$json = const {
 
 /// Descriptor for `SignUpResponse`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List signUpResponseDescriptor = $convert.base64Decode('Cg5TaWduVXBSZXNwb25zZRIQCgN1aWQYASABKAlSA3VpZBISCgRuYW1lGAIgASgJUgRuYW1lEhQKBWVtYWlsGAMgASgJUgVlbWFpbBIUCgV0b2tlbhgEIAEoCVIFdG9rZW4=');
-@$core.Deprecated('Use signOutParamsDescriptor instead')
-const SignOutParams$json = const {
-  '1': 'SignOutParams',
-  '2': const [
-    const {'1': 'token', '3': 1, '4': 1, '5': 9, '10': 'token'},
-  ],
-};
-
-/// Descriptor for `SignOutParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List signOutParamsDescriptor = $convert.base64Decode('Cg1TaWduT3V0UGFyYW1zEhQKBXRva2VuGAEgASgJUgV0b2tlbg==');
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart
index 54c751ee8f..2c50079bbb 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart
@@ -17,6 +17,7 @@ class ErrorCode extends $pb.ProtobufEnum {
   static const ErrorCode UserDatabaseDidNotMatch = ErrorCode._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseDidNotMatch');
   static const ErrorCode UserDatabaseInternalError = ErrorCode._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseInternalError');
   static const ErrorCode SqlInternalError = ErrorCode._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SqlInternalError');
+  static const ErrorCode DatabaseConnectError = ErrorCode._(7, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DatabaseConnectError');
   static const ErrorCode UserNotLoginYet = ErrorCode._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotLoginYet');
   static const ErrorCode ReadCurrentIdFailed = ErrorCode._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadCurrentIdFailed');
   static const ErrorCode WriteCurrentIdFailed = ErrorCode._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WriteCurrentIdFailed');
@@ -44,6 +45,7 @@ class ErrorCode extends $pb.ProtobufEnum {
     UserDatabaseDidNotMatch,
     UserDatabaseInternalError,
     SqlInternalError,
+    DatabaseConnectError,
     UserNotLoginYet,
     ReadCurrentIdFailed,
     WriteCurrentIdFailed,
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart
index 10c025aac6..671f2b1c36 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart
@@ -19,6 +19,7 @@ const ErrorCode$json = const {
     const {'1': 'UserDatabaseDidNotMatch', '2': 4},
     const {'1': 'UserDatabaseInternalError', '2': 5},
     const {'1': 'SqlInternalError', '2': 6},
+    const {'1': 'DatabaseConnectError', '2': 7},
     const {'1': 'UserNotLoginYet', '2': 10},
     const {'1': 'ReadCurrentIdFailed', '2': 11},
     const {'1': 'WriteCurrentIdFailed', '2': 12},
@@ -41,7 +42,7 @@ const ErrorCode$json = const {
 };
 
 /// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSCwoHVW5rbm93bhAAEhoKFlVzZXJEYXRhYmFzZUluaXRGYWlsZWQQARIbChdVc2VyRGF0YWJhc2VXcml0ZUxvY2tlZBACEhoKFlVzZXJEYXRhYmFzZVJlYWRMb2NrZWQQAxIbChdVc2VyRGF0YWJhc2VEaWROb3RNYXRjaBAEEh0KGVVzZXJEYXRhYmFzZUludGVybmFsRXJyb3IQBRIUChBTcWxJbnRlcm5hbEVycm9yEAYSEwoPVXNlck5vdExvZ2luWWV0EAoSFwoTUmVhZEN1cnJlbnRJZEZhaWxlZBALEhgKFFdyaXRlQ3VycmVudElkRmFpbGVkEAwSEAoMRW1haWxJc0VtcHR5EBQSFgoSRW1haWxGb3JtYXRJbnZhbGlkEBUSFgoSRW1haWxBbHJlYWR5RXhpc3RzEBYSEwoPUGFzc3dvcmRJc0VtcHR5EB4SEwoPUGFzc3dvcmRUb29Mb25nEB8SJAogUGFzc3dvcmRDb250YWluc0ZvcmJpZENoYXJhY3RlcnMQIBIZChVQYXNzd29yZEZvcm1hdEludmFsaWQQIRITCg9Vc2VyTmFtZVRvb0xvbmcQKBInCiNVc2VyTmFtZUNvbnRhaW5zRm9yYmlkZGVuQ2hhcmFjdGVycxApEhMKD1VzZXJOYW1lSXNFbXB0eRAqEhgKFFVzZXJXb3Jrc3BhY2VJbnZhbGlkEDISEQoNVXNlcklkSW52YWxpZBAzEiAKHENyZWF0ZURlZmF1bHRXb3Jrc3BhY2VGYWlsZWQQNBIgChxEZWZhdWx0V29ya3NwYWNlQWxyZWFkeUV4aXN0EDUSDwoLU2VydmVyRXJyb3IQZA==');
+final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSCwoHVW5rbm93bhAAEhoKFlVzZXJEYXRhYmFzZUluaXRGYWlsZWQQARIbChdVc2VyRGF0YWJhc2VXcml0ZUxvY2tlZBACEhoKFlVzZXJEYXRhYmFzZVJlYWRMb2NrZWQQAxIbChdVc2VyRGF0YWJhc2VEaWROb3RNYXRjaBAEEh0KGVVzZXJEYXRhYmFzZUludGVybmFsRXJyb3IQBRIUChBTcWxJbnRlcm5hbEVycm9yEAYSGAoURGF0YWJhc2VDb25uZWN0RXJyb3IQBxITCg9Vc2VyTm90TG9naW5ZZXQQChIXChNSZWFkQ3VycmVudElkRmFpbGVkEAsSGAoUV3JpdGVDdXJyZW50SWRGYWlsZWQQDBIQCgxFbWFpbElzRW1wdHkQFBIWChJFbWFpbEZvcm1hdEludmFsaWQQFRIWChJFbWFpbEFscmVhZHlFeGlzdHMQFhITCg9QYXNzd29yZElzRW1wdHkQHhITCg9QYXNzd29yZFRvb0xvbmcQHxIkCiBQYXNzd29yZENvbnRhaW5zRm9yYmlkQ2hhcmFjdGVycxAgEhkKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBAhEhMKD1VzZXJOYW1lVG9vTG9uZxAoEicKI1VzZXJOYW1lQ29udGFpbnNGb3JiaWRkZW5DaGFyYWN0ZXJzECkSEwoPVXNlck5hbWVJc0VtcHR5ECoSGAoUVXNlcldvcmtzcGFjZUludmFsaWQQMhIRCg1Vc2VySWRJbnZhbGlkEDMSIAocQ3JlYXRlRGVmYXVsdFdvcmtzcGFjZUZhaWxlZBA0EiAKHERlZmF1bHRXb3Jrc3BhY2VBbHJlYWR5RXhpc3QQNRIPCgtTZXJ2ZXJFcnJvchBk');
 @$core.Deprecated('Use userErrorDescriptor instead')
 const UserError$json = const {
   '1': 'UserError',
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart
index 9cd1a5ad21..11f095a07c 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart
@@ -10,14 +10,14 @@ import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 
 class UserEvent extends $pb.ProtobufEnum {
-  static const UserEvent GetStatus = UserEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetStatus');
+  static const UserEvent GetUserProfile = UserEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetUserProfile');
   static const UserEvent SignIn = UserEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SignIn');
   static const UserEvent SignUp = UserEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SignUp');
   static const UserEvent SignOut = UserEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SignOut');
   static const UserEvent UpdateUser = UserEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateUser');
 
   static const $core.List<UserEvent> values = <UserEvent> [
-    GetStatus,
+    GetUserProfile,
     SignIn,
     SignUp,
     SignOut,
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart
index b514b74420..596a4c7f87 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart
@@ -12,7 +12,7 @@ import 'dart:typed_data' as $typed_data;
 const UserEvent$json = const {
   '1': 'UserEvent',
   '2': const [
-    const {'1': 'GetStatus', '2': 0},
+    const {'1': 'GetUserProfile', '2': 0},
     const {'1': 'SignIn', '2': 1},
     const {'1': 'SignUp', '2': 2},
     const {'1': 'SignOut', '2': 3},
@@ -21,4 +21,4 @@ const UserEvent$json = const {
 };
 
 /// Descriptor for `UserEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSDQoJR2V0U3RhdHVzEAASCgoGU2lnbkluEAESCgoGU2lnblVwEAISCwoHU2lnbk91dBADEg4KClVwZGF0ZVVzZXIQBA==');
+final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSEgoOR2V0VXNlclByb2ZpbGUQABIKCgZTaWduSW4QARIKCgZTaWduVXAQAhILCgdTaWduT3V0EAMSDgoKVXBkYXRlVXNlchAE');
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pb.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pb.dart
index 83a4c2cf8c..b63e7a97df 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pb.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pb.dart
@@ -11,14 +11,14 @@ import 'package:protobuf/protobuf.dart' as $pb;
 
 export 'user_detail.pbenum.dart';
 
-class QueryUserDetailParams extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryUserDetailParams', createEmptyInstance: create)
+class UserToken extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UserToken', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'token')
     ..hasRequiredFields = false
   ;
 
-  QueryUserDetailParams._() : super();
-  factory QueryUserDetailParams({
+  UserToken._() : super();
+  factory UserToken({
     $core.String? token,
   }) {
     final _result = create();
@@ -27,26 +27,26 @@ class QueryUserDetailParams extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory QueryUserDetailParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory QueryUserDetailParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory UserToken.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UserToken.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
   'Will be removed in next major version')
-  QueryUserDetailParams clone() => QueryUserDetailParams()..mergeFromMessage(this);
+  UserToken clone() => UserToken()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  QueryUserDetailParams copyWith(void Function(QueryUserDetailParams) updates) => super.copyWith((message) => updates(message as QueryUserDetailParams)) as QueryUserDetailParams; // ignore: deprecated_member_use
+  UserToken copyWith(void Function(UserToken) updates) => super.copyWith((message) => updates(message as UserToken)) as UserToken; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static QueryUserDetailParams create() => QueryUserDetailParams._();
-  QueryUserDetailParams createEmptyInstance() => create();
-  static $pb.PbList<QueryUserDetailParams> createRepeated() => $pb.PbList<QueryUserDetailParams>();
+  static UserToken create() => UserToken._();
+  UserToken createEmptyInstance() => create();
+  static $pb.PbList<UserToken> createRepeated() => $pb.PbList<UserToken>();
   @$core.pragma('dart2js:noInline')
-  static QueryUserDetailParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<QueryUserDetailParams>(create);
-  static QueryUserDetailParams? _defaultInstance;
+  static UserToken getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UserToken>(create);
+  static UserToken? _defaultInstance;
 
   @$pb.TagNumber(1)
   $core.String get token => $_getSZ(0);
diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pbjson.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pbjson.dart
index 9394c8524f..94230694b5 100644
--- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pbjson.dart
+++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_detail.pbjson.dart
@@ -20,16 +20,16 @@ const UserStatus$json = const {
 
 /// Descriptor for `UserStatus`. Decode as a `google.protobuf.EnumDescriptorProto`.
 final $typed_data.Uint8List userStatusDescriptor = $convert.base64Decode('CgpVc2VyU3RhdHVzEgsKB1Vua25vd24QABIJCgVMb2dpbhABEgsKB0V4cGlyZWQQAg==');
-@$core.Deprecated('Use queryUserDetailParamsDescriptor instead')
-const QueryUserDetailParams$json = const {
-  '1': 'QueryUserDetailParams',
+@$core.Deprecated('Use userTokenDescriptor instead')
+const UserToken$json = const {
+  '1': 'UserToken',
   '2': const [
     const {'1': 'token', '3': 1, '4': 1, '5': 9, '10': 'token'},
   ],
 };
 
-/// Descriptor for `QueryUserDetailParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List queryUserDetailParamsDescriptor = $convert.base64Decode('ChVRdWVyeVVzZXJEZXRhaWxQYXJhbXMSFAoFdG9rZW4YASABKAlSBXRva2Vu');
+/// Descriptor for `UserToken`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List userTokenDescriptor = $convert.base64Decode('CglVc2VyVG9rZW4SFAoFdG9rZW4YASABKAlSBXRva2Vu');
 @$core.Deprecated('Use userDetailDescriptor instead')
 const UserDetail$json = const {
   '1': 'UserDetail',
diff --git a/backend/src/application.rs b/backend/src/application.rs
index f5c88efdfb..d782478445 100644
--- a/backend/src/application.rs
+++ b/backend/src/application.rs
@@ -83,6 +83,9 @@ fn user_scope() -> Scope {
             .route(web::delete().to(user::sign_out_handler))
             .route(web::get().to(user::user_detail_handler))
         )
+        .service(web::resource("/register")
+            .route(web::post().to(user::register_handler))
+        )
         .service(web::resource("/workspace")
             .route(web::post().to(workspace::create_handler))
             .route(web::delete().to(workspace::delete_handler))
@@ -108,10 +111,6 @@ fn user_scope() -> Scope {
         .service(web::resource("/password_change")
             .route(web::post().to(user::change_password))
         )
-        // register
-        .service(web::resource("/register")
-            .route(web::post().to(user::register_user_handler))
-        )
 }
 
 async fn init_app_context(configuration: &Settings) -> AppContext {
diff --git a/backend/src/user_service/auth.rs b/backend/src/user_service/auth.rs
index ef9ddebf56..bc20ddd5e1 100644
--- a/backend/src/user_service/auth.rs
+++ b/backend/src/user_service/auth.rs
@@ -14,14 +14,7 @@ use flowy_net::{
 };
 use flowy_user::{
     entities::parser::{UserEmail, UserName, UserPassword},
-    protobuf::{
-        SignInParams,
-        SignInResponse,
-        SignOutParams,
-        SignUpParams,
-        SignUpResponse,
-        UserDetail,
-    },
+    protobuf::{SignInParams, SignInResponse, SignUpParams, SignUpResponse, UserDetail},
 };
 use sqlx::{PgPool, Postgres};
 
@@ -59,7 +52,7 @@ pub async fn sign_in(pool: &PgPool, params: SignInParams) -> Result<SignInRespon
     }
 }
 
-pub async fn sign_out(params: SignOutParams) -> Result<FlowyResponse, ServerError> {
+pub async fn sign_out(params: UserToken) -> Result<FlowyResponse, ServerError> {
     let _ = AUTHORIZED_USERS.store_auth(LoggedUser::from_token(params.token.clone())?, false)?;
     Ok(FlowyResponse::success())
 }
diff --git a/backend/src/user_service/mod.rs b/backend/src/user_service/mod.rs
index 3630dedae0..ae79137ff4 100644
--- a/backend/src/user_service/mod.rs
+++ b/backend/src/user_service/mod.rs
@@ -1,10 +1,8 @@
 mod auth;
 mod logged_user;
-mod profile;
 pub mod router;
 mod utils;
 
 pub use auth::*;
 pub use logged_user::*;
-pub use profile::*;
 pub use utils::*;
diff --git a/backend/src/user_service/profile.rs b/backend/src/user_service/profile.rs
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/backend/src/user_service/router.rs b/backend/src/user_service/router.rs
index af7485e78a..cc67ee7a7f 100644
--- a/backend/src/user_service/router.rs
+++ b/backend/src/user_service/router.rs
@@ -8,7 +8,7 @@ use actix_web::{
 use crate::user_service::{get_user_details, register_user, sign_in, sign_out};
 use actix_identity::Identity;
 use flowy_net::{errors::ServerError, response::FlowyResponse};
-use flowy_user::protobuf::{QueryUserDetailParams, SignInParams, SignOutParams, SignUpParams};
+use flowy_user::protobuf::{SignInParams, SignUpParams, UserToken};
 use sqlx::PgPool;
 
 pub async fn sign_in_handler(
@@ -24,7 +24,7 @@ pub async fn sign_in_handler(
 }
 
 pub async fn sign_out_handler(payload: Payload, id: Identity) -> Result<HttpResponse, ServerError> {
-    let params: SignOutParams = parse_from_payload(payload).await?;
+    let params: UserToken = parse_from_payload(payload).await?;
     id.forget();
 
     let response = sign_out(params).await?;
@@ -40,7 +40,7 @@ pub async fn user_detail_handler(
     Ok(response.into())
 }
 
-pub async fn register_user_handler(
+pub async fn register_handler(
     payload: Payload,
     pool: Data<PgPool>,
 ) -> Result<HttpResponse, ServerError> {
diff --git a/backend/tests/api/auth.rs b/backend/tests/api/auth.rs
index ac3b2099cb..dbfa64aad0 100644
--- a/backend/tests/api/auth.rs
+++ b/backend/tests/api/auth.rs
@@ -1,11 +1,5 @@
 use crate::helper::{spawn_app, TestApp};
-use flowy_user::entities::{
-    QueryUserDetailParams,
-    SignInParams,
-    SignOutParams,
-    SignUpParams,
-    SignUpResponse,
-};
+use flowy_user::entities::{SignInParams, SignUpParams, SignUpResponse, UserToken};
 
 #[actix_rt::test]
 async fn user_register() {
@@ -62,12 +56,12 @@ async fn user_sign_out() {
         .await;
 
     let token = sign_in_resp.token.clone();
-    let sign_out_params = SignOutParams {
+    let user_token = UserToken {
         token: token.clone(),
     };
-    app.sign_out(sign_out_params).await;
+    app.sign_out(user_token).await;
 
-    let query_user_params = QueryUserDetailParams { token };
+    let query_user_params = UserToken { token };
     app.get_user_detail(query_user_params).await;
 }
 
@@ -77,7 +71,7 @@ async fn user_get_detail() {
     let email = "annie@appflowy.io";
     let password = "HelloWork123!";
     let sign_up_resp = register_user(&app, email, password).await;
-    let query_user_params = QueryUserDetailParams {
+    let query_user_params = UserToken {
         token: sign_up_resp.token,
     };
     log::info!("{:?}", app.get_user_detail(query_user_params).await);
diff --git a/backend/tests/api/helper.rs b/backend/tests/api/helper.rs
index a6c2b232df..1366a585f6 100644
--- a/backend/tests/api/helper.rs
+++ b/backend/tests/api/helper.rs
@@ -27,12 +27,12 @@ impl TestApp {
         resp
     }
 
-    pub async fn sign_out(&self, params: SignOutParams) {
+    pub async fn sign_out(&self, params: UserToken) {
         let url = format!("{}/api/auth", self.address);
         let _ = user_sign_out(params, &url).await.unwrap();
     }
 
-    pub async fn get_user_detail(&self, params: QueryUserDetailParams) -> UserDetail {
+    pub async fn get_user_detail(&self, params: UserToken) -> UserDetail {
         let url = format!("{}/api/auth", self.address);
         let user_detail = get_user_detail(params, &url).await.unwrap();
         user_detail
diff --git a/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs b/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
index 1f6fb009cd..c2e790c7d1 100644
--- a/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
+++ b/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
@@ -65,8 +65,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "SignUpRequest"
         | "SignUpParams"
         | "SignUpResponse"
-        | "SignOutParams"
-        | "QueryUserDetailParams"
+        | "UserToken"
         | "UserDetail"
         | "UpdateUserRequest"
         | "UpdateUserParams"
diff --git a/rust-lib/flowy-document/tests/editor/helper.rs b/rust-lib/flowy-document/tests/editor/helper.rs
index 83ac57845a..a612d27f53 100644
--- a/rust-lib/flowy-document/tests/editor/helper.rs
+++ b/rust-lib/flowy-document/tests/editor/helper.rs
@@ -1,4 +1,4 @@
-use flowy_test::builder::UserTestBuilder;
+use flowy_test::builder::AnnieTestBuilder;
 
 use flowy_document::{entities::doc::*, event::EditorEvent::*};
 use flowy_infra::uuid;
@@ -11,7 +11,7 @@ pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo {
         text: text.to_owned(),
     };
 
-    let doc_desc = UserTestBuilder::new()
+    let doc_desc = AnnieTestBuilder::new()
         .event(CreateDoc)
         .request(request)
         .sync_send()
@@ -28,7 +28,7 @@ pub fn save_doc(desc: &DocInfo, content: &str) {
         text: Some(content.to_owned()),
     };
 
-    let _ = UserTestBuilder::new()
+    let _ = AnnieTestBuilder::new()
         .event(UpdateDoc)
         .request(request)
         .sync_send();
@@ -40,7 +40,7 @@ pub fn read_doc(doc_id: &str) -> DocInfo {
         doc_id: doc_id.to_string(),
     };
 
-    let doc = UserTestBuilder::new()
+    let doc = AnnieTestBuilder::new()
         .event(ReadDocInfo)
         .request(request)
         .sync_send()
@@ -55,7 +55,7 @@ pub fn read_doc_data(doc_id: &str, path: &str) -> DocData {
         path: path.to_string(),
     };
 
-    let doc = UserTestBuilder::new()
+    let doc = AnnieTestBuilder::new()
         .event(ReadDocData)
         .request(request)
         .sync_send()
diff --git a/rust-lib/flowy-infra/Cargo.toml b/rust-lib/flowy-infra/Cargo.toml
index 0173f3863b..06d6364f48 100644
--- a/rust-lib/flowy-infra/Cargo.toml
+++ b/rust-lib/flowy-infra/Cargo.toml
@@ -16,4 +16,6 @@ lazy_static = "1.4.0"
 protobuf = {version = "2.18.0"}
 log = "0.4.14"
 chrono = "0.4.19"
-bytes = { version = "1.0" }
\ No newline at end of file
+bytes = { version = "1.0" }
+pin-project = "1.0.0"
+futures-core = { version = "0.3", default-features = false }
\ No newline at end of file
diff --git a/rust-lib/flowy-net/src/future.rs b/rust-lib/flowy-infra/src/future.rs
similarity index 100%
rename from rust-lib/flowy-net/src/future.rs
rename to rust-lib/flowy-infra/src/future.rs
diff --git a/rust-lib/flowy-infra/src/lib.rs b/rust-lib/flowy-infra/src/lib.rs
index 039494e6d8..2e38dd2892 100644
--- a/rust-lib/flowy-infra/src/lib.rs
+++ b/rust-lib/flowy-infra/src/lib.rs
@@ -5,6 +5,7 @@ extern crate diesel;
 extern crate diesel_derives;
 
 pub mod errors;
+pub mod future;
 pub mod kv;
 mod protobuf;
 
diff --git a/rust-lib/flowy-net/Cargo.toml b/rust-lib/flowy-net/Cargo.toml
index 2295f58a4a..981d007a3d 100644
--- a/rust-lib/flowy-net/Cargo.toml
+++ b/rust-lib/flowy-net/Cargo.toml
@@ -21,6 +21,7 @@ tokio = { version = "1", features = ["full"] }
 actix-web = {version = "4.0.0-beta.8", optional = true}
 derive_more = {version = "0.99", features = ["display"]}
 flowy-derive = { path = "../flowy-derive" }
+flowy-infra = { path = "../flowy-infra"}
 anyhow = "1.0"
 thiserror = "1.0.24"
 uuid = { version = "0.8", features = ["v4"] }
diff --git a/rust-lib/flowy-net/src/config.rs b/rust-lib/flowy-net/src/config.rs
index 15599b77e7..7143339987 100644
--- a/rust-lib/flowy-net/src/config.rs
+++ b/rust-lib/flowy-net/src/config.rs
@@ -5,4 +5,6 @@ pub const HOST: &'static str = "http://localhost:8000";
 lazy_static! {
     pub static ref SIGN_UP_URL: String = format!("{}/api/register", HOST);
     pub static ref SIGN_IN_URL: String = format!("{}/api/auth", HOST);
+    pub static ref USER_DETAIL_URL: String = format!("{}/api/auth", HOST);
+    pub static ref SIGN_OUT_URL: String = format!("{}/api/auth", HOST);
 }
diff --git a/rust-lib/flowy-net/src/lib.rs b/rust-lib/flowy-net/src/lib.rs
index 4f8feb7562..acd2bf2712 100644
--- a/rust-lib/flowy-net/src/lib.rs
+++ b/rust-lib/flowy-net/src/lib.rs
@@ -1,5 +1,4 @@
 pub mod config;
 pub mod errors;
-pub mod future;
 pub mod request;
 pub mod response;
diff --git a/rust-lib/flowy-sdk/src/deps_resolve/mod.rs b/rust-lib/flowy-sdk/src/deps_resolve/mod.rs
index a56671ac5c..379f23f2fc 100644
--- a/rust-lib/flowy-sdk/src/deps_resolve/mod.rs
+++ b/rust-lib/flowy-sdk/src/deps_resolve/mod.rs
@@ -1,7 +1,5 @@
 mod editor_deps_impl;
-mod user_deps_impl;
 mod workspace_deps_impl;
 
 pub use editor_deps_impl::*;
-pub use user_deps_impl::*;
 pub use workspace_deps_impl::*;
diff --git a/rust-lib/flowy-sdk/src/deps_resolve/user_deps_impl.rs b/rust-lib/flowy-sdk/src/deps_resolve/user_deps_impl.rs
deleted file mode 100644
index 8ac0c93ffe..0000000000
--- a/rust-lib/flowy-sdk/src/deps_resolve/user_deps_impl.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-use flowy_user::services::workspace::UserWorkspaceController;
-
-pub struct UserWorkspaceControllerImpl {}
-impl UserWorkspaceController for UserWorkspaceControllerImpl {}
diff --git a/rust-lib/flowy-sdk/src/module.rs b/rust-lib/flowy-sdk/src/module.rs
index bace7d3754..bb7b4be0c0 100644
--- a/rust-lib/flowy-sdk/src/module.rs
+++ b/rust-lib/flowy-sdk/src/module.rs
@@ -4,7 +4,6 @@ use flowy_user::prelude::*;
 use crate::deps_resolve::{
     EditorDatabaseImpl,
     EditorUserImpl,
-    UserWorkspaceControllerImpl,
     WorkspaceDatabaseImpl,
     WorkspaceUserImpl,
 };
@@ -15,11 +14,7 @@ pub struct ModuleConfig {
 }
 
 pub fn build_modules(config: ModuleConfig) -> Vec<Module> {
-    let user_session = Arc::new(
-        UserSessionBuilder::new()
-            .root_dir(&config.root)
-            .build(Arc::new(UserWorkspaceControllerImpl {})),
-    );
+    let user_session = Arc::new(UserSessionBuilder::new().root_dir(&config.root).build());
 
     let workspace_user_impl = Arc::new(WorkspaceUserImpl {
         user_session: user_session.clone(),
diff --git a/rust-lib/flowy-sqlite/src/database.rs b/rust-lib/flowy-sqlite/src/database.rs
index e3aec6c171..ded7e4a19d 100644
--- a/rust-lib/flowy-sqlite/src/database.rs
+++ b/rust-lib/flowy-sqlite/src/database.rs
@@ -3,10 +3,11 @@ use crate::{
     pool::{ConnectionManager, ConnectionPool, PoolConfig},
 };
 use r2d2::PooledConnection;
+use std::sync::Arc;
 
 pub struct Database {
     uri: String,
-    pool: ConnectionPool,
+    pool: Arc<ConnectionPool>,
 }
 
 pub type DBConnection = PooledConnection<ConnectionManager>;
@@ -20,7 +21,10 @@ impl Database {
         }
 
         let pool = ConnectionPool::new(pool_config, &uri)?;
-        Ok(Self { uri, pool })
+        Ok(Self {
+            uri,
+            pool: Arc::new(pool),
+        })
     }
 
     pub fn get_uri(&self) -> &str { &self.uri }
@@ -29,6 +33,8 @@ impl Database {
         let conn = self.pool.get()?;
         Ok(conn)
     }
+
+    pub fn get_pool(&self) -> Arc<ConnectionPool> { self.pool.clone() }
 }
 
 pub fn db_file_uri(dir: &str, name: &str) -> String {
diff --git a/rust-lib/flowy-test/src/builder.rs b/rust-lib/flowy-test/src/builder.rs
index a7f4e5bfbb..0cd50e45ce 100644
--- a/rust-lib/flowy-test/src/builder.rs
+++ b/rust-lib/flowy-test/src/builder.rs
@@ -13,10 +13,10 @@ use flowy_user::errors::UserError;
 use flowy_workspace::errors::WorkspaceError;
 use std::marker::PhantomData;
 
-pub type UserTestBuilder = TestBuilder<FixedUserTester<WorkspaceError>>;
-impl UserTestBuilder {
+pub type AnnieTestBuilder = Builder<FlowyAnnie<WorkspaceError>>;
+impl AnnieTestBuilder {
     pub fn new() -> Self {
-        let mut builder = TestBuilder::test(Box::new(FixedUserTester::<WorkspaceError>::new()));
+        let mut builder = Builder::test(Box::new(FlowyAnnie::<WorkspaceError>::new()));
         builder.setup_default_workspace();
         builder
     }
@@ -27,19 +27,17 @@ impl UserTestBuilder {
         let _ = create_default_workspace_if_need(&user_id);
     }
 }
-pub type RandomUserTestBuilder = TestBuilder<RandomUserTester<UserError>>;
-impl RandomUserTestBuilder {
-    pub fn new() -> Self { TestBuilder::test(Box::new(RandomUserTester::<UserError>::new())) }
-
-    pub fn reset(self) -> Self { self.login() }
+pub type TestBuilder = Builder<RandomUserTester<UserError>>;
+impl TestBuilder {
+    pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<UserError>::new())) }
 }
 
-pub struct TestBuilder<T: TesterTrait> {
+pub struct Builder<T: TesterTrait> {
     pub tester: Box<T>,
     pub user_detail: Option<UserDetail>,
 }
 
-impl<T> TestBuilder<T>
+impl<T> Builder<T>
 where
     T: TesterTrait,
 {
@@ -135,12 +133,12 @@ where
     fn context(&self) -> &TesterContext { &self.context }
 }
 
-pub struct FixedUserTester<Error> {
+pub struct FlowyAnnie<Error> {
     context: TesterContext,
     err_phantom: PhantomData<Error>,
 }
 
-impl<Error> FixedUserTester<Error>
+impl<Error> FlowyAnnie<Error>
 where
     Error: FromBytes + Debug,
 {
@@ -152,7 +150,7 @@ where
     }
 }
 
-impl<Error> TesterTrait for FixedUserTester<Error>
+impl<Error> TesterTrait for FlowyAnnie<Error>
 where
     Error: FromBytes + Debug,
 {
diff --git a/rust-lib/flowy-test/src/helper.rs b/rust-lib/flowy-test/src/helper.rs
index 76c7c9afe4..2776178142 100644
--- a/rust-lib/flowy-test/src/helper.rs
+++ b/rust-lib/flowy-test/src/helper.rs
@@ -24,7 +24,7 @@ pub fn root_dir() -> String {
     root_dir
 }
 
-pub fn random_valid_email() -> String { format!("{}@appflowy.io", uuid()) }
+pub fn random_email() -> String { format!("{}@appflowy.io", uuid()) }
 
 pub fn valid_email() -> String { "annie@appflowy.io".to_string() }
 
diff --git a/rust-lib/flowy-test/src/tester.rs b/rust-lib/flowy-test/src/tester.rs
index c77967d56e..b8314a654c 100644
--- a/rust-lib/flowy-test/src/tester.rs
+++ b/rust-lib/flowy-test/src/tester.rs
@@ -1,12 +1,12 @@
 use crate::{
-    helper::{random_valid_email, valid_password},
+    helper::{random_email, valid_password},
     init_test_sdk,
 };
 use flowy_dispatch::prelude::*;
 pub use flowy_sdk::*;
 use flowy_user::{
     errors::UserError,
-    event::UserEvent::{GetStatus, SignOut, SignUp},
+    event::UserEvent::{GetUserProfile, SignOut, SignUp},
     prelude::*,
 };
 
@@ -38,7 +38,7 @@ impl std::default::Default for TesterContext {
             request: None,
             status_code: StatusCode::Ok,
             response: None,
-            user_email: random_valid_email(),
+            user_email: random_email(),
         }
     }
 }
@@ -126,7 +126,7 @@ pub trait TesterTrait {
 
     fn login_if_need(&self) -> UserDetail {
         init_test_sdk();
-        match EventDispatch::sync_send(ModuleRequest::new(GetStatus))
+        match EventDispatch::sync_send(ModuleRequest::new(GetUserProfile))
             .parse::<UserDetail, UserError>()
             .unwrap()
         {
diff --git a/rust-lib/flowy-user/Cargo.toml b/rust-lib/flowy-user/Cargo.toml
index 7d5cf18c52..c81ef8d0d0 100644
--- a/rust-lib/flowy-user/Cargo.toml
+++ b/rust-lib/flowy-user/Cargo.toml
@@ -33,6 +33,10 @@ once_cell = "1.7.2"
 parking_lot = "0.11"
 strum = "0.21"
 strum_macros = "0.21"
+tokio = { version = "1", features = ["full"] }
+pin-project = "1.0.0"
+futures-core = { version = "0.3", default-features = false }
+r2d2 = "0.8.9"
 
 [dev-dependencies]
 quickcheck = "0.9.2"
@@ -40,7 +44,6 @@ quickcheck_macros = "0.9.1"
 fake = "~2.3.0"
 claim = "0.4.0"
 flowy-test = { path = "../flowy-test" }
-tokio = { version = "1", features = ["full"] }
 futures = "0.3.15"
 serial_test = "0.5.1"
 
diff --git a/rust-lib/flowy-user/src/entities/auth.rs b/rust-lib/flowy-user/src/entities/auth.rs
index 85f44bb3a6..8cd2b38353 100644
--- a/rust-lib/flowy-user/src/entities/auth.rs
+++ b/rust-lib/flowy-user/src/entities/auth.rs
@@ -104,9 +104,3 @@ pub struct SignUpResponse {
     #[pb(index = 4)]
     pub token: String,
 }
-
-#[derive(Default, ProtoBuf)]
-pub struct SignOutParams {
-    #[pb(index = 1)]
-    pub token: String,
-}
diff --git a/rust-lib/flowy-user/src/entities/user_detail.rs b/rust-lib/flowy-user/src/entities/user_detail.rs
index 07fe7bb649..1f7b65ad38 100644
--- a/rust-lib/flowy-user/src/entities/user_detail.rs
+++ b/rust-lib/flowy-user/src/entities/user_detail.rs
@@ -1,7 +1,7 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 
 #[derive(Default, ProtoBuf)]
-pub struct QueryUserDetailParams {
+pub struct UserToken {
     #[pb(index = 1)]
     pub token: String,
 }
diff --git a/rust-lib/flowy-user/src/errors.rs b/rust-lib/flowy-user/src/errors.rs
index c4fec0f838..5a0406f9ba 100644
--- a/rust-lib/flowy-user/src/errors.rs
+++ b/rust-lib/flowy-user/src/errors.rs
@@ -43,6 +43,9 @@ pub enum ErrorCode {
     #[display(fmt = "Sql internal error")]
     SqlInternalError     = 6,
 
+    #[display(fmt = "r2d2 connection error")]
+    DatabaseConnectError = 7,
+
     #[display(fmt = "User not login yet")]
     UserNotLoginYet      = 10,
     #[display(fmt = "Get current id read lock failed")]
@@ -106,6 +109,15 @@ impl std::convert::From<flowy_database::result::Error> for UserError {
             .build()
     }
 }
+
+impl std::convert::From<::r2d2::Error> for UserError {
+    fn from(error: r2d2::Error) -> Self {
+        ErrorBuilder::new(ErrorCode::DatabaseConnectError)
+            .error(error)
+            .build()
+    }
+}
+
 // use diesel::result::{Error, DatabaseErrorKind};
 // use flowy_sqlite::ErrorKind;
 impl std::convert::From<flowy_sqlite::Error> for UserError {
diff --git a/rust-lib/flowy-user/src/event.rs b/rust-lib/flowy-user/src/event.rs
index 273972a899..f0ff2aafe7 100644
--- a/rust-lib/flowy-user/src/event.rs
+++ b/rust-lib/flowy-user/src/event.rs
@@ -5,17 +5,17 @@ use strum_macros::Display;
 #[event_err = "UserError"]
 pub enum UserEvent {
     #[event(output = "UserDetail")]
-    GetStatus  = 0,
+    GetUserProfile = 0,
 
     #[event(input = "SignInRequest", output = "UserDetail")]
-    SignIn     = 1,
+    SignIn         = 1,
 
     #[event(input = "SignUpRequest", output = "UserDetail")]
-    SignUp     = 2,
+    SignUp         = 2,
 
     #[event(passthrough)]
-    SignOut    = 3,
+    SignOut        = 3,
 
-    #[event(input = "UpdateUserRequest", output = "UserDetail")]
-    UpdateUser = 4,
+    #[event(input = "UpdateUserRequest")]
+    UpdateUser     = 4,
 }
diff --git a/rust-lib/flowy-user/src/handlers/user_handler.rs b/rust-lib/flowy-user/src/handlers/user_handler.rs
index 4796324af5..7447e254ea 100644
--- a/rust-lib/flowy-user/src/handlers/user_handler.rs
+++ b/rust-lib/flowy-user/src/handlers/user_handler.rs
@@ -1,10 +1,17 @@
-use crate::{entities::*, errors::UserError, services::user::UserSession};
+use crate::{
+    entities::*,
+    errors::UserError,
+    services::user::{update_user, UserSession},
+};
 use flowy_dispatch::prelude::*;
+use flowy_infra::future::ResultFuture;
 use std::{convert::TryInto, sync::Arc};
 
 #[tracing::instrument(name = "get_user_status", skip(session))]
-pub async fn get_user_status(session: Unit<Arc<UserSession>>) -> DataResult<UserDetail, UserError> {
-    let user_detail = session.user_detail()?;
+pub async fn user_status_handler(
+    session: Unit<Arc<UserSession>>,
+) -> DataResult<UserDetail, UserError> {
+    let user_detail = session.user_detail().await?;
     data_result(user_detail)
 }
 
@@ -15,11 +22,11 @@ pub async fn sign_out(session: Unit<Arc<UserSession>>) -> Result<(), UserError>
 }
 
 #[tracing::instrument(name = "update_user", skip(data, session))]
-pub async fn update_user(
+pub async fn update_user_handler(
     data: Data<UpdateUserRequest>,
     session: Unit<Arc<UserSession>>,
-) -> DataResult<UserDetail, UserError> {
+) -> Result<(), UserError> {
     let params: UpdateUserParams = data.into_inner().try_into()?;
-    let user_detail = session.update_user(params)?;
-    data_result(user_detail)
+    session.update_user(params).await?;
+    Ok(())
 }
diff --git a/rust-lib/flowy-user/src/lib.rs b/rust-lib/flowy-user/src/lib.rs
index d5459ba5e9..690b714d7e 100644
--- a/rust-lib/flowy-user/src/lib.rs
+++ b/rust-lib/flowy-user/src/lib.rs
@@ -12,8 +12,5 @@ pub mod services;
 extern crate flowy_database;
 
 pub mod prelude {
-    pub use crate::{
-        entities::*,
-        services::{user::*, workspace::*},
-    };
+    pub use crate::{entities::*, services::user::*};
 }
diff --git a/rust-lib/flowy-user/src/module.rs b/rust-lib/flowy-user/src/module.rs
index 5fa2d6e7ab..54ae495359 100644
--- a/rust-lib/flowy-user/src/module.rs
+++ b/rust-lib/flowy-user/src/module.rs
@@ -9,7 +9,7 @@ pub fn create(user_session: Arc<UserSession>) -> Module {
         .data(user_session)
         .event(UserEvent::SignIn, sign_in)
         .event(UserEvent::SignUp, sign_up)
-        .event(UserEvent::GetStatus, get_user_status)
+        .event(UserEvent::GetUserProfile, user_status_handler)
         .event(UserEvent::SignOut, sign_out)
-        .event(UserEvent::UpdateUser, update_user)
+        .event(UserEvent::UpdateUser, update_user_handler)
 }
diff --git a/rust-lib/flowy-user/src/protobuf/model/auth.rs b/rust-lib/flowy-user/src/protobuf/model/auth.rs
index e33c4b8e08..09f2f7382e 100644
--- a/rust-lib/flowy-user/src/protobuf/model/auth.rs
+++ b/rust-lib/flowy-user/src/protobuf/model/auth.rs
@@ -1481,165 +1481,6 @@ impl ::protobuf::reflect::ProtobufValue for SignUpResponse {
     }
 }
 
-#[derive(PartialEq,Clone,Default)]
-pub struct SignOutParams {
-    // message fields
-    pub token: ::std::string::String,
-    // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
-}
-
-impl<'a> ::std::default::Default for &'a SignOutParams {
-    fn default() -> &'a SignOutParams {
-        <SignOutParams as ::protobuf::Message>::default_instance()
-    }
-}
-
-impl SignOutParams {
-    pub fn new() -> SignOutParams {
-        ::std::default::Default::default()
-    }
-
-    // string token = 1;
-
-
-    pub fn get_token(&self) -> &str {
-        &self.token
-    }
-    pub fn clear_token(&mut self) {
-        self.token.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_token(&mut self, v: ::std::string::String) {
-        self.token = v;
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_token(&mut self) -> &mut ::std::string::String {
-        &mut self.token
-    }
-
-    // Take field
-    pub fn take_token(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.token, ::std::string::String::new())
-    }
-}
-
-impl ::protobuf::Message for SignOutParams {
-    fn is_initialized(&self) -> bool {
-        true
-    }
-
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.token)?;
-                },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
-                },
-            };
-        }
-        ::std::result::Result::Ok(())
-    }
-
-    // Compute sizes of nested messages
-    #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
-        let mut my_size = 0;
-        if !self.token.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.token);
-        }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
-        my_size
-    }
-
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.token.is_empty() {
-            os.write_string(1, &self.token)?;
-        }
-        os.write_unknown_fields(self.get_unknown_fields())?;
-        ::std::result::Result::Ok(())
-    }
-
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
-    }
-
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
-    }
-
-    fn new() -> SignOutParams {
-        SignOutParams::new()
-    }
-
-    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
-        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
-        descriptor.get(|| {
-            let mut fields = ::std::vec::Vec::new();
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "token",
-                |m: &SignOutParams| { &m.token },
-                |m: &mut SignOutParams| { &mut m.token },
-            ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<SignOutParams>(
-                "SignOutParams",
-                fields,
-                file_descriptor_proto()
-            )
-        })
-    }
-
-    fn default_instance() -> &'static SignOutParams {
-        static instance: ::protobuf::rt::LazyV2<SignOutParams> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(SignOutParams::new)
-    }
-}
-
-impl ::protobuf::Clear for SignOutParams {
-    fn clear(&mut self) {
-        self.token.clear();
-        self.unknown_fields.clear();
-    }
-}
-
-impl ::std::fmt::Debug for SignOutParams {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-        ::protobuf::text_format::fmt(self, f)
-    }
-}
-
-impl ::protobuf::reflect::ProtobufValue for SignOutParams {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\nauth.proto\"A\n\rSignInRequest\x12\x14\n\x05email\x18\x01\x20\x01(\t\
     R\x05email\x12\x1a\n\x08password\x18\x02\x20\x01(\tR\x08password\"@\n\
@@ -1655,69 +1496,65 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x20\x01(\tR\x08password\"b\n\x0eSignUpResponse\x12\x10\n\x03uid\x18\x01\
     \x20\x01(\tR\x03uid\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\
     \x14\n\x05email\x18\x03\x20\x01(\tR\x05email\x12\x14\n\x05token\x18\x04\
-    \x20\x01(\tR\x05token\"%\n\rSignOutParams\x12\x14\n\x05token\x18\x01\x20\
-    \x01(\tR\x05tokenJ\xcf\t\n\x06\x12\x04\0\0\"\x01\n\x08\n\x01\x0c\x12\x03\
-    \0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\
-    \x03\x02\x08\x15\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\x0c\n\x05\
-    \x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\
-    \x03\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\x0b\n\x04\
-    \x04\0\x02\x01\x12\x03\x04\x04\x18\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\
-    \x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x13\n\x0c\n\x05\
-    \x04\0\x02\x01\x03\x12\x03\x04\x16\x17\n\n\n\x02\x04\x01\x12\x04\x06\0\t\
-    \x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x14\n\x0b\n\x04\x04\x01\x02\0\
-    \x12\x03\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\
-    \x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\x10\n\x0c\n\x05\x04\x01\x02\
-    \0\x03\x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x08\x04\
-    \x18\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x08\x04\n\n\x0c\n\x05\x04\
-    \x01\x02\x01\x01\x12\x03\x08\x0b\x13\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\
-    \x03\x08\x16\x17\n\n\n\x02\x04\x02\x12\x04\n\0\x0f\x01\n\n\n\x03\x04\x02\
-    \x01\x12\x03\n\x08\x16\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0b\x04\x13\n\
-    \x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x02\x02\0\
-    \x01\x12\x03\x0b\x0b\x0e\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0b\x11\
-    \x12\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x02\
-    \x02\x01\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\
-    \x0c\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0c\x12\x13\n\x0b\n\
-    \x04\x04\x02\x02\x02\x12\x03\r\x04\x15\n\x0c\n\x05\x04\x02\x02\x02\x05\
-    \x12\x03\r\x04\n\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\r\x0b\x10\n\x0c\
-    \n\x05\x04\x02\x02\x02\x03\x12\x03\r\x13\x14\n\x0b\n\x04\x04\x02\x02\x03\
-    \x12\x03\x0e\x04\x15\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\x03\x0e\x04\n\n\
-    \x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x0e\x0b\x10\n\x0c\n\x05\x04\x02\
-    \x02\x03\x03\x12\x03\x0e\x13\x14\n\n\n\x02\x04\x03\x12\x04\x10\0\x14\x01\
-    \n\n\n\x03\x04\x03\x01\x12\x03\x10\x08\x15\n\x0b\n\x04\x04\x03\x02\0\x12\
-    \x03\x11\x04\x15\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x11\x04\n\n\x0c\n\
-    \x05\x04\x03\x02\0\x01\x12\x03\x11\x0b\x10\n\x0c\n\x05\x04\x03\x02\0\x03\
-    \x12\x03\x11\x13\x14\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\x12\x04\x14\n\
-    \x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\x03\x02\
-    \x01\x01\x12\x03\x12\x0b\x0f\n\x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\x12\
-    \x12\x13\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x13\x04\x18\n\x0c\n\x05\x04\
-    \x03\x02\x02\x05\x12\x03\x13\x04\n\n\x0c\n\x05\x04\x03\x02\x02\x01\x12\
-    \x03\x13\x0b\x13\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\x13\x16\x17\n\n\
-    \n\x02\x04\x04\x12\x04\x15\0\x19\x01\n\n\n\x03\x04\x04\x01\x12\x03\x15\
-    \x08\x14\n\x0b\n\x04\x04\x04\x02\0\x12\x03\x16\x04\x15\n\x0c\n\x05\x04\
-    \x04\x02\0\x05\x12\x03\x16\x04\n\n\x0c\n\x05\x04\x04\x02\0\x01\x12\x03\
-    \x16\x0b\x10\n\x0c\n\x05\x04\x04\x02\0\x03\x12\x03\x16\x13\x14\n\x0b\n\
-    \x04\x04\x04\x02\x01\x12\x03\x17\x04\x14\n\x0c\n\x05\x04\x04\x02\x01\x05\
-    \x12\x03\x17\x04\n\n\x0c\n\x05\x04\x04\x02\x01\x01\x12\x03\x17\x0b\x0f\n\
-    \x0c\n\x05\x04\x04\x02\x01\x03\x12\x03\x17\x12\x13\n\x0b\n\x04\x04\x04\
-    \x02\x02\x12\x03\x18\x04\x18\n\x0c\n\x05\x04\x04\x02\x02\x05\x12\x03\x18\
-    \x04\n\n\x0c\n\x05\x04\x04\x02\x02\x01\x12\x03\x18\x0b\x13\n\x0c\n\x05\
-    \x04\x04\x02\x02\x03\x12\x03\x18\x16\x17\n\n\n\x02\x04\x05\x12\x04\x1a\0\
-    \x1f\x01\n\n\n\x03\x04\x05\x01\x12\x03\x1a\x08\x16\n\x0b\n\x04\x04\x05\
-    \x02\0\x12\x03\x1b\x04\x13\n\x0c\n\x05\x04\x05\x02\0\x05\x12\x03\x1b\x04\
-    \n\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03\x1b\x0b\x0e\n\x0c\n\x05\x04\x05\
-    \x02\0\x03\x12\x03\x1b\x11\x12\n\x0b\n\x04\x04\x05\x02\x01\x12\x03\x1c\
-    \x04\x14\n\x0c\n\x05\x04\x05\x02\x01\x05\x12\x03\x1c\x04\n\n\x0c\n\x05\
-    \x04\x05\x02\x01\x01\x12\x03\x1c\x0b\x0f\n\x0c\n\x05\x04\x05\x02\x01\x03\
-    \x12\x03\x1c\x12\x13\n\x0b\n\x04\x04\x05\x02\x02\x12\x03\x1d\x04\x15\n\
-    \x0c\n\x05\x04\x05\x02\x02\x05\x12\x03\x1d\x04\n\n\x0c\n\x05\x04\x05\x02\
-    \x02\x01\x12\x03\x1d\x0b\x10\n\x0c\n\x05\x04\x05\x02\x02\x03\x12\x03\x1d\
-    \x13\x14\n\x0b\n\x04\x04\x05\x02\x03\x12\x03\x1e\x04\x15\n\x0c\n\x05\x04\
-    \x05\x02\x03\x05\x12\x03\x1e\x04\n\n\x0c\n\x05\x04\x05\x02\x03\x01\x12\
-    \x03\x1e\x0b\x10\n\x0c\n\x05\x04\x05\x02\x03\x03\x12\x03\x1e\x13\x14\n\n\
-    \n\x02\x04\x06\x12\x04\x20\0\"\x01\n\n\n\x03\x04\x06\x01\x12\x03\x20\x08\
-    \x15\n\x0b\n\x04\x04\x06\x02\0\x12\x03!\x04\x15\n\x0c\n\x05\x04\x06\x02\
-    \0\x05\x12\x03!\x04\n\n\x0c\n\x05\x04\x06\x02\0\x01\x12\x03!\x0b\x10\n\
-    \x0c\n\x05\x04\x06\x02\0\x03\x12\x03!\x13\x14b\x06proto3\
+    \x20\x01(\tR\x05tokenJ\x80\t\n\x06\x12\x04\0\0\x1f\x01\n\x08\n\x01\x0c\
+    \x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\
+    \x01\x12\x03\x02\x08\x15\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\
+    \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
+    \x12\x03\x03\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\
+    \x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x18\n\x0c\n\x05\x04\0\x02\x01\
+    \x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x13\
+    \n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x16\x17\n\n\n\x02\x04\x01\x12\
+    \x04\x06\0\t\x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x14\n\x0b\n\x04\
+    \x04\x01\x02\0\x12\x03\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\
+    \x07\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\x10\n\x0c\n\x05\
+    \x04\x01\x02\0\x03\x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\x01\x12\
+    \x03\x08\x04\x18\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x08\x04\n\n\x0c\
+    \n\x05\x04\x01\x02\x01\x01\x12\x03\x08\x0b\x13\n\x0c\n\x05\x04\x01\x02\
+    \x01\x03\x12\x03\x08\x16\x17\n\n\n\x02\x04\x02\x12\x04\n\0\x0f\x01\n\n\n\
+    \x03\x04\x02\x01\x12\x03\n\x08\x16\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0b\
+    \x04\x13\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\
+    \x02\x02\0\x01\x12\x03\x0b\x0b\x0e\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\
+    \x0b\x11\x12\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0c\x04\x14\n\x0c\n\x05\
+    \x04\x02\x02\x01\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\
+    \x12\x03\x0c\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0c\x12\x13\
+    \n\x0b\n\x04\x04\x02\x02\x02\x12\x03\r\x04\x15\n\x0c\n\x05\x04\x02\x02\
+    \x02\x05\x12\x03\r\x04\n\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\r\x0b\
+    \x10\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\r\x13\x14\n\x0b\n\x04\x04\
+    \x02\x02\x03\x12\x03\x0e\x04\x15\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\x03\
+    \x0e\x04\n\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x0e\x0b\x10\n\x0c\n\
+    \x05\x04\x02\x02\x03\x03\x12\x03\x0e\x13\x14\n\n\n\x02\x04\x03\x12\x04\
+    \x10\0\x14\x01\n\n\n\x03\x04\x03\x01\x12\x03\x10\x08\x15\n\x0b\n\x04\x04\
+    \x03\x02\0\x12\x03\x11\x04\x15\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x11\
+    \x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x11\x0b\x10\n\x0c\n\x05\x04\
+    \x03\x02\0\x03\x12\x03\x11\x13\x14\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\
+    \x12\x04\x14\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x12\x04\n\n\x0c\n\
+    \x05\x04\x03\x02\x01\x01\x12\x03\x12\x0b\x0f\n\x0c\n\x05\x04\x03\x02\x01\
+    \x03\x12\x03\x12\x12\x13\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x13\x04\x18\
+    \n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x13\x04\n\n\x0c\n\x05\x04\x03\
+    \x02\x02\x01\x12\x03\x13\x0b\x13\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\
+    \x13\x16\x17\n\n\n\x02\x04\x04\x12\x04\x15\0\x19\x01\n\n\n\x03\x04\x04\
+    \x01\x12\x03\x15\x08\x14\n\x0b\n\x04\x04\x04\x02\0\x12\x03\x16\x04\x15\n\
+    \x0c\n\x05\x04\x04\x02\0\x05\x12\x03\x16\x04\n\n\x0c\n\x05\x04\x04\x02\0\
+    \x01\x12\x03\x16\x0b\x10\n\x0c\n\x05\x04\x04\x02\0\x03\x12\x03\x16\x13\
+    \x14\n\x0b\n\x04\x04\x04\x02\x01\x12\x03\x17\x04\x14\n\x0c\n\x05\x04\x04\
+    \x02\x01\x05\x12\x03\x17\x04\n\n\x0c\n\x05\x04\x04\x02\x01\x01\x12\x03\
+    \x17\x0b\x0f\n\x0c\n\x05\x04\x04\x02\x01\x03\x12\x03\x17\x12\x13\n\x0b\n\
+    \x04\x04\x04\x02\x02\x12\x03\x18\x04\x18\n\x0c\n\x05\x04\x04\x02\x02\x05\
+    \x12\x03\x18\x04\n\n\x0c\n\x05\x04\x04\x02\x02\x01\x12\x03\x18\x0b\x13\n\
+    \x0c\n\x05\x04\x04\x02\x02\x03\x12\x03\x18\x16\x17\n\n\n\x02\x04\x05\x12\
+    \x04\x1a\0\x1f\x01\n\n\n\x03\x04\x05\x01\x12\x03\x1a\x08\x16\n\x0b\n\x04\
+    \x04\x05\x02\0\x12\x03\x1b\x04\x13\n\x0c\n\x05\x04\x05\x02\0\x05\x12\x03\
+    \x1b\x04\n\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03\x1b\x0b\x0e\n\x0c\n\x05\
+    \x04\x05\x02\0\x03\x12\x03\x1b\x11\x12\n\x0b\n\x04\x04\x05\x02\x01\x12\
+    \x03\x1c\x04\x14\n\x0c\n\x05\x04\x05\x02\x01\x05\x12\x03\x1c\x04\n\n\x0c\
+    \n\x05\x04\x05\x02\x01\x01\x12\x03\x1c\x0b\x0f\n\x0c\n\x05\x04\x05\x02\
+    \x01\x03\x12\x03\x1c\x12\x13\n\x0b\n\x04\x04\x05\x02\x02\x12\x03\x1d\x04\
+    \x15\n\x0c\n\x05\x04\x05\x02\x02\x05\x12\x03\x1d\x04\n\n\x0c\n\x05\x04\
+    \x05\x02\x02\x01\x12\x03\x1d\x0b\x10\n\x0c\n\x05\x04\x05\x02\x02\x03\x12\
+    \x03\x1d\x13\x14\n\x0b\n\x04\x04\x05\x02\x03\x12\x03\x1e\x04\x15\n\x0c\n\
+    \x05\x04\x05\x02\x03\x05\x12\x03\x1e\x04\n\n\x0c\n\x05\x04\x05\x02\x03\
+    \x01\x12\x03\x1e\x0b\x10\n\x0c\n\x05\x04\x05\x02\x03\x03\x12\x03\x1e\x13\
+    \x14b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
diff --git a/rust-lib/flowy-user/src/protobuf/model/errors.rs b/rust-lib/flowy-user/src/protobuf/model/errors.rs
index a49ca7900b..45e2a66280 100644
--- a/rust-lib/flowy-user/src/protobuf/model/errors.rs
+++ b/rust-lib/flowy-user/src/protobuf/model/errors.rs
@@ -222,6 +222,7 @@ pub enum ErrorCode {
     UserDatabaseDidNotMatch = 4,
     UserDatabaseInternalError = 5,
     SqlInternalError = 6,
+    DatabaseConnectError = 7,
     UserNotLoginYet = 10,
     ReadCurrentIdFailed = 11,
     WriteCurrentIdFailed = 12,
@@ -256,6 +257,7 @@ impl ::protobuf::ProtobufEnum for ErrorCode {
             4 => ::std::option::Option::Some(ErrorCode::UserDatabaseDidNotMatch),
             5 => ::std::option::Option::Some(ErrorCode::UserDatabaseInternalError),
             6 => ::std::option::Option::Some(ErrorCode::SqlInternalError),
+            7 => ::std::option::Option::Some(ErrorCode::DatabaseConnectError),
             10 => ::std::option::Option::Some(ErrorCode::UserNotLoginYet),
             11 => ::std::option::Option::Some(ErrorCode::ReadCurrentIdFailed),
             12 => ::std::option::Option::Some(ErrorCode::WriteCurrentIdFailed),
@@ -287,6 +289,7 @@ impl ::protobuf::ProtobufEnum for ErrorCode {
             ErrorCode::UserDatabaseDidNotMatch,
             ErrorCode::UserDatabaseInternalError,
             ErrorCode::SqlInternalError,
+            ErrorCode::DatabaseConnectError,
             ErrorCode::UserNotLoginYet,
             ErrorCode::ReadCurrentIdFailed,
             ErrorCode::WriteCurrentIdFailed,
@@ -335,80 +338,82 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode {
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x0cerrors.proto\"=\n\tUserError\x12\x1e\n\x04code\x18\x01\x20\x01(\
     \x0e2\n.ErrorCodeR\x04code\x12\x10\n\x03msg\x18\x02\x20\x01(\tR\x03msg*\
-    \x89\x05\n\tErrorCode\x12\x0b\n\x07Unknown\x10\0\x12\x1a\n\x16UserDataba\
+    \xa3\x05\n\tErrorCode\x12\x0b\n\x07Unknown\x10\0\x12\x1a\n\x16UserDataba\
     seInitFailed\x10\x01\x12\x1b\n\x17UserDatabaseWriteLocked\x10\x02\x12\
     \x1a\n\x16UserDatabaseReadLocked\x10\x03\x12\x1b\n\x17UserDatabaseDidNot\
     Match\x10\x04\x12\x1d\n\x19UserDatabaseInternalError\x10\x05\x12\x14\n\
-    \x10SqlInternalError\x10\x06\x12\x13\n\x0fUserNotLoginYet\x10\n\x12\x17\
-    \n\x13ReadCurrentIdFailed\x10\x0b\x12\x18\n\x14WriteCurrentIdFailed\x10\
-    \x0c\x12\x10\n\x0cEmailIsEmpty\x10\x14\x12\x16\n\x12EmailFormatInvalid\
-    \x10\x15\x12\x16\n\x12EmailAlreadyExists\x10\x16\x12\x13\n\x0fPasswordIs\
-    Empty\x10\x1e\x12\x13\n\x0fPasswordTooLong\x10\x1f\x12$\n\x20PasswordCon\
-    tainsForbidCharacters\x10\x20\x12\x19\n\x15PasswordFormatInvalid\x10!\
-    \x12\x13\n\x0fUserNameTooLong\x10(\x12'\n#UserNameContainsForbiddenChara\
-    cters\x10)\x12\x13\n\x0fUserNameIsEmpty\x10*\x12\x18\n\x14UserWorkspaceI\
-    nvalid\x102\x12\x11\n\rUserIdInvalid\x103\x12\x20\n\x1cCreateDefaultWork\
-    spaceFailed\x104\x12\x20\n\x1cDefaultWorkspaceAlreadyExist\x105\x12\x0f\
-    \n\x0bServerError\x10dJ\xb1\t\n\x06\x12\x04\0\0\x20\x01\n\x08\n\x01\x0c\
-    \x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\
-    \x01\x12\x03\x02\x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\
-    \x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\r\n\x0c\n\x05\x04\0\x02\0\x01\
-    \x12\x03\x03\x0e\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\
-    \x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x13\n\x0c\n\x05\x04\0\x02\x01\
-    \x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0e\
-    \n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x11\x12\n\n\n\x02\x05\0\x12\
-    \x04\x06\0\x20\x01\n\n\n\x03\x05\0\x01\x12\x03\x06\x05\x0e\n\x0b\n\x04\
-    \x05\0\x02\0\x12\x03\x07\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x07\
-    \x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\x0e\x0f\n\x0b\n\x04\x05\
-    \0\x02\x01\x12\x03\x08\x04\x1f\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x08\
-    \x04\x1a\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x08\x1d\x1e\n\x0b\n\x04\
-    \x05\0\x02\x02\x12\x03\t\x04\x20\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\t\
-    \x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\t\x1e\x1f\n\x0b\n\x04\x05\
-    \0\x02\x03\x12\x03\n\x04\x1f\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\n\x04\
-    \x1a\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\n\x1d\x1e\n\x0b\n\x04\x05\0\
-    \x02\x04\x12\x03\x0b\x04\x20\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x0b\
-    \x04\x1b\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x0b\x1e\x1f\n\x0b\n\x04\
-    \x05\0\x02\x05\x12\x03\x0c\x04\"\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\
-    \x0c\x04\x1d\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x0c\x20!\n\x0b\n\x04\
-    \x05\0\x02\x06\x12\x03\r\x04\x19\n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\r\
-    \x04\x14\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\r\x17\x18\n\x0b\n\x04\x05\
-    \0\x02\x07\x12\x03\x0e\x04\x19\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\x0e\
-    \x04\x13\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\x0e\x16\x18\n\x0b\n\x04\
-    \x05\0\x02\x08\x12\x03\x0f\x04\x1d\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\
-    \x0f\x04\x17\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0f\x1a\x1c\n\x0b\n\
-    \x04\x05\0\x02\t\x12\x03\x10\x04\x1e\n\x0c\n\x05\x05\0\x02\t\x01\x12\x03\
-    \x10\x04\x18\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x10\x1b\x1d\n\x0b\n\x04\
-    \x05\0\x02\n\x12\x03\x11\x04\x16\n\x0c\n\x05\x05\0\x02\n\x01\x12\x03\x11\
-    \x04\x10\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\x11\x13\x15\n\x0b\n\x04\x05\
-    \0\x02\x0b\x12\x03\x12\x04\x1c\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\x12\
-    \x04\x16\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x12\x19\x1b\n\x0b\n\x04\
-    \x05\0\x02\x0c\x12\x03\x13\x04\x1c\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\x03\
-    \x13\x04\x16\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x13\x19\x1b\n\x0b\n\
-    \x04\x05\0\x02\r\x12\x03\x14\x04\x19\n\x0c\n\x05\x05\0\x02\r\x01\x12\x03\
-    \x14\x04\x13\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x14\x16\x18\n\x0b\n\x04\
-    \x05\0\x02\x0e\x12\x03\x15\x04\x19\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\x03\
-    \x15\x04\x13\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\x15\x16\x18\n\x0b\n\
-    \x04\x05\0\x02\x0f\x12\x03\x16\x04*\n\x0c\n\x05\x05\0\x02\x0f\x01\x12\
-    \x03\x16\x04$\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\x03\x16')\n\x0b\n\x04\
-    \x05\0\x02\x10\x12\x03\x17\x04\x1f\n\x0c\n\x05\x05\0\x02\x10\x01\x12\x03\
-    \x17\x04\x19\n\x0c\n\x05\x05\0\x02\x10\x02\x12\x03\x17\x1c\x1e\n\x0b\n\
-    \x04\x05\0\x02\x11\x12\x03\x18\x04\x19\n\x0c\n\x05\x05\0\x02\x11\x01\x12\
-    \x03\x18\x04\x13\n\x0c\n\x05\x05\0\x02\x11\x02\x12\x03\x18\x16\x18\n\x0b\
-    \n\x04\x05\0\x02\x12\x12\x03\x19\x04-\n\x0c\n\x05\x05\0\x02\x12\x01\x12\
-    \x03\x19\x04'\n\x0c\n\x05\x05\0\x02\x12\x02\x12\x03\x19*,\n\x0b\n\x04\
-    \x05\0\x02\x13\x12\x03\x1a\x04\x19\n\x0c\n\x05\x05\0\x02\x13\x01\x12\x03\
-    \x1a\x04\x13\n\x0c\n\x05\x05\0\x02\x13\x02\x12\x03\x1a\x16\x18\n\x0b\n\
-    \x04\x05\0\x02\x14\x12\x03\x1b\x04\x1e\n\x0c\n\x05\x05\0\x02\x14\x01\x12\
-    \x03\x1b\x04\x18\n\x0c\n\x05\x05\0\x02\x14\x02\x12\x03\x1b\x1b\x1d\n\x0b\
-    \n\x04\x05\0\x02\x15\x12\x03\x1c\x04\x17\n\x0c\n\x05\x05\0\x02\x15\x01\
-    \x12\x03\x1c\x04\x11\n\x0c\n\x05\x05\0\x02\x15\x02\x12\x03\x1c\x14\x16\n\
-    \x0b\n\x04\x05\0\x02\x16\x12\x03\x1d\x04&\n\x0c\n\x05\x05\0\x02\x16\x01\
-    \x12\x03\x1d\x04\x20\n\x0c\n\x05\x05\0\x02\x16\x02\x12\x03\x1d#%\n\x0b\n\
-    \x04\x05\0\x02\x17\x12\x03\x1e\x04&\n\x0c\n\x05\x05\0\x02\x17\x01\x12\
-    \x03\x1e\x04\x20\n\x0c\n\x05\x05\0\x02\x17\x02\x12\x03\x1e#%\n\x0b\n\x04\
-    \x05\0\x02\x18\x12\x03\x1f\x04\x16\n\x0c\n\x05\x05\0\x02\x18\x01\x12\x03\
-    \x1f\x04\x0f\n\x0c\n\x05\x05\0\x02\x18\x02\x12\x03\x1f\x12\x15b\x06proto\
-    3\
+    \x10SqlInternalError\x10\x06\x12\x18\n\x14DatabaseConnectError\x10\x07\
+    \x12\x13\n\x0fUserNotLoginYet\x10\n\x12\x17\n\x13ReadCurrentIdFailed\x10\
+    \x0b\x12\x18\n\x14WriteCurrentIdFailed\x10\x0c\x12\x10\n\x0cEmailIsEmpty\
+    \x10\x14\x12\x16\n\x12EmailFormatInvalid\x10\x15\x12\x16\n\x12EmailAlrea\
+    dyExists\x10\x16\x12\x13\n\x0fPasswordIsEmpty\x10\x1e\x12\x13\n\x0fPassw\
+    ordTooLong\x10\x1f\x12$\n\x20PasswordContainsForbidCharacters\x10\x20\
+    \x12\x19\n\x15PasswordFormatInvalid\x10!\x12\x13\n\x0fUserNameTooLong\
+    \x10(\x12'\n#UserNameContainsForbiddenCharacters\x10)\x12\x13\n\x0fUserN\
+    ameIsEmpty\x10*\x12\x18\n\x14UserWorkspaceInvalid\x102\x12\x11\n\rUserId\
+    Invalid\x103\x12\x20\n\x1cCreateDefaultWorkspaceFailed\x104\x12\x20\n\
+    \x1cDefaultWorkspaceAlreadyExist\x105\x12\x0f\n\x0bServerError\x10dJ\xda\
+    \t\n\x06\x12\x04\0\0!\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\
+    \0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x11\n\x0b\n\
+    \x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\
+    \x03\x04\r\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0e\x12\n\x0c\n\x05\
+    \x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\x0b\n\x04\x04\0\x02\x01\x12\x03\
+    \x04\x04\x13\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\
+    \x04\0\x02\x01\x01\x12\x03\x04\x0b\x0e\n\x0c\n\x05\x04\0\x02\x01\x03\x12\
+    \x03\x04\x11\x12\n\n\n\x02\x05\0\x12\x04\x06\0!\x01\n\n\n\x03\x05\0\x01\
+    \x12\x03\x06\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x07\x04\x10\n\x0c\n\
+    \x05\x05\0\x02\0\x01\x12\x03\x07\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\
+    \x03\x07\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x08\x04\x1f\n\x0c\n\
+    \x05\x05\0\x02\x01\x01\x12\x03\x08\x04\x1a\n\x0c\n\x05\x05\0\x02\x01\x02\
+    \x12\x03\x08\x1d\x1e\n\x0b\n\x04\x05\0\x02\x02\x12\x03\t\x04\x20\n\x0c\n\
+    \x05\x05\0\x02\x02\x01\x12\x03\t\x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x02\
+    \x12\x03\t\x1e\x1f\n\x0b\n\x04\x05\0\x02\x03\x12\x03\n\x04\x1f\n\x0c\n\
+    \x05\x05\0\x02\x03\x01\x12\x03\n\x04\x1a\n\x0c\n\x05\x05\0\x02\x03\x02\
+    \x12\x03\n\x1d\x1e\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x0b\x04\x20\n\x0c\n\
+    \x05\x05\0\x02\x04\x01\x12\x03\x0b\x04\x1b\n\x0c\n\x05\x05\0\x02\x04\x02\
+    \x12\x03\x0b\x1e\x1f\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x0c\x04\"\n\x0c\n\
+    \x05\x05\0\x02\x05\x01\x12\x03\x0c\x04\x1d\n\x0c\n\x05\x05\0\x02\x05\x02\
+    \x12\x03\x0c\x20!\n\x0b\n\x04\x05\0\x02\x06\x12\x03\r\x04\x19\n\x0c\n\
+    \x05\x05\0\x02\x06\x01\x12\x03\r\x04\x14\n\x0c\n\x05\x05\0\x02\x06\x02\
+    \x12\x03\r\x17\x18\n\x0b\n\x04\x05\0\x02\x07\x12\x03\x0e\x04\x1d\n\x0c\n\
+    \x05\x05\0\x02\x07\x01\x12\x03\x0e\x04\x18\n\x0c\n\x05\x05\0\x02\x07\x02\
+    \x12\x03\x0e\x1b\x1c\n\x0b\n\x04\x05\0\x02\x08\x12\x03\x0f\x04\x19\n\x0c\
+    \n\x05\x05\0\x02\x08\x01\x12\x03\x0f\x04\x13\n\x0c\n\x05\x05\0\x02\x08\
+    \x02\x12\x03\x0f\x16\x18\n\x0b\n\x04\x05\0\x02\t\x12\x03\x10\x04\x1d\n\
+    \x0c\n\x05\x05\0\x02\t\x01\x12\x03\x10\x04\x17\n\x0c\n\x05\x05\0\x02\t\
+    \x02\x12\x03\x10\x1a\x1c\n\x0b\n\x04\x05\0\x02\n\x12\x03\x11\x04\x1e\n\
+    \x0c\n\x05\x05\0\x02\n\x01\x12\x03\x11\x04\x18\n\x0c\n\x05\x05\0\x02\n\
+    \x02\x12\x03\x11\x1b\x1d\n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x12\x04\x16\n\
+    \x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\x12\x04\x10\n\x0c\n\x05\x05\0\x02\
+    \x0b\x02\x12\x03\x12\x13\x15\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x13\x04\
+    \x1c\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\x03\x13\x04\x16\n\x0c\n\x05\x05\0\
+    \x02\x0c\x02\x12\x03\x13\x19\x1b\n\x0b\n\x04\x05\0\x02\r\x12\x03\x14\x04\
+    \x1c\n\x0c\n\x05\x05\0\x02\r\x01\x12\x03\x14\x04\x16\n\x0c\n\x05\x05\0\
+    \x02\r\x02\x12\x03\x14\x19\x1b\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\x15\x04\
+    \x19\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\x03\x15\x04\x13\n\x0c\n\x05\x05\0\
+    \x02\x0e\x02\x12\x03\x15\x16\x18\n\x0b\n\x04\x05\0\x02\x0f\x12\x03\x16\
+    \x04\x19\n\x0c\n\x05\x05\0\x02\x0f\x01\x12\x03\x16\x04\x13\n\x0c\n\x05\
+    \x05\0\x02\x0f\x02\x12\x03\x16\x16\x18\n\x0b\n\x04\x05\0\x02\x10\x12\x03\
+    \x17\x04*\n\x0c\n\x05\x05\0\x02\x10\x01\x12\x03\x17\x04$\n\x0c\n\x05\x05\
+    \0\x02\x10\x02\x12\x03\x17')\n\x0b\n\x04\x05\0\x02\x11\x12\x03\x18\x04\
+    \x1f\n\x0c\n\x05\x05\0\x02\x11\x01\x12\x03\x18\x04\x19\n\x0c\n\x05\x05\0\
+    \x02\x11\x02\x12\x03\x18\x1c\x1e\n\x0b\n\x04\x05\0\x02\x12\x12\x03\x19\
+    \x04\x19\n\x0c\n\x05\x05\0\x02\x12\x01\x12\x03\x19\x04\x13\n\x0c\n\x05\
+    \x05\0\x02\x12\x02\x12\x03\x19\x16\x18\n\x0b\n\x04\x05\0\x02\x13\x12\x03\
+    \x1a\x04-\n\x0c\n\x05\x05\0\x02\x13\x01\x12\x03\x1a\x04'\n\x0c\n\x05\x05\
+    \0\x02\x13\x02\x12\x03\x1a*,\n\x0b\n\x04\x05\0\x02\x14\x12\x03\x1b\x04\
+    \x19\n\x0c\n\x05\x05\0\x02\x14\x01\x12\x03\x1b\x04\x13\n\x0c\n\x05\x05\0\
+    \x02\x14\x02\x12\x03\x1b\x16\x18\n\x0b\n\x04\x05\0\x02\x15\x12\x03\x1c\
+    \x04\x1e\n\x0c\n\x05\x05\0\x02\x15\x01\x12\x03\x1c\x04\x18\n\x0c\n\x05\
+    \x05\0\x02\x15\x02\x12\x03\x1c\x1b\x1d\n\x0b\n\x04\x05\0\x02\x16\x12\x03\
+    \x1d\x04\x17\n\x0c\n\x05\x05\0\x02\x16\x01\x12\x03\x1d\x04\x11\n\x0c\n\
+    \x05\x05\0\x02\x16\x02\x12\x03\x1d\x14\x16\n\x0b\n\x04\x05\0\x02\x17\x12\
+    \x03\x1e\x04&\n\x0c\n\x05\x05\0\x02\x17\x01\x12\x03\x1e\x04\x20\n\x0c\n\
+    \x05\x05\0\x02\x17\x02\x12\x03\x1e#%\n\x0b\n\x04\x05\0\x02\x18\x12\x03\
+    \x1f\x04&\n\x0c\n\x05\x05\0\x02\x18\x01\x12\x03\x1f\x04\x20\n\x0c\n\x05\
+    \x05\0\x02\x18\x02\x12\x03\x1f#%\n\x0b\n\x04\x05\0\x02\x19\x12\x03\x20\
+    \x04\x16\n\x0c\n\x05\x05\0\x02\x19\x01\x12\x03\x20\x04\x0f\n\x0c\n\x05\
+    \x05\0\x02\x19\x02\x12\x03\x20\x12\x15b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
diff --git a/rust-lib/flowy-user/src/protobuf/model/event.rs b/rust-lib/flowy-user/src/protobuf/model/event.rs
index f22923026e..32e93ad8f5 100644
--- a/rust-lib/flowy-user/src/protobuf/model/event.rs
+++ b/rust-lib/flowy-user/src/protobuf/model/event.rs
@@ -25,7 +25,7 @@
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
 pub enum UserEvent {
-    GetStatus = 0,
+    GetUserProfile = 0,
     SignIn = 1,
     SignUp = 2,
     SignOut = 3,
@@ -39,7 +39,7 @@ impl ::protobuf::ProtobufEnum for UserEvent {
 
     fn from_i32(value: i32) -> ::std::option::Option<UserEvent> {
         match value {
-            0 => ::std::option::Option::Some(UserEvent::GetStatus),
+            0 => ::std::option::Option::Some(UserEvent::GetUserProfile),
             1 => ::std::option::Option::Some(UserEvent::SignIn),
             2 => ::std::option::Option::Some(UserEvent::SignUp),
             3 => ::std::option::Option::Some(UserEvent::SignOut),
@@ -50,7 +50,7 @@ impl ::protobuf::ProtobufEnum for UserEvent {
 
     fn values() -> &'static [Self] {
         static values: &'static [UserEvent] = &[
-            UserEvent::GetStatus,
+            UserEvent::GetUserProfile,
             UserEvent::SignIn,
             UserEvent::SignUp,
             UserEvent::SignOut,
@@ -72,7 +72,7 @@ impl ::std::marker::Copy for UserEvent {
 
 impl ::std::default::Default for UserEvent {
     fn default() -> Self {
-        UserEvent::GetStatus
+        UserEvent::GetUserProfile
     }
 }
 
@@ -83,21 +83,21 @@ impl ::protobuf::reflect::ProtobufValue for UserEvent {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0bevent.proto*O\n\tUserEvent\x12\r\n\tGetStatus\x10\0\x12\n\n\x06Sig\
-    nIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOut\x10\x03\x12\
-    \x0e\n\nUpdateUser\x10\x04J\xf7\x01\n\x06\x12\x04\0\0\x08\x01\n\x08\n\
-    \x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x08\x01\n\n\n\x03\
-    \x05\0\x01\x12\x03\x02\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\
-    \x12\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\r\n\x0c\n\x05\x05\0\x02\
-    \0\x02\x12\x03\x03\x10\x11\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x0f\
-    \n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\n\n\x0c\n\x05\x05\0\x02\
-    \x01\x02\x12\x03\x04\r\x0e\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x0f\
-    \n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\n\n\x0c\n\x05\x05\0\x02\
-    \x02\x02\x12\x03\x05\r\x0e\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x10\
-    \n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x0b\n\x0c\n\x05\x05\0\x02\
-    \x03\x02\x12\x03\x06\x0e\x0f\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\
-    \x13\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x0e\n\x0c\n\x05\x05\0\
-    \x02\x04\x02\x12\x03\x07\x11\x12b\x06proto3\
+    \n\x0bevent.proto*T\n\tUserEvent\x12\x12\n\x0eGetUserProfile\x10\0\x12\n\
+    \n\x06SignIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOut\x10\
+    \x03\x12\x0e\n\nUpdateUser\x10\x04J\xf7\x01\n\x06\x12\x04\0\0\x08\x01\n\
+    \x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x08\x01\n\n\
+    \n\x03\x05\0\x01\x12\x03\x02\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\
+    \x04\x17\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\x12\n\x0c\n\x05\x05\
+    \0\x02\0\x02\x12\x03\x03\x15\x16\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\
+    \x04\x0f\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\n\n\x0c\n\x05\x05\
+    \0\x02\x01\x02\x12\x03\x04\r\x0e\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\
+    \x04\x0f\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\n\n\x0c\n\x05\x05\
+    \0\x02\x02\x02\x12\x03\x05\r\x0e\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\
+    \x04\x10\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x0b\n\x0c\n\x05\
+    \x05\0\x02\x03\x02\x12\x03\x06\x0e\x0f\n\x0b\n\x04\x05\0\x02\x04\x12\x03\
+    \x07\x04\x13\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x0e\n\x0c\n\
+    \x05\x05\0\x02\x04\x02\x12\x03\x07\x11\x12b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
diff --git a/rust-lib/flowy-user/src/protobuf/model/user_detail.rs b/rust-lib/flowy-user/src/protobuf/model/user_detail.rs
index 7ad6d40765..e11979954f 100644
--- a/rust-lib/flowy-user/src/protobuf/model/user_detail.rs
+++ b/rust-lib/flowy-user/src/protobuf/model/user_detail.rs
@@ -24,7 +24,7 @@
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
 #[derive(PartialEq,Clone,Default)]
-pub struct QueryUserDetailParams {
+pub struct UserToken {
     // message fields
     pub token: ::std::string::String,
     // special fields
@@ -32,14 +32,14 @@ pub struct QueryUserDetailParams {
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a QueryUserDetailParams {
-    fn default() -> &'a QueryUserDetailParams {
-        <QueryUserDetailParams as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a UserToken {
+    fn default() -> &'a UserToken {
+        <UserToken as ::protobuf::Message>::default_instance()
     }
 }
 
-impl QueryUserDetailParams {
-    pub fn new() -> QueryUserDetailParams {
+impl UserToken {
+    pub fn new() -> UserToken {
         ::std::default::Default::default()
     }
 
@@ -70,7 +70,7 @@ impl QueryUserDetailParams {
     }
 }
 
-impl ::protobuf::Message for QueryUserDetailParams {
+impl ::protobuf::Message for UserToken {
     fn is_initialized(&self) -> bool {
         true
     }
@@ -136,8 +136,8 @@ impl ::protobuf::Message for QueryUserDetailParams {
         Self::descriptor_static()
     }
 
-    fn new() -> QueryUserDetailParams {
-        QueryUserDetailParams::new()
+    fn new() -> UserToken {
+        UserToken::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -146,37 +146,37 @@ impl ::protobuf::Message for QueryUserDetailParams {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "token",
-                |m: &QueryUserDetailParams| { &m.token },
-                |m: &mut QueryUserDetailParams| { &mut m.token },
+                |m: &UserToken| { &m.token },
+                |m: &mut UserToken| { &mut m.token },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryUserDetailParams>(
-                "QueryUserDetailParams",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<UserToken>(
+                "UserToken",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static QueryUserDetailParams {
-        static instance: ::protobuf::rt::LazyV2<QueryUserDetailParams> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(QueryUserDetailParams::new)
+    fn default_instance() -> &'static UserToken {
+        static instance: ::protobuf::rt::LazyV2<UserToken> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(UserToken::new)
     }
 }
 
-impl ::protobuf::Clear for QueryUserDetailParams {
+impl ::protobuf::Clear for UserToken {
     fn clear(&mut self) {
         self.token.clear();
         self.unknown_fields.clear();
     }
 }
 
-impl ::std::fmt::Debug for QueryUserDetailParams {
+impl ::std::fmt::Debug for UserToken {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for QueryUserDetailParams {
+impl ::protobuf::reflect::ProtobufValue for UserToken {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -1327,77 +1327,76 @@ impl ::protobuf::reflect::ProtobufValue for UserStatus {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x11user_detail.proto\"-\n\x15QueryUserDetailParams\x12\x14\n\x05token\
-    \x18\x01\x20\x01(\tR\x05token\"\\\n\nUserDetail\x12\x0e\n\x02id\x18\x01\
-    \x20\x01(\tR\x02id\x12\x14\n\x05email\x18\x02\x20\x01(\tR\x05email\x12\
-    \x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x14\n\x05token\x18\x04\
-    \x20\x01(\tR\x05token\"\xa1\x01\n\x11UpdateUserRequest\x12\x0e\n\x02id\
-    \x18\x01\x20\x01(\tR\x02id\x12\x14\n\x04name\x18\x02\x20\x01(\tH\0R\x04n\
-    ame\x12\x16\n\x05email\x18\x03\x20\x01(\tH\x01R\x05email\x12\x1c\n\x08pa\
-    ssword\x18\x04\x20\x01(\tH\x02R\x08passwordB\r\n\x0bone_of_nameB\x0e\n\
-    \x0cone_of_emailB\x11\n\x0fone_of_password\"\xa0\x01\n\x10UpdateUserPara\
-    ms\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x14\n\x04name\x18\x02\
-    \x20\x01(\tH\0R\x04name\x12\x16\n\x05email\x18\x03\x20\x01(\tH\x01R\x05e\
-    mail\x12\x1c\n\x08password\x18\x04\x20\x01(\tH\x02R\x08passwordB\r\n\x0b\
-    one_of_nameB\x0e\n\x0cone_of_emailB\x11\n\x0fone_of_password*1\n\nUserSt\
-    atus\x12\x0b\n\x07Unknown\x10\0\x12\t\n\x05Login\x10\x01\x12\x0b\n\x07Ex\
-    pired\x10\x02J\xf2\x08\n\x06\x12\x04\0\0\x1b\x01\n\x08\n\x01\x0c\x12\x03\
-    \0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x04\0\x01\x12\
-    \x03\x02\x08\x1d\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\x0c\n\x05\
-    \x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\
-    \x03\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\n\n\x02\
-    \x04\x01\x12\x04\x05\0\n\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\x12\n\
-    \x0b\n\x04\x04\x01\x02\0\x12\x03\x06\x04\x12\n\x0c\n\x05\x04\x01\x02\0\
-    \x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\x0b\r\n\
-    \x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x06\x10\x11\n\x0b\n\x04\x04\x01\x02\
-    \x01\x12\x03\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x07\x04\
-    \n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x07\x0b\x10\n\x0c\n\x05\x04\
-    \x01\x02\x01\x03\x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\
-    \x08\x04\x14\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x08\x04\n\n\x0c\n\
-    \x05\x04\x01\x02\x02\x01\x12\x03\x08\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x02\
-    \x03\x12\x03\x08\x12\x13\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\t\x04\x15\n\
-    \x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\x02\
-    \x03\x01\x12\x03\t\x0b\x10\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\t\x13\
-    \x14\n\n\n\x02\x04\x02\x12\x04\x0b\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\
-    \x03\x0b\x08\x19\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0c\x04\x12\n\x0c\n\
-    \x05\x04\x02\x02\0\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\
-    \x12\x03\x0c\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0c\x10\x11\n\
-    \x0b\n\x04\x04\x02\x08\0\x12\x03\r\x04*\n\x0c\n\x05\x04\x02\x08\0\x01\
-    \x12\x03\r\n\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\r\x18(\n\x0c\n\x05\
-    \x04\x02\x02\x01\x05\x12\x03\r\x18\x1e\n\x0c\n\x05\x04\x02\x02\x01\x01\
-    \x12\x03\r\x1f#\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\r&'\n\x0b\n\x04\
-    \x04\x02\x08\x01\x12\x03\x0e\x04,\n\x0c\n\x05\x04\x02\x08\x01\x01\x12\
-    \x03\x0e\n\x16\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x0e\x19*\n\x0c\n\x05\
-    \x04\x02\x02\x02\x05\x12\x03\x0e\x19\x1f\n\x0c\n\x05\x04\x02\x02\x02\x01\
-    \x12\x03\x0e\x20%\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x0e()\n\x0b\n\
-    \x04\x04\x02\x08\x02\x12\x03\x0f\x042\n\x0c\n\x05\x04\x02\x08\x02\x01\
-    \x12\x03\x0f\n\x19\n\x0b\n\x04\x04\x02\x02\x03\x12\x03\x0f\x1c0\n\x0c\n\
-    \x05\x04\x02\x02\x03\x05\x12\x03\x0f\x1c\"\n\x0c\n\x05\x04\x02\x02\x03\
-    \x01\x12\x03\x0f#+\n\x0c\n\x05\x04\x02\x02\x03\x03\x12\x03\x0f./\n\n\n\
-    \x02\x04\x03\x12\x04\x11\0\x16\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\
-    \x18\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x12\x04\x12\n\x0c\n\x05\x04\x03\
-    \x02\0\x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\
-    \x0b\r\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x12\x10\x11\n\x0b\n\x04\x04\
-    \x03\x08\0\x12\x03\x13\x04*\n\x0c\n\x05\x04\x03\x08\0\x01\x12\x03\x13\n\
-    \x15\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\x13\x18(\n\x0c\n\x05\x04\x03\
-    \x02\x01\x05\x12\x03\x13\x18\x1e\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\
-    \x13\x1f#\n\x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\x13&'\n\x0b\n\x04\x04\
-    \x03\x08\x01\x12\x03\x14\x04,\n\x0c\n\x05\x04\x03\x08\x01\x01\x12\x03\
-    \x14\n\x16\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x14\x19*\n\x0c\n\x05\x04\
-    \x03\x02\x02\x05\x12\x03\x14\x19\x1f\n\x0c\n\x05\x04\x03\x02\x02\x01\x12\
-    \x03\x14\x20%\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\x14()\n\x0b\n\x04\
-    \x04\x03\x08\x02\x12\x03\x15\x042\n\x0c\n\x05\x04\x03\x08\x02\x01\x12\
-    \x03\x15\n\x19\n\x0b\n\x04\x04\x03\x02\x03\x12\x03\x15\x1c0\n\x0c\n\x05\
-    \x04\x03\x02\x03\x05\x12\x03\x15\x1c\"\n\x0c\n\x05\x04\x03\x02\x03\x01\
-    \x12\x03\x15#+\n\x0c\n\x05\x04\x03\x02\x03\x03\x12\x03\x15./\n\n\n\x02\
-    \x05\0\x12\x04\x17\0\x1b\x01\n\n\n\x03\x05\0\x01\x12\x03\x17\x05\x0f\n\
-    \x0b\n\x04\x05\0\x02\0\x12\x03\x18\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\
-    \x12\x03\x18\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x18\x0e\x0f\n\
-    \x0b\n\x04\x05\0\x02\x01\x12\x03\x19\x04\x0e\n\x0c\n\x05\x05\0\x02\x01\
-    \x01\x12\x03\x19\x04\t\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x19\x0c\r\n\
-    \x0b\n\x04\x05\0\x02\x02\x12\x03\x1a\x04\x10\n\x0c\n\x05\x05\0\x02\x02\
-    \x01\x12\x03\x1a\x04\x0b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x1a\x0e\
-    \x0fb\x06proto3\
+    \n\x11user_detail.proto\"!\n\tUserToken\x12\x14\n\x05token\x18\x01\x20\
+    \x01(\tR\x05token\"\\\n\nUserDetail\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\
+    \x02id\x12\x14\n\x05email\x18\x02\x20\x01(\tR\x05email\x12\x12\n\x04name\
+    \x18\x03\x20\x01(\tR\x04name\x12\x14\n\x05token\x18\x04\x20\x01(\tR\x05t\
+    oken\"\xa1\x01\n\x11UpdateUserRequest\x12\x0e\n\x02id\x18\x01\x20\x01(\t\
+    R\x02id\x12\x14\n\x04name\x18\x02\x20\x01(\tH\0R\x04name\x12\x16\n\x05em\
+    ail\x18\x03\x20\x01(\tH\x01R\x05email\x12\x1c\n\x08password\x18\x04\x20\
+    \x01(\tH\x02R\x08passwordB\r\n\x0bone_of_nameB\x0e\n\x0cone_of_emailB\
+    \x11\n\x0fone_of_password\"\xa0\x01\n\x10UpdateUserParams\x12\x0e\n\x02i\
+    d\x18\x01\x20\x01(\tR\x02id\x12\x14\n\x04name\x18\x02\x20\x01(\tH\0R\x04\
+    name\x12\x16\n\x05email\x18\x03\x20\x01(\tH\x01R\x05email\x12\x1c\n\x08p\
+    assword\x18\x04\x20\x01(\tH\x02R\x08passwordB\r\n\x0bone_of_nameB\x0e\n\
+    \x0cone_of_emailB\x11\n\x0fone_of_password*1\n\nUserStatus\x12\x0b\n\x07\
+    Unknown\x10\0\x12\t\n\x05Login\x10\x01\x12\x0b\n\x07Expired\x10\x02J\xf2\
+    \x08\n\x06\x12\x04\0\0\x1b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
+    \x04\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x11\n\
+    \x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\x0c\n\x05\x04\0\x02\0\x05\
+    \x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x10\n\x0c\
+    \n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\n\n\x02\x04\x01\x12\x04\x05\
+    \0\n\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\x12\n\x0b\n\x04\x04\x01\
+    \x02\0\x12\x03\x06\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x06\x04\
+    \n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\x0b\r\n\x0c\n\x05\x04\x01\
+    \x02\0\x03\x12\x03\x06\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x07\
+    \x04\x15\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x07\x04\n\n\x0c\n\x05\
+    \x04\x01\x02\x01\x01\x12\x03\x07\x0b\x10\n\x0c\n\x05\x04\x01\x02\x01\x03\
+    \x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x08\x04\x14\n\
+    \x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x08\x04\n\n\x0c\n\x05\x04\x01\x02\
+    \x02\x01\x12\x03\x08\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x08\
+    \x12\x13\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\t\x04\x15\n\x0c\n\x05\x04\
+    \x01\x02\x03\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\
+    \t\x0b\x10\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\t\x13\x14\n\n\n\x02\
+    \x04\x02\x12\x04\x0b\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0b\x08\x19\
+    \n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0c\x04\x12\n\x0c\n\x05\x04\x02\x02\0\
+    \x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0c\x0b\r\n\
+    \x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0c\x10\x11\n\x0b\n\x04\x04\x02\x08\
+    \0\x12\x03\r\x04*\n\x0c\n\x05\x04\x02\x08\0\x01\x12\x03\r\n\x15\n\x0b\n\
+    \x04\x04\x02\x02\x01\x12\x03\r\x18(\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\
+    \x03\r\x18\x1e\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\r\x1f#\n\x0c\n\
+    \x05\x04\x02\x02\x01\x03\x12\x03\r&'\n\x0b\n\x04\x04\x02\x08\x01\x12\x03\
+    \x0e\x04,\n\x0c\n\x05\x04\x02\x08\x01\x01\x12\x03\x0e\n\x16\n\x0b\n\x04\
+    \x04\x02\x02\x02\x12\x03\x0e\x19*\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\
+    \x03\x0e\x19\x1f\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x0e\x20%\n\x0c\
+    \n\x05\x04\x02\x02\x02\x03\x12\x03\x0e()\n\x0b\n\x04\x04\x02\x08\x02\x12\
+    \x03\x0f\x042\n\x0c\n\x05\x04\x02\x08\x02\x01\x12\x03\x0f\n\x19\n\x0b\n\
+    \x04\x04\x02\x02\x03\x12\x03\x0f\x1c0\n\x0c\n\x05\x04\x02\x02\x03\x05\
+    \x12\x03\x0f\x1c\"\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x0f#+\n\x0c\n\
+    \x05\x04\x02\x02\x03\x03\x12\x03\x0f./\n\n\n\x02\x04\x03\x12\x04\x11\0\
+    \x16\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\x18\n\x0b\n\x04\x04\x03\
+    \x02\0\x12\x03\x12\x04\x12\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x12\x04\
+    \n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\x0b\r\n\x0c\n\x05\x04\x03\
+    \x02\0\x03\x12\x03\x12\x10\x11\n\x0b\n\x04\x04\x03\x08\0\x12\x03\x13\x04\
+    *\n\x0c\n\x05\x04\x03\x08\0\x01\x12\x03\x13\n\x15\n\x0b\n\x04\x04\x03\
+    \x02\x01\x12\x03\x13\x18(\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x13\
+    \x18\x1e\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x13\x1f#\n\x0c\n\x05\
+    \x04\x03\x02\x01\x03\x12\x03\x13&'\n\x0b\n\x04\x04\x03\x08\x01\x12\x03\
+    \x14\x04,\n\x0c\n\x05\x04\x03\x08\x01\x01\x12\x03\x14\n\x16\n\x0b\n\x04\
+    \x04\x03\x02\x02\x12\x03\x14\x19*\n\x0c\n\x05\x04\x03\x02\x02\x05\x12\
+    \x03\x14\x19\x1f\n\x0c\n\x05\x04\x03\x02\x02\x01\x12\x03\x14\x20%\n\x0c\
+    \n\x05\x04\x03\x02\x02\x03\x12\x03\x14()\n\x0b\n\x04\x04\x03\x08\x02\x12\
+    \x03\x15\x042\n\x0c\n\x05\x04\x03\x08\x02\x01\x12\x03\x15\n\x19\n\x0b\n\
+    \x04\x04\x03\x02\x03\x12\x03\x15\x1c0\n\x0c\n\x05\x04\x03\x02\x03\x05\
+    \x12\x03\x15\x1c\"\n\x0c\n\x05\x04\x03\x02\x03\x01\x12\x03\x15#+\n\x0c\n\
+    \x05\x04\x03\x02\x03\x03\x12\x03\x15./\n\n\n\x02\x05\0\x12\x04\x17\0\x1b\
+    \x01\n\n\n\x03\x05\0\x01\x12\x03\x17\x05\x0f\n\x0b\n\x04\x05\0\x02\0\x12\
+    \x03\x18\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x18\x04\x0b\n\x0c\n\
+    \x05\x05\0\x02\0\x02\x12\x03\x18\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\
+    \x03\x19\x04\x0e\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x19\x04\t\n\x0c\n\
+    \x05\x05\0\x02\x01\x02\x12\x03\x19\x0c\r\n\x0b\n\x04\x05\0\x02\x02\x12\
+    \x03\x1a\x04\x10\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x1a\x04\x0b\n\x0c\
+    \n\x05\x05\0\x02\x02\x02\x12\x03\x1a\x0e\x0fb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
diff --git a/rust-lib/flowy-user/src/protobuf/proto/auth.proto b/rust-lib/flowy-user/src/protobuf/proto/auth.proto
index 1bc9537d50..cd73cbed1d 100644
--- a/rust-lib/flowy-user/src/protobuf/proto/auth.proto
+++ b/rust-lib/flowy-user/src/protobuf/proto/auth.proto
@@ -30,6 +30,3 @@ message SignUpResponse {
     string email = 3;
     string token = 4;
 }
-message SignOutParams {
-    string token = 1;
-}
diff --git a/rust-lib/flowy-user/src/protobuf/proto/errors.proto b/rust-lib/flowy-user/src/protobuf/proto/errors.proto
index 34d6f5f14e..f286b178dd 100644
--- a/rust-lib/flowy-user/src/protobuf/proto/errors.proto
+++ b/rust-lib/flowy-user/src/protobuf/proto/errors.proto
@@ -12,6 +12,7 @@ enum ErrorCode {
     UserDatabaseDidNotMatch = 4;
     UserDatabaseInternalError = 5;
     SqlInternalError = 6;
+    DatabaseConnectError = 7;
     UserNotLoginYet = 10;
     ReadCurrentIdFailed = 11;
     WriteCurrentIdFailed = 12;
diff --git a/rust-lib/flowy-user/src/protobuf/proto/event.proto b/rust-lib/flowy-user/src/protobuf/proto/event.proto
index 21a6f65d7c..96ec640e3e 100644
--- a/rust-lib/flowy-user/src/protobuf/proto/event.proto
+++ b/rust-lib/flowy-user/src/protobuf/proto/event.proto
@@ -1,7 +1,7 @@
 syntax = "proto3";
 
 enum UserEvent {
-    GetStatus = 0;
+    GetUserProfile = 0;
     SignIn = 1;
     SignUp = 2;
     SignOut = 3;
diff --git a/rust-lib/flowy-user/src/protobuf/proto/user_detail.proto b/rust-lib/flowy-user/src/protobuf/proto/user_detail.proto
index 99041159ac..b32ca2c693 100644
--- a/rust-lib/flowy-user/src/protobuf/proto/user_detail.proto
+++ b/rust-lib/flowy-user/src/protobuf/proto/user_detail.proto
@@ -1,6 +1,6 @@
 syntax = "proto3";
 
-message QueryUserDetailParams {
+message UserToken {
     string token = 1;
 }
 message UserDetail {
diff --git a/rust-lib/flowy-user/src/services/mod.rs b/rust-lib/flowy-user/src/services/mod.rs
index bbc7890d9b..c984864809 100644
--- a/rust-lib/flowy-user/src/services/mod.rs
+++ b/rust-lib/flowy-user/src/services/mod.rs
@@ -1,2 +1,2 @@
+mod server;
 pub mod user;
-pub mod workspace;
diff --git a/rust-lib/flowy-user/src/services/server/mod.rs b/rust-lib/flowy-user/src/services/server/mod.rs
new file mode 100644
index 0000000000..e62aaf6f2d
--- /dev/null
+++ b/rust-lib/flowy-user/src/services/server/mod.rs
@@ -0,0 +1,13 @@
+mod server_api;
+mod server_api_mock;
+pub use server_api::*;
+pub use server_api_mock::*;
+
+use std::sync::Arc;
+pub(crate) fn construct_user_server() -> Arc<dyn UserServerAPI + Send + Sync> {
+    if cfg!(feature = "http_server") {
+        Arc::new(UserServer {})
+    } else {
+        Arc::new(UserServerMock {})
+    }
+}
diff --git a/rust-lib/flowy-user/src/services/user/user_server/server_api.rs b/rust-lib/flowy-user/src/services/server/server_api.rs
similarity index 66%
rename from rust-lib/flowy-user/src/services/user/user_server/server_api.rs
rename to rust-lib/flowy-user/src/services/server/server_api.rs
index ebfb39082b..87d0026b64 100644
--- a/rust-lib/flowy-user/src/services/user/user_server/server_api.rs
+++ b/rust-lib/flowy-user/src/services/server/server_api.rs
@@ -3,14 +3,15 @@ use crate::{
     errors::{ErrorBuilder, ErrorCode, UserError},
 };
 
-use crate::entities::{QueryUserDetailParams, SignOutParams};
-use flowy_net::{config::*, future::ResultFuture, request::HttpRequestBuilder};
+use crate::entities::UserToken;
+use flowy_infra::future::ResultFuture;
+use flowy_net::{config::*, request::HttpRequestBuilder};
 
 pub trait UserServerAPI {
     fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError>;
     fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError>;
     fn sign_out(&self, token: &str) -> ResultFuture<(), UserError>;
-    fn get_user_info(&self, user_id: &str) -> ResultFuture<UserDetail, UserError>;
+    fn get_user_detail(&self, token: &str) -> ResultFuture<UserDetail, UserError>;
 }
 
 pub struct UserServer {}
@@ -27,12 +28,21 @@ impl UserServerAPI for UserServer {
         ResultFuture::new(async move { user_sign_in(params, SIGN_IN_URL.as_ref()).await })
     }
 
-    fn sign_out(&self, _token: &str) -> ResultFuture<(), UserError> {
-        ResultFuture::new(async { Err(ErrorBuilder::new(ErrorCode::Unknown).build()) })
+    fn sign_out(&self, token: &str) -> ResultFuture<(), UserError> {
+        let params = UserToken {
+            token: token.to_string(),
+        };
+        ResultFuture::new(async move {
+            let _ = user_sign_out(params, SIGN_OUT_URL.as_ref()).await;
+            Ok(())
+        })
     }
 
-    fn get_user_info(&self, _user_id: &str) -> ResultFuture<UserDetail, UserError> {
-        ResultFuture::new(async { Err(ErrorBuilder::new(ErrorCode::Unknown).build()) })
+    fn get_user_detail(&self, token: &str) -> ResultFuture<UserDetail, UserError> {
+        let params = UserToken {
+            token: token.to_string(),
+        };
+        ResultFuture::new(async { get_user_detail(params, USER_DETAIL_URL.as_ref()).await })
     }
 }
 
@@ -56,7 +66,7 @@ pub async fn user_sign_in(params: SignInParams, url: &str) -> Result<SignInRespo
     Ok(response)
 }
 
-pub async fn user_sign_out(params: SignOutParams, url: &str) -> Result<(), UserError> {
+pub async fn user_sign_out(params: UserToken, url: &str) -> Result<(), UserError> {
     let _ = HttpRequestBuilder::delete(&url.to_owned())
         .protobuf(params)?
         .send()
@@ -64,10 +74,7 @@ pub async fn user_sign_out(params: SignOutParams, url: &str) -> Result<(), UserE
     Ok(())
 }
 
-pub async fn get_user_detail(
-    params: QueryUserDetailParams,
-    url: &str,
-) -> Result<UserDetail, UserError> {
+pub async fn get_user_detail(params: UserToken, url: &str) -> Result<UserDetail, UserError> {
     let user_detail = HttpRequestBuilder::get(&url.to_owned())
         .protobuf(params)?
         .send()
diff --git a/rust-lib/flowy-user/src/services/user/user_server/server_api_mock.rs b/rust-lib/flowy-user/src/services/server/server_api_mock.rs
similarity index 82%
rename from rust-lib/flowy-user/src/services/user/user_server/server_api_mock.rs
rename to rust-lib/flowy-user/src/services/server/server_api_mock.rs
index d548783d82..a1c0844f7a 100644
--- a/rust-lib/flowy-user/src/services/user/user_server/server_api_mock.rs
+++ b/rust-lib/flowy-user/src/services/server/server_api_mock.rs
@@ -4,14 +4,12 @@ use crate::{
     services::user::UserServerAPI,
 };
 
-use crate::services::workspace::UserWorkspaceController;
+use crate::entities::UserToken;
 
-use flowy_net::future::ResultFuture;
+use flowy_infra::future::ResultFuture;
 use std::sync::Arc;
 
-pub struct UserServerMock {
-    pub workspace_controller: Arc<dyn UserWorkspaceController + Send + Sync>,
-}
+pub struct UserServerMock {}
 
 impl UserServerMock {}
 
@@ -44,7 +42,7 @@ impl UserServerAPI for UserServerMock {
         ResultFuture::new(async { Ok(()) })
     }
 
-    fn get_user_info(&self, _user_id: &str) -> ResultFuture<UserDetail, UserError> {
+    fn get_user_detail(&self, _token: &str) -> ResultFuture<UserDetail, UserError> {
         ResultFuture::new(async { Err(ErrorBuilder::new(ErrorCode::Unknown).build()) })
     }
 }
diff --git a/rust-lib/flowy-user/src/services/user/builder.rs b/rust-lib/flowy-user/src/services/user/builder.rs
index 0708f697b8..50e7b9cd67 100644
--- a/rust-lib/flowy-user/src/services/user/builder.rs
+++ b/rust-lib/flowy-user/src/services/user/builder.rs
@@ -1,7 +1,4 @@
-use crate::services::{
-    user::{UserSession, UserSessionConfig},
-    workspace::UserWorkspaceController,
-};
+use crate::services::user::{UserSession, UserSessionConfig};
 use std::sync::Arc;
 
 pub struct UserSessionBuilder {
@@ -16,12 +13,9 @@ impl UserSessionBuilder {
         self
     }
 
-    pub fn build<S>(mut self, workspace_controller: Arc<S>) -> UserSession
-    where
-        S: 'static + UserWorkspaceController + Send + Sync,
-    {
+    pub fn build(mut self) -> UserSession {
         let config = self.config.take().unwrap();
 
-        UserSession::new(config, workspace_controller)
+        UserSession::new(config)
     }
 }
diff --git a/rust-lib/flowy-user/src/services/user/database.rs b/rust-lib/flowy-user/src/services/user/database.rs
index eaded8f390..a7719d1bd6 100644
--- a/rust-lib/flowy-user/src/services/user/database.rs
+++ b/rust-lib/flowy-user/src/services/user/database.rs
@@ -1,9 +1,13 @@
 use crate::errors::{ErrorBuilder, ErrorCode, UserError};
 use flowy_database::{DBConnection, Database};
+use flowy_sqlite::ConnectionPool;
 use lazy_static::lazy_static;
 use once_cell::sync::Lazy;
 use parking_lot::Mutex;
-use std::{collections::HashMap, sync::RwLock};
+use std::{
+    collections::HashMap,
+    sync::{Arc, RwLock},
+};
 
 lazy_static! {
     static ref DB: RwLock<Option<Database>> = RwLock::new(None);
@@ -57,6 +61,11 @@ impl UserDB {
     }
 
     pub(crate) fn get_connection(&self, user_id: &str) -> Result<DBConnection, UserError> {
+        let conn = self.get_pool(user_id)?.get()?;
+        Ok(conn)
+    }
+
+    pub(crate) fn get_pool(&self, user_id: &str) -> Result<Arc<ConnectionPool>, UserError> {
         if !is_user_db_init(user_id) {
             let _ = self.open_user_db(user_id)?;
             set_user_db_init(true, user_id);
@@ -72,7 +81,7 @@ impl UserDB {
             None => Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed)
                 .msg("Get connection failed. The database is not initialization")
                 .build()),
-            Some(database) => Ok(database.get_connection()?),
+            Some(database) => Ok(database.get_pool()),
         }
     }
 }
diff --git a/rust-lib/flowy-user/src/services/user/mod.rs b/rust-lib/flowy-user/src/services/user/mod.rs
index 896a1afc9f..3d4446797b 100644
--- a/rust-lib/flowy-user/src/services/user/mod.rs
+++ b/rust-lib/flowy-user/src/services/user/mod.rs
@@ -1,8 +1,8 @@
 pub use builder::*;
-pub use user_server::*;
 pub use user_session::*;
 
+pub use crate::services::server::*;
+
 mod builder;
 pub mod database;
-mod user_server;
 mod user_session;
diff --git a/rust-lib/flowy-user/src/services/user/user_server/mod.rs b/rust-lib/flowy-user/src/services/user/user_server/mod.rs
deleted file mode 100644
index 77ebf0f7e7..0000000000
--- a/rust-lib/flowy-user/src/services/user/user_server/mod.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-mod server_api;
-mod server_api_mock;
-
-pub use server_api::*;
-pub use server_api_mock::*;
-
-use crate::services::workspace::UserWorkspaceController;
-use std::sync::Arc;
-
-pub(crate) fn construct_user_server(
-    workspace_controller: Arc<dyn UserWorkspaceController + Send + Sync>,
-) -> Arc<dyn UserServerAPI + Send + Sync> {
-    if cfg!(feature = "http_server") {
-        Arc::new(UserServer {})
-    } else {
-        Arc::new(UserServerMock {
-            workspace_controller,
-        })
-    }
-}
diff --git a/rust-lib/flowy-user/src/services/user/user_session.rs b/rust-lib/flowy-user/src/services/user/user_session.rs
index 310d896a88..92670d3b7c 100644
--- a/rust-lib/flowy-user/src/services/user/user_session.rs
+++ b/rust-lib/flowy-user/src/services/user/user_session.rs
@@ -1,10 +1,7 @@
 use crate::{
     entities::{SignInParams, SignUpParams, UpdateUserParams, UserDetail},
     errors::{ErrorBuilder, ErrorCode, UserError},
-    services::{
-        user::{construct_user_server, database::UserDB, UserServerAPI},
-        workspace::UserWorkspaceController,
-    },
+    services::user::{construct_user_server, database::UserDB, UserServerAPI},
     sql_tables::{UserTable, UserTableChangeset},
 };
 
@@ -16,7 +13,9 @@ use flowy_database::{
     UserDatabaseConnection,
 };
 
+use crate::entities::UserToken;
 use flowy_infra::kv::KVStore;
+use flowy_sqlite::ConnectionPool;
 use std::sync::{Arc, RwLock};
 
 pub struct UserSessionConfig {
@@ -31,26 +30,23 @@ impl UserSessionConfig {
     }
 }
 
+type Server = Arc<dyn UserServerAPI + Send + Sync>;
+
 pub struct UserSession {
     database: UserDB,
     config: UserSessionConfig,
     #[allow(dead_code)]
-    workspace_controller: Arc<dyn UserWorkspaceController + Send + Sync>,
-    server: Arc<dyn UserServerAPI + Send + Sync>,
+    pub(crate) server: Server,
     user_id: RwLock<Option<String>>,
 }
 
 impl UserSession {
-    pub fn new<R>(config: UserSessionConfig, workspace_controller: Arc<R>) -> Self
-    where
-        R: 'static + UserWorkspaceController + Send + Sync,
-    {
+    pub fn new(config: UserSessionConfig) -> Self {
         let db = UserDB::new(&config.root_dir);
-        let server = construct_user_server(workspace_controller.clone());
+        let server = construct_user_server();
         Self {
             database: db,
             config,
-            workspace_controller,
             server,
             user_id: RwLock::new(None),
         }
@@ -61,6 +57,11 @@ impl UserSession {
         self.database.get_connection(&user_id)
     }
 
+    pub fn db_connection_pool(&self) -> Result<Arc<ConnectionPool>, UserError> {
+        let user_id = self.user_id()?;
+        self.database.get_pool(&user_id)
+    }
+
     pub async fn sign_in(&self, params: SignInParams) -> Result<UserTable, UserError> {
         let resp = self.server.sign_in(params).await?;
         let _ = self.set_user_id(Some(resp.uid.clone()))?;
@@ -78,7 +79,7 @@ impl UserSession {
     }
 
     pub async fn sign_out(&self) -> Result<(), UserError> {
-        let user_detail = self.user_detail()?;
+        let user_detail = self.user_detail().await?;
 
         match self.server.sign_out(&user_detail.token).await {
             Ok(_) => {},
@@ -104,21 +105,34 @@ impl UserSession {
         Ok(user)
     }
 
-    pub fn update_user(&self, params: UpdateUserParams) -> Result<UserDetail, UserError> {
+    pub async fn update_user(&self, params: UpdateUserParams) -> Result<(), UserError> {
         let changeset = UserTableChangeset::new(params);
         let conn = self.get_db_connection()?;
         diesel_update_table!(user_table, changeset, conn);
-        let user_detail = self.user_detail()?;
-        Ok(user_detail)
+        Ok(())
     }
 
-    pub fn user_detail(&self) -> Result<UserDetail, UserError> {
+    pub async fn user_detail(&self) -> Result<UserDetail, UserError> {
         let user_id = self.user_id()?;
         let user = dsl::user_table
             .filter(user_table::id.eq(&user_id))
             .first::<UserTable>(&*(self.get_db_connection()?))?;
 
-        let _ = self.server.get_user_info(&user_id);
+        let server = self.server.clone();
+        let token = user.token.clone();
+        tokio::spawn(async move {
+            match server.get_user_detail(&token).await {
+                Ok(user_detail) => {
+                    //
+                    log::info!("{:?}", user_detail);
+                },
+                Err(e) => {
+                    //
+                    log::info!("{:?}", e);
+                },
+            }
+        })
+        .await;
 
         Ok(UserDetail::from(user))
     }
@@ -164,10 +178,21 @@ impl UserSession {
         }
     }
 
-    pub fn user_token(&self) -> Result<String, UserError> {
-        let user_detail = self.user_detail()?;
-        Ok(user_detail.token)
-    }
+    // pub fn user_token(&self) -> Result<String, UserError> {
+    //     let user_detail = self.user_detail()?;
+    //     Ok(user_detail.token)
+    // }
+}
+
+pub async fn update_user(
+    server: Server,
+    pool: Arc<ConnectionPool>,
+    params: UpdateUserParams,
+) -> Result<(), UserError> {
+    let changeset = UserTableChangeset::new(params);
+    let conn = pool.get()?;
+    diesel_update_table!(user_table, changeset, conn);
+    Ok(())
 }
 
 pub fn current_user_id() -> Result<String, UserError> {
diff --git a/rust-lib/flowy-user/src/services/workspace/action.rs b/rust-lib/flowy-user/src/services/workspace/action.rs
deleted file mode 100644
index aa2c5763c4..0000000000
--- a/rust-lib/flowy-user/src/services/workspace/action.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub trait UserWorkspaceController {}
diff --git a/rust-lib/flowy-user/src/services/workspace/mod.rs b/rust-lib/flowy-user/src/services/workspace/mod.rs
deleted file mode 100644
index 8bd911fd53..0000000000
--- a/rust-lib/flowy-user/src/services/workspace/mod.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-mod action;
-
-pub use action::*;
diff --git a/rust-lib/flowy-user/tests/event/helper.rs b/rust-lib/flowy-user/tests/event/helper.rs
index 62cc345d1c..90e1a6d94d 100644
--- a/rust-lib/flowy-user/tests/event/helper.rs
+++ b/rust-lib/flowy-user/tests/event/helper.rs
@@ -1,6 +1,6 @@
-pub use flowy_test::builder::RandomUserTestBuilder;
+pub use flowy_test::builder::TestBuilder;
 
-pub use flowy_test::prelude::{random_valid_email, valid_password};
+pub use flowy_test::prelude::{random_email, valid_password};
 
 pub(crate) fn invalid_email_test_case() -> Vec<String> {
     // https://gist.github.com/cjaoude/fd9910626629b53c4d25
diff --git a/rust-lib/flowy-user/tests/event/main.rs b/rust-lib/flowy-user/tests/event/main.rs
index c5c296acab..f05894579e 100644
--- a/rust-lib/flowy-user/tests/event/main.rs
+++ b/rust-lib/flowy-user/tests/event/main.rs
@@ -1,5 +1,5 @@
 mod helper;
 mod sign_in_test;
 mod sign_up_test;
-mod user_status_test;
+mod user_detail_test;
 mod user_update_test;
diff --git a/rust-lib/flowy-user/tests/event/sign_in_test.rs b/rust-lib/flowy-user/tests/event/sign_in_test.rs
index f08e9281ad..ecdcf04831 100644
--- a/rust-lib/flowy-user/tests/event/sign_in_test.rs
+++ b/rust-lib/flowy-user/tests/event/sign_in_test.rs
@@ -6,11 +6,11 @@ use serial_test::*;
 #[serial]
 fn sign_in_success() {
     let request = SignInRequest {
-        email: random_valid_email(),
+        email: random_email(),
         password: valid_password(),
     };
 
-    let response = RandomUserTestBuilder::new()
+    let response = TestBuilder::new()
         .logout()
         .event(SignIn)
         .request(request)
@@ -29,7 +29,7 @@ fn sign_in_with_invalid_email() {
         };
 
         assert_eq!(
-            RandomUserTestBuilder::new()
+            TestBuilder::new()
                 .event(SignIn)
                 .request(request)
                 .sync_send()
@@ -45,11 +45,11 @@ fn sign_in_with_invalid_email() {
 fn sign_in_with_invalid_password() {
     for password in invalid_password_test_case() {
         let request = SignInRequest {
-            email: random_valid_email(),
+            email: random_email(),
             password,
         };
 
-        RandomUserTestBuilder::new()
+        TestBuilder::new()
             .event(SignIn)
             .request(request)
             .sync_send()
diff --git a/rust-lib/flowy-user/tests/event/sign_up_test.rs b/rust-lib/flowy-user/tests/event/sign_up_test.rs
index bf7947f7c6..79fe31677a 100644
--- a/rust-lib/flowy-user/tests/event/sign_up_test.rs
+++ b/rust-lib/flowy-user/tests/event/sign_up_test.rs
@@ -6,12 +6,12 @@ use serial_test::*;
 #[serial]
 fn sign_up_success() {
     let request = SignUpRequest {
-        email: random_valid_email(),
+        email: random_email(),
         name: valid_name(),
         password: valid_password(),
     };
 
-    let _response = RandomUserTestBuilder::new()
+    let _response = TestBuilder::new()
         .logout()
         .event(SignUp)
         .request(request)
@@ -29,7 +29,7 @@ fn sign_up_with_invalid_email() {
         };
 
         assert_eq!(
-            RandomUserTestBuilder::new()
+            TestBuilder::new()
                 .event(SignUp)
                 .request(request)
                 .sync_send()
@@ -44,12 +44,12 @@ fn sign_up_with_invalid_email() {
 fn sign_up_with_invalid_password() {
     for password in invalid_password_test_case() {
         let request = SignUpRequest {
-            email: random_valid_email(),
+            email: random_email(),
             name: valid_name(),
             password,
         };
 
-        RandomUserTestBuilder::new()
+        TestBuilder::new()
             .event(SignUp)
             .request(request)
             .sync_send()
diff --git a/rust-lib/flowy-user/tests/event/user_status_test.rs b/rust-lib/flowy-user/tests/event/user_detail_test.rs
similarity index 60%
rename from rust-lib/flowy-user/tests/event/user_status_test.rs
rename to rust-lib/flowy-user/tests/event/user_detail_test.rs
index 18a02197bc..41a4627684 100644
--- a/rust-lib/flowy-user/tests/event/user_status_test.rs
+++ b/rust-lib/flowy-user/tests/event/user_detail_test.rs
@@ -4,23 +4,23 @@ use serial_test::*;
 
 #[test]
 #[serial]
-fn user_status_get_failed_before_login() {
-    let _a = RandomUserTestBuilder::new()
+fn user_status_get_failed() {
+    let _ = TestBuilder::new()
         .logout()
-        .event(GetStatus)
+        .event(GetUserProfile)
         .assert_error()
         .sync_send();
 }
 
 #[test]
 #[serial]
-fn user_status_get_success_after_login() {
+fn user_detail_get() {
     let request = SignInRequest {
-        email: random_valid_email(),
+        email: random_email(),
         password: valid_password(),
     };
 
-    let response = RandomUserTestBuilder::new()
+    let response = TestBuilder::new()
         .logout()
         .event(SignIn)
         .request(request)
@@ -28,8 +28,8 @@ fn user_status_get_success_after_login() {
         .parse::<UserDetail>();
     dbg!(&response);
 
-    let _ = RandomUserTestBuilder::new()
-        .event(GetStatus)
+    let _ = TestBuilder::new()
+        .event(GetUserProfile)
         .sync_send()
         .parse::<UserDetail>();
 }
diff --git a/rust-lib/flowy-user/tests/event/user_update_test.rs b/rust-lib/flowy-user/tests/event/user_update_test.rs
index 03597f5b2d..47592a03fe 100644
--- a/rust-lib/flowy-user/tests/event/user_update_test.rs
+++ b/rust-lib/flowy-user/tests/event/user_update_test.rs
@@ -5,18 +5,17 @@ use serial_test::*;
 #[test]
 #[serial]
 fn user_update_with_name() {
-    let user_detail = RandomUserTestBuilder::new().reset().user_detail.unwrap();
+    let user_detail = TestBuilder::new().login().user_detail.unwrap();
     let new_name = "hello_world".to_owned();
-    let request = UpdateUserRequest {
-        id: user_detail.id.clone(),
-        name: Some(new_name.clone()),
-        email: None,
-        password: None,
-    };
-
-    let user_detail = RandomUserTestBuilder::new()
+    let request = UpdateUserRequest::new(&user_detail.id).name(&new_name);
+    let _ = TestBuilder::new()
         .event(UpdateUser)
         .request(request)
+        .sync_send();
+
+    let user_detail = TestBuilder::new()
+        .event(GetUserProfile)
+        .assert_error()
         .sync_send()
         .parse::<UserDetail>();
 
@@ -26,18 +25,18 @@ fn user_update_with_name() {
 #[test]
 #[serial]
 fn user_update_with_email() {
-    let user_detail = RandomUserTestBuilder::new().reset().user_detail.unwrap();
+    let user_detail = TestBuilder::new().login().user_detail.unwrap();
     let new_email = "123@gmai.com".to_owned();
-    let request = UpdateUserRequest {
-        id: user_detail.id.clone(),
-        name: None,
-        email: Some(new_email.clone()),
-        password: None,
-    };
+    let request = UpdateUserRequest::new(&user_detail.id).email(&new_email);
 
-    let user_detail = RandomUserTestBuilder::new()
+    let _ = TestBuilder::new()
         .event(UpdateUser)
         .request(request)
+        .sync_send();
+
+    let user_detail = TestBuilder::new()
+        .event(GetUserProfile)
+        .assert_error()
         .sync_send()
         .parse::<UserDetail>();
 
@@ -47,16 +46,11 @@ fn user_update_with_email() {
 #[test]
 #[serial]
 fn user_update_with_password() {
-    let user_detail = RandomUserTestBuilder::new().reset().user_detail.unwrap();
+    let user_detail = TestBuilder::new().login().user_detail.unwrap();
     let new_password = "H123world!".to_owned();
-    let request = UpdateUserRequest {
-        id: user_detail.id.clone(),
-        name: None,
-        email: None,
-        password: Some(new_password.clone()),
-    };
+    let request = UpdateUserRequest::new(&user_detail.id).password(&new_password);
 
-    let _ = RandomUserTestBuilder::new()
+    let _ = TestBuilder::new()
         .event(UpdateUser)
         .request(request)
         .sync_send()
@@ -66,17 +60,11 @@ fn user_update_with_password() {
 #[test]
 #[serial]
 fn user_update_with_invalid_email() {
-    let user_detail = RandomUserTestBuilder::new().reset().user_detail.unwrap();
+    let user_detail = TestBuilder::new().login().user_detail.unwrap();
     for email in invalid_email_test_case() {
-        let request = UpdateUserRequest {
-            id: user_detail.id.clone(),
-            name: None,
-            email: Some(email),
-            password: None,
-        };
-
+        let request = UpdateUserRequest::new(&user_detail.id).email(&email);
         assert_eq!(
-            RandomUserTestBuilder::new()
+            TestBuilder::new()
                 .event(UpdateUser)
                 .request(request)
                 .sync_send()
@@ -90,16 +78,11 @@ fn user_update_with_invalid_email() {
 #[test]
 #[serial]
 fn user_update_with_invalid_password() {
-    let user_detail = RandomUserTestBuilder::new().reset().user_detail.unwrap();
+    let user_detail = TestBuilder::new().login().user_detail.unwrap();
     for password in invalid_password_test_case() {
-        let request = UpdateUserRequest {
-            id: user_detail.id.clone(),
-            name: None,
-            email: None,
-            password: Some(password),
-        };
+        let request = UpdateUserRequest::new(&user_detail.id).password(&password);
 
-        RandomUserTestBuilder::new()
+        TestBuilder::new()
             .event(UpdateUser)
             .request(request)
             .sync_send()
@@ -110,15 +93,10 @@ fn user_update_with_invalid_password() {
 #[test]
 #[serial]
 fn user_update_with_invalid_name() {
-    let user_detail = RandomUserTestBuilder::new().reset().user_detail.unwrap();
-    let request = UpdateUserRequest {
-        id: user_detail.id.clone(),
-        name: Some("".to_string()),
-        email: None,
-        password: None,
-    };
+    let user_detail = TestBuilder::new().login().user_detail.unwrap();
+    let request = UpdateUserRequest::new(&user_detail.id).name("");
 
-    RandomUserTestBuilder::new()
+    TestBuilder::new()
         .event(UpdateUser)
         .request(request)
         .sync_send()
diff --git a/rust-lib/flowy-workspace/tests/event/helper.rs b/rust-lib/flowy-workspace/tests/event/helper.rs
index b5f64ccb70..f0943255fa 100644
--- a/rust-lib/flowy-workspace/tests/event/helper.rs
+++ b/rust-lib/flowy-workspace/tests/event/helper.rs
@@ -1,4 +1,4 @@
-pub use flowy_test::builder::UserTestBuilder;
+pub use flowy_test::builder::AnnieTestBuilder;
 use flowy_workspace::{
     entities::{app::*, view::*, workspace::*},
     event::WorkspaceEvent::*,
@@ -12,7 +12,7 @@ pub(crate) fn invalid_workspace_name_test_case() -> Vec<String> {
 }
 
 pub fn create_workspace(name: &str, desc: &str) -> (String, Workspace) {
-    let builder = UserTestBuilder::new();
+    let builder = AnnieTestBuilder::new();
     let user_id = builder.user_detail.as_ref().unwrap().id.clone();
 
     let request = CreateWorkspaceRequest {
@@ -31,7 +31,7 @@ pub fn create_workspace(name: &str, desc: &str) -> (String, Workspace) {
 }
 
 pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option<Workspace> {
-    let mut repeated_workspace = UserTestBuilder::new()
+    let mut repeated_workspace = AnnieTestBuilder::new()
         .event(ReadWorkspaces)
         .request(request)
         .sync_send()
@@ -52,7 +52,7 @@ pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App {
         color_style: Default::default(),
     };
 
-    let app = UserTestBuilder::new()
+    let app = AnnieTestBuilder::new()
         .event(CreateApp)
         .request(create_app_request)
         .sync_send()
@@ -65,21 +65,21 @@ pub fn delete_app(app_id: &str) {
         app_id: app_id.to_string(),
     };
 
-    UserTestBuilder::new()
+    AnnieTestBuilder::new()
         .event(DeleteApp)
         .request(delete_app_request)
         .sync_send();
 }
 
 pub fn update_app(request: UpdateAppRequest) {
-    UserTestBuilder::new()
+    AnnieTestBuilder::new()
         .event(UpdateApp)
         .request(request)
         .sync_send();
 }
 
 pub fn read_app(request: QueryAppRequest) -> App {
-    let app = UserTestBuilder::new()
+    let app = AnnieTestBuilder::new()
         .event(ReadApp)
         .request(request)
         .sync_send()
@@ -89,7 +89,7 @@ pub fn read_app(request: QueryAppRequest) -> App {
 }
 
 pub fn create_view_with_request(request: CreateViewRequest) -> View {
-    let view = UserTestBuilder::new()
+    let view = AnnieTestBuilder::new()
         .event(CreateView)
         .request(request)
         .sync_send()
@@ -113,14 +113,14 @@ pub fn create_view() -> View {
 }
 
 pub fn update_view(request: UpdateViewRequest) {
-    UserTestBuilder::new()
+    AnnieTestBuilder::new()
         .event(UpdateView)
         .request(request)
         .sync_send();
 }
 
 pub fn read_view(request: QueryViewRequest) -> View {
-    UserTestBuilder::new()
+    AnnieTestBuilder::new()
         .event(ReadView)
         .request(request)
         .sync_send()
diff --git a/rust-lib/flowy-workspace/tests/event/workspace_test.rs b/rust-lib/flowy-workspace/tests/event/workspace_test.rs
index 22524207d1..2df7aca428 100644
--- a/rust-lib/flowy-workspace/tests/event/workspace_test.rs
+++ b/rust-lib/flowy-workspace/tests/event/workspace_test.rs
@@ -15,7 +15,7 @@ fn workspace_read_all() {
         "workspace_create_and_then_get_workspace_success",
     );
     let request = QueryWorkspaceRequest::new(&user_id);
-    let workspaces = UserTestBuilder::new()
+    let workspaces = AnnieTestBuilder::new()
         .event(ReadWorkspaces)
         .request(request)
         .sync_send()
@@ -48,7 +48,7 @@ fn workspace_create_with_apps() {
 #[test]
 fn workspace_create_with_invalid_name() {
     for name in invalid_workspace_name_test_case() {
-        let builder = UserTestBuilder::new();
+        let builder = AnnieTestBuilder::new();
         let user_id = builder.user_detail.as_ref().unwrap().id.clone();
 
         let request = CreateWorkspaceRequest {
@@ -72,7 +72,7 @@ fn workspace_create_with_invalid_name() {
 #[test]
 fn workspace_update_with_invalid_name() {
     for name in invalid_workspace_name_test_case() {
-        let builder = UserTestBuilder::new();
+        let builder = AnnieTestBuilder::new();
         let user_id = builder.user_detail.as_ref().unwrap().id.clone();
 
         let request = CreateWorkspaceRequest {