소스 검색

[rust]: create default workspace

appflowy 3 년 전
부모
커밋
b79267d15c
40개의 변경된 파일364개의 추가작업 그리고 259개의 파일을 삭제
  1. 1 0
      Makefile.toml
  2. 5 5
      app_flowy/lib/user/application/sign_up_bloc.dart
  3. 12 3
      app_flowy/lib/user/domain/i_auth.dart
  4. 21 2
      app_flowy/lib/user/infrastructure/i_auth_impl.dart
  5. 14 7
      app_flowy/lib/user/infrastructure/repos/auth_repo.dart
  6. 56 50
      app_flowy/lib/user/presentation/skip_log_in_screen.dart
  7. 2 2
      app_flowy/lib/user/presentation/splash_screen.dart
  8. 2 2
      app_flowy/lib/workspace/presentation/widgets/menu/widget/app/header/header.dart
  9. 14 0
      app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
  10. 18 18
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/workspace_query.pb.dart
  11. 5 5
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/workspace_query.pbjson.dart
  12. 2 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbenum.dart
  13. 2 1
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbjson.dart
  14. 1 2
      backend/src/service/user/user_default.rs
  15. 2 2
      backend/src/service/workspace/router.rs
  16. 1 4
      backend/src/service/workspace/sql_builder.rs
  17. 6 6
      backend/tests/api/workspace.rs
  18. 1 1
      backend/tests/helper.rs
  19. 1 1
      rust-lib/flowy-backend-api/src/workspace_request.rs
  20. 1 2
      rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
  21. 6 0
      rust-lib/flowy-workspace-infra/src/entities/app/app_create.rs
  22. 3 0
      rust-lib/flowy-workspace-infra/src/entities/workspace/workspace_create.rs
  23. 6 16
      rust-lib/flowy-workspace-infra/src/entities/workspace/workspace_query.rs
  24. 34 34
      rust-lib/flowy-workspace-infra/src/protobuf/model/workspace_query.rs
  25. 1 1
      rust-lib/flowy-workspace-infra/src/protobuf/proto/workspace_query.proto
  26. 0 1
      rust-lib/flowy-workspace-infra/src/user_default.rs
  27. 1 1
      rust-lib/flowy-workspace/Cargo.toml
  28. 3 0
      rust-lib/flowy-workspace/src/event.rs
  29. 1 1
      rust-lib/flowy-workspace/src/handlers/app_handler.rs
  30. 1 1
      rust-lib/flowy-workspace/src/handlers/view_handler.rs
  31. 34 5
      rust-lib/flowy-workspace/src/handlers/workspace_handler.rs
  32. 2 1
      rust-lib/flowy-workspace/src/module.rs
  33. 69 64
      rust-lib/flowy-workspace/src/protobuf/model/event.rs
  34. 1 0
      rust-lib/flowy-workspace/src/protobuf/proto/event.proto
  35. 5 2
      rust-lib/flowy-workspace/src/services/app_controller.rs
  36. 2 2
      rust-lib/flowy-workspace/src/services/server/mod.rs
  37. 2 2
      rust-lib/flowy-workspace/src/services/server/server_api.rs
  38. 2 2
      rust-lib/flowy-workspace/src/services/server/server_api_mock.rs
  39. 6 2
      rust-lib/flowy-workspace/src/services/view_controller.rs
  40. 18 11
      rust-lib/flowy-workspace/src/services/workspace_controller.rs

+ 1 - 0
Makefile.toml

@@ -25,6 +25,7 @@ CRATE_TYPE = "cdylib"
 BUILD_FLAG = "debug"
 FLUTTER_PLATFORM = "macos"
 FLUTTER_OUTPUT_DIR = "Debug"
+FEATURES = "flutter"
 PRODUCT_EXT = "app"
 
 

+ 5 - 5
app_flowy/lib/user/application/sign_up_bloc.dart

@@ -9,8 +9,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 part 'sign_up_bloc.freezed.dart';
 
 class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
-  final IAuth authImpl;
-  SignUpBloc(this.authImpl) : super(SignUpState.initial());
+  final IAuth authManager;
+  SignUpBloc(this.authManager) : super(SignUpState.initial());
 
   @override
   Stream<SignUpState> mapEventToState(
@@ -64,11 +64,11 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
       repeatPasswordError: none(),
     );
 
-    final result = await authImpl.signUp(state.email, state.password, state.email);
+    final result = await authManager.signUp(state.email, state.password, state.email);
     yield result.fold(
-      (userProfile) => state.copyWith(
+      (newUser) => state.copyWith(
         isSubmitting: false,
-        successOrFail: some(left(userProfile)),
+        successOrFail: some(left(newUser.profile)),
         emailError: none(),
         passwordError: none(),
         repeatPasswordError: none(),

+ 12 - 3
app_flowy/lib/user/domain/i_auth.dart

@@ -1,11 +1,19 @@
-import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
 import 'package:dartz/dartz.dart';
+import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
 import 'package:flutter/material.dart';
 
+class NewUser {
+  UserProfile profile;
+  String workspaceId;
+  NewUser({
+    required this.profile,
+    required this.workspaceId,
+  });
+}
+
 abstract class IAuth {
   Future<Either<UserProfile, UserError>> signIn(String? email, String? password);
-  Future<Either<UserProfile, UserError>> signUp(String? name, String? password, String? email);
-
+  Future<Either<NewUser, UserError>> signUp(String? name, String? password, String? email);
   Future<Either<Unit, UserError>> signOut();
 }
 
@@ -13,4 +21,5 @@ abstract class IAuthRouter {
   void pushWelcomeScreen(BuildContext context, UserProfile userProfile);
   void pushSignUpScreen(BuildContext context);
   void pushForgetPasswordScreen(BuildContext context);
+  void pushHomeScreen(BuildContext context, UserProfile profile, String workspaceId);
 }

+ 21 - 2
app_flowy/lib/user/infrastructure/i_auth_impl.dart

@@ -1,7 +1,9 @@
 import 'package:app_flowy/startup/startup.dart';
 import 'package:app_flowy/user/domain/i_splash.dart';
 import 'package:app_flowy/user/presentation/sign_up_screen.dart';
+import 'package:app_flowy/workspace/presentation/home/home_screen.dart';
 import 'package:dartz/dartz.dart';
+import 'package:flowy_infra/time/duration.dart';
 import 'package:flowy_infra_ui/widget/route/animation.dart';
 import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
 import 'package:app_flowy/user/domain/i_auth.dart';
@@ -20,8 +22,17 @@ class AuthImpl extends IAuth {
   }
 
   @override
-  Future<Either<UserProfile, UserError>> signUp(String? name, String? password, String? email) {
-    return repo.signUp(name: name, password: password, email: email);
+  Future<Either<NewUser, UserError>> signUp(String? name, String? password, String? email) {
+    return repo.signUp(name: name, password: password, email: email).then((result) {
+      return result.fold(
+          (tuple) => left(
+                NewUser(
+                  profile: tuple.value1,
+                  workspaceId: tuple.value2,
+                ),
+              ),
+          (error) => right(error));
+    });
   }
 
   @override
@@ -49,4 +60,12 @@ class AuthRouterImpl extends IAuthRouter {
       ),
     );
   }
+
+  @override
+  void pushHomeScreen(BuildContext context, UserProfile profile, String workspaceId) {
+    Navigator.push(
+      context,
+      PageRoutes.fade(() => HomeScreen(profile, workspaceId), RouteDurations.slow.inMilliseconds * .001),
+    );
+  }
 }

+ 14 - 7
app_flowy/lib/user/infrastructure/repos/auth_repo.dart

@@ -3,8 +3,7 @@ import 'package:flowy_sdk/dispatch/dispatch.dart';
 import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
 
 class AuthRepository {
-  Future<Either<UserProfile, UserError>> signIn(
-      {required String? email, required String? password}) {
+  Future<Either<UserProfile, UserError>> signIn({required String? email, required String? password}) {
     //
     final request = SignInRequest.create()
       ..email = email ?? ''
@@ -13,16 +12,24 @@ class AuthRepository {
     return UserEventSignIn(request).send();
   }
 
-  Future<Either<UserProfile, UserError>> signUp(
-      {required String? name,
-      required String? password,
-      required String? email}) {
+  Future<Either<Tuple2<UserProfile, String>, UserError>> signUp(
+      {required String? name, required String? password, required String? email}) {
     final request = SignUpRequest.create()
       ..email = email ?? ''
       ..name = name ?? ''
       ..password = password ?? '';
 
-    return UserEventSignUp(request).send();
+    return UserEventSignUp(request).send().then((result) {
+      return result.fold((userProfile) async {
+        return await WorkspaceEventCreateDefaultWorkspace().send().then((result) {
+          return result.fold((workspaceIdentifier) {
+            return left(Tuple2(userProfile, workspaceIdentifier.workspaceId));
+          }, (error) {
+            throw UnimplementedError;
+          });
+        });
+      }, (error) => right(error));
+    });
   }
 
   Future<Either<Unit, UserError>> signOut() {

+ 56 - 50
app_flowy/lib/user/presentation/skip_log_in_screen.dart

@@ -2,8 +2,10 @@ import 'package:app_flowy/user/domain/i_auth.dart';
 import 'package:app_flowy/user/presentation/widgets/background.dart';
 import 'package:flowy_infra/size.dart';
 import 'package:flowy_infra/theme.dart';
+import 'package:flowy_infra/uuid.dart';
 import 'package:flowy_infra_ui/widget/rounded_button.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
+import 'package:flowy_log/flowy_log.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:url_launcher/url_launcher.dart';
@@ -16,61 +18,52 @@ class SkipLogInScreen extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return Scaffold(
-      body: SignInForm(router: router),
+      body: Center(
+        child: SizedBox(
+          width: 400,
+          height: 600,
+          child: _renderBody(context),
+        ),
+      ),
     );
   }
-}
-
-class SignInForm extends StatelessWidget {
-  final IAuthRouter router;
-  const SignInForm({
-    Key? key,
-    required this.router,
-  }) : super(key: key);
 
-  @override
-  Widget build(BuildContext context) {
-    return Center(
-      child: SizedBox(
-        width: 400,
-        height: 600,
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
+  Widget _renderBody(BuildContext context) {
+    return Column(
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        const FlowyLogoTitle(
+          title: 'Welcome to AppFlowy',
+          logoSize: Size.square(60),
+        ),
+        const VSpace(80),
+        GoButton(onPressed: () => _autoRegister(context)),
+        const VSpace(30),
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
           children: [
-            const FlowyLogoTitle(
-              title: 'Welcome to AppFlowy',
-              logoSize: Size.square(60),
+            InkWell(
+              child: const Text(
+                'Star on Github',
+                style: TextStyle(decoration: TextDecoration.underline, color: Colors.blue),
+              ),
+              onTap: () {
+                _launchURL('https://github.com/AppFlowy-IO/appflowy');
+              },
+            ),
+            const Spacer(),
+            InkWell(
+              child: const Text(
+                'Subscribe to Newsletter',
+                style: TextStyle(decoration: TextDecoration.underline, color: Colors.blue),
+              ),
+              onTap: () {
+                _launchURL('https://www.appflowy.io/blog');
+              },
             ),
-            const VSpace(80),
-            GoButton(onPressed: _autoRegister),
-            const VSpace(30),
-            Row(
-              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-              children: [
-                InkWell(
-                  child: const Text(
-                    'Star on Github',
-                    style: TextStyle(decoration: TextDecoration.underline, color: Colors.blue),
-                  ),
-                  onTap: () {
-                    _launchURL('https://github.com/AppFlowy-IO/appflowy');
-                  },
-                ),
-                const Spacer(),
-                InkWell(
-                  child: const Text(
-                    'Subscribe to Newsletter',
-                    style: TextStyle(decoration: TextDecoration.underline, color: Colors.blue),
-                  ),
-                  onTap: () {
-                    _launchURL('https://www.appflowy.io/blog');
-                  },
-                ),
-              ],
-            )
           ],
-        ),
-      ),
+        )
+      ],
     );
   }
 
@@ -82,7 +75,20 @@ class SignInForm extends StatelessWidget {
     }
   }
 
-  void _autoRegister() {}
+  void _autoRegister(BuildContext context) async {
+    const password = "AppFlowy123@";
+    final uid = uuid();
+    final userEmail = "[email protected]";
+    final result = await authManager.signUp("FlowyUser", password, userEmail);
+    result.fold(
+      (newUser) {
+        router.pushHomeScreen(context, newUser.profile, newUser.workspaceId);
+      },
+      (error) {
+        Log.error(error);
+      },
+    );
+  }
 }
 
 class GoButton extends StatelessWidget {

+ 2 - 2
app_flowy/lib/user/presentation/splash_screen.dart

@@ -59,9 +59,9 @@ class SplashScreen extends StatelessWidget {
 
   void _handleUnauthenticated(BuildContext context, Unauthenticated result) {
     Log.error(result.error);
-    getIt<ISplashRoute>().pushSignInScreen(context);
+    // getIt<ISplashRoute>().pushSignInScreen(context);
 
-    // getIt<ISplashRoute>().pushSkipLoginScreen(context);
+    getIt<ISplashRoute>().pushSkipLoginScreen(context);
   }
 }
 

+ 2 - 2
app_flowy/lib/workspace/presentation/widgets/menu/widget/app/header/header.dart

@@ -35,7 +35,7 @@ class MenuAppHeader extends StatelessWidget {
         crossAxisAlignment: CrossAxisAlignment.center,
         children: [
           _renderExpandedIcon(context, theme),
-          HSpace(MenuAppSizes.iconPadding),
+          // HSpace(MenuAppSizes.iconPadding),
           _renderTitle(context),
           _renderAddButton(context),
         ],
@@ -57,7 +57,7 @@ class MenuAppHeader extends StatelessWidget {
             collapseIcon: FlowyIconData.drop_down_hide,
             iconColor: theme.shader1,
             iconSize: MenuAppSizes.iconSize,
-            iconPadding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
+            iconPadding: const EdgeInsets.fromLTRB(0, 0, 10, 0),
             hasIcon: false,
           ),
         ),

+ 14 - 0
app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -101,6 +101,20 @@ class WorkspaceEventReadWorkspaceApps {
     }
 }
 
+class WorkspaceEventCreateDefaultWorkspace {
+    WorkspaceEventCreateDefaultWorkspace();
+
+    Future<Either<WorkspaceIdentifier, WorkspaceError>> send() {
+     final request = FFIRequest.create()
+        ..event = WorkspaceEvent.CreateDefaultWorkspace.toString();
+
+     return Dispatch.asyncRequest(request).then((bytesResult) => bytesResult.fold(
+        (okBytes) => left(WorkspaceIdentifier.fromBuffer(okBytes)),
+        (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+      ));
+    }
+}
+
 class WorkspaceEventCreateApp {
      CreateAppRequest request;
      WorkspaceEventCreateApp(this.request);

+ 18 - 18
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/workspace_query.pb.dart

@@ -69,24 +69,24 @@ class QueryWorkspaceRequest extends $pb.GeneratedMessage {
   void clearWorkspaceId() => clearField(1);
 }
 
-enum QueryWorkspaceParams_OneOfWorkspaceId {
+enum WorkspaceIdentifier_OneOfWorkspaceId {
   workspaceId, 
   notSet
 }
 
-class QueryWorkspaceParams extends $pb.GeneratedMessage {
-  static const $core.Map<$core.int, QueryWorkspaceParams_OneOfWorkspaceId> _QueryWorkspaceParams_OneOfWorkspaceIdByTag = {
-    1 : QueryWorkspaceParams_OneOfWorkspaceId.workspaceId,
-    0 : QueryWorkspaceParams_OneOfWorkspaceId.notSet
+class WorkspaceIdentifier extends $pb.GeneratedMessage {
+  static const $core.Map<$core.int, WorkspaceIdentifier_OneOfWorkspaceId> _WorkspaceIdentifier_OneOfWorkspaceIdByTag = {
+    1 : WorkspaceIdentifier_OneOfWorkspaceId.workspaceId,
+    0 : WorkspaceIdentifier_OneOfWorkspaceId.notSet
   };
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryWorkspaceParams', createEmptyInstance: create)
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WorkspaceIdentifier', createEmptyInstance: create)
     ..oo(0, [1])
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'workspaceId')
     ..hasRequiredFields = false
   ;
 
-  QueryWorkspaceParams._() : super();
-  factory QueryWorkspaceParams({
+  WorkspaceIdentifier._() : super();
+  factory WorkspaceIdentifier({
     $core.String? workspaceId,
   }) {
     final _result = create();
@@ -95,28 +95,28 @@ class QueryWorkspaceParams extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory QueryWorkspaceParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory QueryWorkspaceParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory WorkspaceIdentifier.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory WorkspaceIdentifier.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')
-  QueryWorkspaceParams clone() => QueryWorkspaceParams()..mergeFromMessage(this);
+  WorkspaceIdentifier clone() => WorkspaceIdentifier()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  QueryWorkspaceParams copyWith(void Function(QueryWorkspaceParams) updates) => super.copyWith((message) => updates(message as QueryWorkspaceParams)) as QueryWorkspaceParams; // ignore: deprecated_member_use
+  WorkspaceIdentifier copyWith(void Function(WorkspaceIdentifier) updates) => super.copyWith((message) => updates(message as WorkspaceIdentifier)) as WorkspaceIdentifier; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static QueryWorkspaceParams create() => QueryWorkspaceParams._();
-  QueryWorkspaceParams createEmptyInstance() => create();
-  static $pb.PbList<QueryWorkspaceParams> createRepeated() => $pb.PbList<QueryWorkspaceParams>();
+  static WorkspaceIdentifier create() => WorkspaceIdentifier._();
+  WorkspaceIdentifier createEmptyInstance() => create();
+  static $pb.PbList<WorkspaceIdentifier> createRepeated() => $pb.PbList<WorkspaceIdentifier>();
   @$core.pragma('dart2js:noInline')
-  static QueryWorkspaceParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<QueryWorkspaceParams>(create);
-  static QueryWorkspaceParams? _defaultInstance;
+  static WorkspaceIdentifier getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WorkspaceIdentifier>(create);
+  static WorkspaceIdentifier? _defaultInstance;
 
-  QueryWorkspaceParams_OneOfWorkspaceId whichOneOfWorkspaceId() => _QueryWorkspaceParams_OneOfWorkspaceIdByTag[$_whichOneof(0)]!;
+  WorkspaceIdentifier_OneOfWorkspaceId whichOneOfWorkspaceId() => _WorkspaceIdentifier_OneOfWorkspaceIdByTag[$_whichOneof(0)]!;
   void clearOneOfWorkspaceId() => clearField($_whichOneof(0));
 
   @$pb.TagNumber(1)

+ 5 - 5
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/workspace_query.pbjson.dart

@@ -21,9 +21,9 @@ const QueryWorkspaceRequest$json = const {
 
 /// Descriptor for `QueryWorkspaceRequest`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List queryWorkspaceRequestDescriptor = $convert.base64Decode('ChVRdWVyeVdvcmtzcGFjZVJlcXVlc3QSIwoMd29ya3NwYWNlX2lkGAEgASgJSABSC3dvcmtzcGFjZUlkQhUKE29uZV9vZl93b3Jrc3BhY2VfaWQ=');
-@$core.Deprecated('Use queryWorkspaceParamsDescriptor instead')
-const QueryWorkspaceParams$json = const {
-  '1': 'QueryWorkspaceParams',
+@$core.Deprecated('Use workspaceIdentifierDescriptor instead')
+const WorkspaceIdentifier$json = const {
+  '1': 'WorkspaceIdentifier',
   '2': const [
     const {'1': 'workspace_id', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'workspaceId'},
   ],
@@ -32,5 +32,5 @@ const QueryWorkspaceParams$json = const {
   ],
 };
 
-/// Descriptor for `QueryWorkspaceParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List queryWorkspaceParamsDescriptor = $convert.base64Decode('ChRRdWVyeVdvcmtzcGFjZVBhcmFtcxIjCgx3b3Jrc3BhY2VfaWQYASABKAlIAFILd29ya3NwYWNlSWRCFQoTb25lX29mX3dvcmtzcGFjZV9pZA==');
+/// Descriptor for `WorkspaceIdentifier`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List workspaceIdentifierDescriptor = $convert.base64Decode('ChNXb3Jrc3BhY2VJZGVudGlmaWVyEiMKDHdvcmtzcGFjZV9pZBgBIAEoCUgAUgt3b3Jrc3BhY2VJZEIVChNvbmVfb2Zfd29ya3NwYWNlX2lk');

+ 2 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbenum.dart

@@ -16,6 +16,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
   static const WorkspaceEvent DeleteWorkspace = WorkspaceEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteWorkspace');
   static const WorkspaceEvent OpenWorkspace = WorkspaceEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OpenWorkspace');
   static const WorkspaceEvent ReadWorkspaceApps = WorkspaceEvent._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadWorkspaceApps');
+  static const WorkspaceEvent CreateDefaultWorkspace = WorkspaceEvent._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateDefaultWorkspace');
   static const WorkspaceEvent CreateApp = WorkspaceEvent._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateApp');
   static const WorkspaceEvent DeleteApp = WorkspaceEvent._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteApp');
   static const WorkspaceEvent ReadApp = WorkspaceEvent._(103, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadApp');
@@ -43,6 +44,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
     DeleteWorkspace,
     OpenWorkspace,
     ReadWorkspaceApps,
+    CreateDefaultWorkspace,
     CreateApp,
     DeleteApp,
     ReadApp,

+ 2 - 1
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbjson.dart

@@ -18,6 +18,7 @@ const WorkspaceEvent$json = const {
     const {'1': 'DeleteWorkspace', '2': 3},
     const {'1': 'OpenWorkspace', '2': 4},
     const {'1': 'ReadWorkspaceApps', '2': 5},
+    const {'1': 'CreateDefaultWorkspace', '2': 6},
     const {'1': 'CreateApp', '2': 101},
     const {'1': 'DeleteApp', '2': 102},
     const {'1': 'ReadApp', '2': 103},
@@ -41,4 +42,4 @@ const WorkspaceEvent$json = const {
 };
 
 /// Descriptor for `WorkspaceEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARINCghPcGVuVmlldxDPARIOCglDbG9zZVZpZXcQ0AESDgoJUmVhZFRyYXNoEKwCEhEKDFB1dGJhY2tUcmFzaBCtAhIQCgtEZWxldGVUcmFzaBCuAhIPCgpSZXN0b3JlQWxsEK8CEg4KCURlbGV0ZUFsbBCwAhISCg1BcHBseURvY0RlbHRhEJADEhIKDUluaXRXb3Jrc3BhY2UQ6Ac=');
+final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRIaChZDcmVhdGVEZWZhdWx0V29ya3NwYWNlEAYSDQoJQ3JlYXRlQXBwEGUSDQoJRGVsZXRlQXBwEGYSCwoHUmVhZEFwcBBnEg0KCVVwZGF0ZUFwcBBoEg8KCkNyZWF0ZVZpZXcQyQESDQoIUmVhZFZpZXcQygESDwoKVXBkYXRlVmlldxDLARIPCgpEZWxldGVWaWV3EMwBEhIKDUR1cGxpY2F0ZVZpZXcQzQESDQoIQ29weUxpbmsQzgESDQoIT3BlblZpZXcQzwESDgoJQ2xvc2VWaWV3ENABEg4KCVJlYWRUcmFzaBCsAhIRCgxQdXRiYWNrVHJhc2gQrQISEAoLRGVsZXRlVHJhc2gQrgISDwoKUmVzdG9yZUFsbBCvAhIOCglEZWxldGVBbGwQsAISEgoNQXBwbHlEb2NEZWx0YRCQAxISCg1Jbml0V29ya3NwYWNlEOgH');

+ 1 - 2
backend/src/service/user/user_default.rs

@@ -1,7 +1,6 @@
 use crate::{
     service::{
         app::sql_builder::NewAppSqlBuilder as AppBuilder,
-        view::create_view,
         workspace::sql_builder::NewWorkspaceBuilder as WorkspaceBuilder,
     },
     sqlx_ext::{map_sqlx_error, DBTransaction},
@@ -11,7 +10,7 @@ use crate::service::view::{create_view_with_args, sql_builder::NewViewSqlBuilder
 use chrono::Utc;
 use flowy_document::services::doc::doc_initial_string;
 use flowy_net::errors::ServerError;
-use flowy_workspace_infra::protobuf::{App, CreateViewParams, View, ViewType, Workspace};
+use flowy_workspace_infra::protobuf::Workspace;
 use std::convert::TryInto;
 
 pub async fn create_default_workspace(

+ 2 - 2
backend/src/service/workspace/router.rs

@@ -20,7 +20,7 @@ use flowy_net::{
 };
 use flowy_workspace_infra::{
     parser::workspace::{WorkspaceDesc, WorkspaceName},
-    protobuf::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams},
+    protobuf::{CreateWorkspaceParams, DeleteWorkspaceParams, UpdateWorkspaceParams, WorkspaceIdentifier},
 };
 use sqlx::PgPool;
 
@@ -50,7 +50,7 @@ pub async fn read_handler(
     pool: Data<PgPool>,
     logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
-    let params: QueryWorkspaceParams = parse_from_payload(payload).await?;
+    let params: WorkspaceIdentifier = parse_from_payload(payload).await?;
     let mut transaction = pool
         .begin()
         .await

+ 1 - 4
backend/src/service/workspace/sql_builder.rs

@@ -4,10 +4,7 @@ use crate::{
 };
 use chrono::{DateTime, NaiveDateTime, Utc};
 use flowy_net::errors::{invalid_params, ServerError};
-use flowy_workspace_infra::{
-    parser::workspace::WorkspaceId,
-    protobuf::{RepeatedApp, Workspace},
-};
+use flowy_workspace_infra::{parser::workspace::WorkspaceId, protobuf::Workspace};
 use sqlx::postgres::PgArguments;
 use uuid::Uuid;
 

+ 6 - 6
backend/tests/api/workspace.rs

@@ -3,7 +3,7 @@ use flowy_workspace_infra::entities::{
     app::{AppIdentifier, UpdateAppParams},
     trash::{TrashIdentifier, TrashIdentifiers, TrashType},
     view::{UpdateViewParams, ViewIdentifier},
-    workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams},
+    workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, UpdateWorkspaceParams, WorkspaceIdentifier},
 };
 
 #[actix_rt::test]
@@ -15,7 +15,7 @@ async fn workspace_create() {
 #[actix_rt::test]
 async fn workspace_read() {
     let test = WorkspaceTest::new().await;
-    let read_params = QueryWorkspaceParams::new().workspace_id(&test.workspace.id);
+    let read_params = WorkspaceIdentifier::new(Some(test.workspace.id.clone()));
     let repeated_workspace = test.server.read_workspaces(read_params).await;
     tracing::info!("{:?}", repeated_workspace);
 }
@@ -28,7 +28,7 @@ async fn workspace_read_with_belongs() {
     let _ = test.create_app().await;
     let _ = test.create_app().await;
 
-    let read_params = QueryWorkspaceParams::new().workspace_id(&test.workspace.id);
+    let read_params = WorkspaceIdentifier::new(Some(test.workspace.id.clone()));
     let workspaces = test.server.read_workspaces(read_params).await;
     let workspace = workspaces.items.first().unwrap();
     assert_eq!(workspace.apps.len(), 3);
@@ -46,7 +46,7 @@ async fn workspace_update() {
         desc: Some(new_desc.to_string()),
     };
     test.server.update_workspace(update_params).await;
-    let read_params = QueryWorkspaceParams::new().workspace_id(&test.workspace.id);
+    let read_params = WorkspaceIdentifier::new(Some(test.workspace.id.clone()));
     let repeated_workspace = test.server.read_workspaces(read_params).await;
 
     let workspace = repeated_workspace.first().unwrap();
@@ -62,7 +62,7 @@ async fn workspace_delete() {
     };
 
     let _ = test.server.delete_workspace(delete_params).await;
-    let read_params = QueryWorkspaceParams::new().workspace_id(&test.workspace.id);
+    let read_params = WorkspaceIdentifier::new(Some(test.workspace.id.clone()));
     let repeated_workspace = test.server.read_workspaces(read_params).await;
     assert_eq!(repeated_workspace.len(), 0);
 }
@@ -210,7 +210,7 @@ async fn workspace_list_read() {
         let _ = server.create_workspace(params).await;
     }
 
-    let read_params = QueryWorkspaceParams::new();
+    let read_params = WorkspaceIdentifier::new();
     let workspaces = server.read_workspaces(read_params).await;
     assert_eq!(workspaces.len(), 4);
 }

+ 1 - 1
backend/tests/helper.rs

@@ -66,7 +66,7 @@ impl TestUserServer {
         workspace
     }
 
-    pub async fn read_workspaces(&self, params: QueryWorkspaceParams) -> RepeatedWorkspace {
+    pub async fn read_workspaces(&self, params: WorkspaceIdentifier) -> RepeatedWorkspace {
         let url = format!("{}/api/workspace", self.http_addr());
         let workspaces = read_workspaces_request(self.user_token(), params, &url).await.unwrap();
         workspaces

+ 1 - 1
rust-lib/flowy-backend-api/src/workspace_request.rs

@@ -21,7 +21,7 @@ pub async fn create_workspace_request(
 
 pub async fn read_workspaces_request(
     token: &str,
-    params: QueryWorkspaceParams,
+    params: WorkspaceIdentifier,
     url: &str,
 ) -> Result<RepeatedWorkspace, ServerError> {
     let repeated_workspace = request_builder()

+ 1 - 2
rust-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -33,7 +33,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "Workspace"
         | "RepeatedWorkspace"
         | "QueryWorkspaceRequest"
-        | "QueryWorkspaceParams"
+        | "WorkspaceIdentifier"
         | "CurrentWorkspace"
         | "TrashIdentifiers"
         | "TrashIdentifier"
@@ -82,7 +82,6 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "ViewType"
         | "ErrorCode"
         | "WorkspaceEvent"
-        | "WorkspaceNotification"
         | "WsModule"
         | "RevType"
         | "WsDataType"

+ 6 - 0
rust-lib/flowy-workspace-infra/src/entities/app/app_create.rs

@@ -98,6 +98,12 @@ pub struct App {
     pub create_time: i64,
 }
 
+impl App {
+    pub fn take_belongings(&mut self) -> RepeatedView {
+        ::std::mem::replace(&mut self.belongings, RepeatedView::default())
+    }
+}
+
 #[derive(PartialEq, Debug, Default, ProtoBuf, Clone)]
 pub struct RepeatedApp {
     #[pb(index = 1)]

+ 3 - 0
rust-lib/flowy-workspace-infra/src/entities/workspace/workspace_create.rs

@@ -60,6 +60,9 @@ pub struct Workspace {
     pub create_time: i64,
 }
 
+impl Workspace {
+    pub fn take_apps(&mut self) -> RepeatedApp { ::std::mem::replace(&mut self.apps, RepeatedApp::default()) }
+}
 #[derive(PartialEq, Debug, Default, ProtoBuf)]
 pub struct RepeatedWorkspace {
     #[pb(index = 1)]

+ 6 - 16
rust-lib/flowy-workspace-infra/src/entities/workspace/workspace_query.rs

@@ -20,34 +20,24 @@ impl QueryWorkspaceRequest {
 
 // Read all workspaces if the workspace_id is None
 #[derive(Clone, ProtoBuf, Default, Debug)]
-pub struct QueryWorkspaceParams {
+pub struct WorkspaceIdentifier {
     #[pb(index = 1, one_of)]
     pub workspace_id: Option<String>,
 }
 
-impl QueryWorkspaceParams {
-    pub fn new() -> Self {
-        Self {
-            workspace_id: None,
-            ..Default::default()
-        }
-    }
-
-    pub fn workspace_id(mut self, workspace_id: &str) -> Self {
-        self.workspace_id = Some(workspace_id.to_string());
-        self
-    }
+impl WorkspaceIdentifier {
+    pub fn new(workspace_id: Option<String>) -> Self { Self { workspace_id } }
 }
 
-impl TryInto<QueryWorkspaceParams> for QueryWorkspaceRequest {
+impl TryInto<WorkspaceIdentifier> for QueryWorkspaceRequest {
     type Error = ErrorCode;
 
-    fn try_into(self) -> Result<QueryWorkspaceParams, Self::Error> {
+    fn try_into(self) -> Result<WorkspaceIdentifier, Self::Error> {
         let workspace_id = match self.workspace_id {
             None => None,
             Some(workspace_id) => Some(WorkspaceId::parse(workspace_id)?.0),
         };
 
-        Ok(QueryWorkspaceParams { workspace_id })
+        Ok(WorkspaceIdentifier { workspace_id })
     }
 }

+ 34 - 34
rust-lib/flowy-workspace-infra/src/protobuf/model/workspace_query.rs

@@ -222,27 +222,27 @@ impl ::protobuf::reflect::ProtobufValue for QueryWorkspaceRequest {
 }
 
 #[derive(PartialEq,Clone,Default)]
-pub struct QueryWorkspaceParams {
+pub struct WorkspaceIdentifier {
     // message oneof groups
-    pub one_of_workspace_id: ::std::option::Option<QueryWorkspaceParams_oneof_one_of_workspace_id>,
+    pub one_of_workspace_id: ::std::option::Option<WorkspaceIdentifier_oneof_one_of_workspace_id>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a QueryWorkspaceParams {
-    fn default() -> &'a QueryWorkspaceParams {
-        <QueryWorkspaceParams as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a WorkspaceIdentifier {
+    fn default() -> &'a WorkspaceIdentifier {
+        <WorkspaceIdentifier as ::protobuf::Message>::default_instance()
     }
 }
 
 #[derive(Clone,PartialEq,Debug)]
-pub enum QueryWorkspaceParams_oneof_one_of_workspace_id {
+pub enum WorkspaceIdentifier_oneof_one_of_workspace_id {
     workspace_id(::std::string::String),
 }
 
-impl QueryWorkspaceParams {
-    pub fn new() -> QueryWorkspaceParams {
+impl WorkspaceIdentifier {
+    pub fn new() -> WorkspaceIdentifier {
         ::std::default::Default::default()
     }
 
@@ -251,7 +251,7 @@ impl QueryWorkspaceParams {
 
     pub fn get_workspace_id(&self) -> &str {
         match self.one_of_workspace_id {
-            ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(ref v)) => v,
+            ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(ref v)) => v,
             _ => "",
         }
     }
@@ -261,24 +261,24 @@ impl QueryWorkspaceParams {
 
     pub fn has_workspace_id(&self) -> bool {
         match self.one_of_workspace_id {
-            ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(..)) => true,
+            ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(..)) => true,
             _ => false,
         }
     }
 
     // Param is passed by value, moved
     pub fn set_workspace_id(&mut self, v: ::std::string::String) {
-        self.one_of_workspace_id = ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(v))
+        self.one_of_workspace_id = ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(v))
     }
 
     // Mutable pointer to the field.
     pub fn mut_workspace_id(&mut self) -> &mut ::std::string::String {
-        if let ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(_)) = self.one_of_workspace_id {
+        if let ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(_)) = self.one_of_workspace_id {
         } else {
-            self.one_of_workspace_id = ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(::std::string::String::new()));
+            self.one_of_workspace_id = ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(::std::string::String::new()));
         }
         match self.one_of_workspace_id {
-            ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(ref mut v)) => v,
+            ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(ref mut v)) => v,
             _ => panic!(),
         }
     }
@@ -287,7 +287,7 @@ impl QueryWorkspaceParams {
     pub fn take_workspace_id(&mut self) -> ::std::string::String {
         if self.has_workspace_id() {
             match self.one_of_workspace_id.take() {
-                ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(v)) => v,
+                ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(v)) => v,
                 _ => panic!(),
             }
         } else {
@@ -296,7 +296,7 @@ impl QueryWorkspaceParams {
     }
 }
 
-impl ::protobuf::Message for QueryWorkspaceParams {
+impl ::protobuf::Message for WorkspaceIdentifier {
     fn is_initialized(&self) -> bool {
         true
     }
@@ -309,7 +309,7 @@ impl ::protobuf::Message for QueryWorkspaceParams {
                     if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
-                    self.one_of_workspace_id = ::std::option::Option::Some(QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(is.read_string()?));
+                    self.one_of_workspace_id = ::std::option::Option::Some(WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(is.read_string()?));
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -325,7 +325,7 @@ impl ::protobuf::Message for QueryWorkspaceParams {
         let mut my_size = 0;
         if let ::std::option::Option::Some(ref v) = self.one_of_workspace_id {
             match v {
-                &QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(ref v) => {
+                &WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(ref v) => {
                     my_size += ::protobuf::rt::string_size(1, &v);
                 },
             };
@@ -338,7 +338,7 @@ impl ::protobuf::Message for QueryWorkspaceParams {
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
         if let ::std::option::Option::Some(ref v) = self.one_of_workspace_id {
             match v {
-                &QueryWorkspaceParams_oneof_one_of_workspace_id::workspace_id(ref v) => {
+                &WorkspaceIdentifier_oneof_one_of_workspace_id::workspace_id(ref v) => {
                     os.write_string(1, v)?;
                 },
             };
@@ -373,8 +373,8 @@ impl ::protobuf::Message for QueryWorkspaceParams {
         Self::descriptor_static()
     }
 
-    fn new() -> QueryWorkspaceParams {
-        QueryWorkspaceParams::new()
+    fn new() -> WorkspaceIdentifier {
+        WorkspaceIdentifier::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -383,37 +383,37 @@ impl ::protobuf::Message for QueryWorkspaceParams {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
                 "workspace_id",
-                QueryWorkspaceParams::has_workspace_id,
-                QueryWorkspaceParams::get_workspace_id,
+                WorkspaceIdentifier::has_workspace_id,
+                WorkspaceIdentifier::get_workspace_id,
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryWorkspaceParams>(
-                "QueryWorkspaceParams",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<WorkspaceIdentifier>(
+                "WorkspaceIdentifier",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static QueryWorkspaceParams {
-        static instance: ::protobuf::rt::LazyV2<QueryWorkspaceParams> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(QueryWorkspaceParams::new)
+    fn default_instance() -> &'static WorkspaceIdentifier {
+        static instance: ::protobuf::rt::LazyV2<WorkspaceIdentifier> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(WorkspaceIdentifier::new)
     }
 }
 
-impl ::protobuf::Clear for QueryWorkspaceParams {
+impl ::protobuf::Clear for WorkspaceIdentifier {
     fn clear(&mut self) {
         self.one_of_workspace_id = ::std::option::Option::None;
         self.unknown_fields.clear();
     }
 }
 
-impl ::std::fmt::Debug for QueryWorkspaceParams {
+impl ::std::fmt::Debug for WorkspaceIdentifier {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for QueryWorkspaceParams {
+impl ::protobuf::reflect::ProtobufValue for WorkspaceIdentifier {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -422,15 +422,15 @@ impl ::protobuf::reflect::ProtobufValue for QueryWorkspaceParams {
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x15workspace_query.proto\"S\n\x15QueryWorkspaceRequest\x12#\n\x0cwork\
     space_id\x18\x01\x20\x01(\tH\0R\x0bworkspaceIdB\x15\n\x13one_of_workspac\
-    e_id\"R\n\x14QueryWorkspaceParams\x12#\n\x0cworkspace_id\x18\x01\x20\x01\
-    (\tH\0R\x0bworkspaceIdB\x15\n\x13one_of_workspace_idJ\xe6\x01\n\x06\x12\
+    e_id\"Q\n\x13WorkspaceIdentifier\x12#\n\x0cworkspace_id\x18\x01\x20\x01(\
+    \tH\0R\x0bworkspaceIdB\x15\n\x13one_of_workspace_idJ\xe6\x01\n\x06\x12\
     \x04\0\0\x07\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\
     \x08\0\x12\x03\x03\x04:\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\x03\n\x1d\n\
     \x0b\n\x04\x04\0\x02\0\x12\x03\x03\x208\n\x0c\n\x05\x04\0\x02\0\x05\x12\
     \x03\x03\x20&\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03'3\n\x0c\n\x05\x04\
     \0\x02\0\x03\x12\x03\x0367\n\n\n\x02\x04\x01\x12\x04\x05\0\x07\x01\n\n\n\
-    \x03\x04\x01\x01\x12\x03\x05\x08\x1c\n\x0b\n\x04\x04\x01\x08\0\x12\x03\
+    \x03\x04\x01\x01\x12\x03\x05\x08\x1b\n\x0b\n\x04\x04\x01\x08\0\x12\x03\
     \x06\x04:\n\x0c\n\x05\x04\x01\x08\0\x01\x12\x03\x06\n\x1d\n\x0b\n\x04\
     \x04\x01\x02\0\x12\x03\x06\x208\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\
     \x06\x20&\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06'3\n\x0c\n\x05\x04\

+ 1 - 1
rust-lib/flowy-workspace-infra/src/protobuf/proto/workspace_query.proto

@@ -3,6 +3,6 @@ syntax = "proto3";
 message QueryWorkspaceRequest {
     oneof one_of_workspace_id { string workspace_id = 1; };
 }
-message QueryWorkspaceParams {
+message WorkspaceIdentifier {
     oneof one_of_workspace_id { string workspace_id = 1; };
 }

+ 0 - 1
rust-lib/flowy-workspace-infra/src/user_default.rs

@@ -4,7 +4,6 @@ use crate::entities::{
     workspace::Workspace,
 };
 use chrono::Utc;
-use uuid::Uuid;
 
 pub fn create_default_workspace(time: chrono::DateTime<Utc>) -> Workspace {
     let workspace_id = uuid::Uuid::new_v4();

+ 1 - 1
rust-lib/flowy-workspace/Cargo.toml

@@ -39,7 +39,7 @@ tracing = { version = "0.1", features = ["log"] }
 bytes = { version = "1.0" }
 crossbeam = "0.8.1"
 crossbeam-utils = "0.8"
-
+chrono = "0.4"
 
 [dev-dependencies]
 flowy-test = { path = "../flowy-test" }

+ 3 - 0
rust-lib/flowy-workspace/src/event.rs

@@ -22,6 +22,9 @@ pub enum WorkspaceEvent {
     #[event(input = "QueryWorkspaceRequest", output = "RepeatedApp")]
     ReadWorkspaceApps = 5,
 
+    #[event(output = "WorkspaceIdentifier")]
+    CreateDefaultWorkspace = 6,
+
     #[event(input = "CreateAppRequest", output = "App")]
     CreateApp         = 101,
 

+ 1 - 1
rust-lib/flowy-workspace/src/handlers/app_handler.rs

@@ -22,7 +22,7 @@ pub(crate) async fn create_app_handler(
     controller: Unit<Arc<AppController>>,
 ) -> DataResult<App, WorkspaceError> {
     let params: CreateAppParams = data.into_inner().try_into()?;
-    let detail = controller.create_app(params).await?;
+    let detail = controller.create_app_from_params(params).await?;
 
     data_result(detail)
 }

+ 1 - 1
rust-lib/flowy-workspace/src/handlers/view_handler.rs

@@ -24,7 +24,7 @@ pub(crate) async fn create_view_handler(
     controller: Unit<Arc<ViewController>>,
 ) -> DataResult<View, WorkspaceError> {
     let params: CreateViewParams = data.into_inner().try_into()?;
-    let view = controller.create_view(params).await?;
+    let view = controller.create_view_from_params(params).await?;
     data_result(view)
 }
 

+ 34 - 5
rust-lib/flowy-workspace/src/handlers/workspace_handler.rs

@@ -1,9 +1,13 @@
 use crate::{
-    entities::{app::RepeatedApp, workspace::*},
     errors::WorkspaceError,
-    services::WorkspaceController,
+    services::{AppController, ViewController, WorkspaceController},
 };
+use chrono::Utc;
 use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
+use flowy_workspace_infra::{
+    entities::{app::RepeatedApp, workspace::*},
+    user_default,
+};
 use std::{convert::TryInto, sync::Arc};
 
 #[tracing::instrument(skip(controller), err)]
@@ -19,7 +23,7 @@ pub(crate) async fn create_workspace_handler(
 ) -> DataResult<Workspace, WorkspaceError> {
     let controller = controller.get_ref().clone();
     let params: CreateWorkspaceParams = data.into_inner().try_into()?;
-    let detail = controller.create_workspace(params).await?;
+    let detail = controller.create_workspace_from_params(params).await?;
     data_result(detail)
 }
 
@@ -39,12 +43,37 @@ pub(crate) async fn read_workspace_apps_handler(
     data_result(repeated_app)
 }
 
+#[tracing::instrument(skip(workspace_controller, app_controller, view_controller), err)]
+pub(crate) async fn create_default_workspace_handler(
+    workspace_controller: Unit<Arc<WorkspaceController>>,
+    app_controller: Unit<Arc<AppController>>,
+    view_controller: Unit<Arc<ViewController>>,
+) -> DataResult<WorkspaceIdentifier, WorkspaceError> {
+    let time = Utc::now();
+    let mut workspace = user_default::create_default_workspace(time);
+    let workspace_id = workspace.id.clone();
+    let apps = workspace.take_apps().into_inner();
+
+    let _ = workspace_controller.create_workspace(workspace).await?;
+    for mut app in apps {
+        let views = app.take_belongings().into_inner();
+        let _ = app_controller.create_app(app).await?;
+        for view in views {
+            let _ = view_controller.create_view(view).await?;
+        }
+    }
+
+    data_result(WorkspaceIdentifier {
+        workspace_id: Some(workspace_id),
+    })
+}
+
 #[tracing::instrument(skip(data, controller), err)]
 pub(crate) async fn read_workspaces_handler(
     data: Data<QueryWorkspaceRequest>,
     controller: Unit<Arc<WorkspaceController>>,
 ) -> DataResult<RepeatedWorkspace, WorkspaceError> {
-    let params: QueryWorkspaceParams = data.into_inner().try_into()?;
+    let params: WorkspaceIdentifier = data.into_inner().try_into()?;
     let workspaces = controller.read_workspaces(params).await?;
     data_result(workspaces)
 }
@@ -54,7 +83,7 @@ pub(crate) async fn open_workspace_handler(
     data: Data<QueryWorkspaceRequest>,
     controller: Unit<Arc<WorkspaceController>>,
 ) -> DataResult<Workspace, WorkspaceError> {
-    let params: QueryWorkspaceParams = data.into_inner().try_into()?;
+    let params: WorkspaceIdentifier = data.into_inner().try_into()?;
     let workspaces = controller.open_workspace(params).await?;
     data_result(workspaces)
 }

+ 2 - 1
rust-lib/flowy-workspace/src/module.rs

@@ -80,7 +80,8 @@ pub fn create(workspace: Arc<WorkspaceController>) -> Module {
         .event(WorkspaceEvent::ReadCurWorkspace, read_cur_workspace_handler)
         .event(WorkspaceEvent::ReadWorkspaces, read_workspaces_handler)
         .event(WorkspaceEvent::OpenWorkspace, open_workspace_handler)
-        .event(WorkspaceEvent::ReadWorkspaceApps, read_workspace_apps_handler);
+        .event(WorkspaceEvent::ReadWorkspaceApps, read_workspace_apps_handler)
+        .event(WorkspaceEvent::CreateDefaultWorkspace, create_default_workspace_handler);
 
     module = module
         .event(WorkspaceEvent::CreateApp, create_app_handler)

+ 69 - 64
rust-lib/flowy-workspace/src/protobuf/model/event.rs

@@ -31,6 +31,7 @@ pub enum WorkspaceEvent {
     DeleteWorkspace = 3,
     OpenWorkspace = 4,
     ReadWorkspaceApps = 5,
+    CreateDefaultWorkspace = 6,
     CreateApp = 101,
     DeleteApp = 102,
     ReadApp = 103,
@@ -65,6 +66,7 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             3 => ::std::option::Option::Some(WorkspaceEvent::DeleteWorkspace),
             4 => ::std::option::Option::Some(WorkspaceEvent::OpenWorkspace),
             5 => ::std::option::Option::Some(WorkspaceEvent::ReadWorkspaceApps),
+            6 => ::std::option::Option::Some(WorkspaceEvent::CreateDefaultWorkspace),
             101 => ::std::option::Option::Some(WorkspaceEvent::CreateApp),
             102 => ::std::option::Option::Some(WorkspaceEvent::DeleteApp),
             103 => ::std::option::Option::Some(WorkspaceEvent::ReadApp),
@@ -96,6 +98,7 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             WorkspaceEvent::DeleteWorkspace,
             WorkspaceEvent::OpenWorkspace,
             WorkspaceEvent::ReadWorkspaceApps,
+            WorkspaceEvent::CreateDefaultWorkspace,
             WorkspaceEvent::CreateApp,
             WorkspaceEvent::DeleteApp,
             WorkspaceEvent::ReadApp,
@@ -143,72 +146,74 @@ impl ::protobuf::reflect::ProtobufValue for WorkspaceEvent {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0bevent.proto*\xca\x03\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\
+    \n\x0bevent.proto*\xe6\x03\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\
     ace\x10\0\x12\x14\n\x10ReadCurWorkspace\x10\x01\x12\x12\n\x0eReadWorkspa\
     ces\x10\x02\x12\x13\n\x0fDeleteWorkspace\x10\x03\x12\x11\n\rOpenWorkspac\
-    e\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\r\n\tCreateApp\x10e\
-    \x12\r\n\tDeleteApp\x10f\x12\x0b\n\x07ReadApp\x10g\x12\r\n\tUpdateApp\
-    \x10h\x12\x0f\n\nCreateView\x10\xc9\x01\x12\r\n\x08ReadView\x10\xca\x01\
-    \x12\x0f\n\nUpdateView\x10\xcb\x01\x12\x0f\n\nDeleteView\x10\xcc\x01\x12\
-    \x12\n\rDuplicateView\x10\xcd\x01\x12\r\n\x08CopyLink\x10\xce\x01\x12\r\
-    \n\x08OpenView\x10\xcf\x01\x12\x0e\n\tCloseView\x10\xd0\x01\x12\x0e\n\tR\
-    eadTrash\x10\xac\x02\x12\x11\n\x0cPutbackTrash\x10\xad\x02\x12\x10\n\x0b\
-    DeleteTrash\x10\xae\x02\x12\x0f\n\nRestoreAll\x10\xaf\x02\x12\x0e\n\tDel\
-    eteAll\x10\xb0\x02\x12\x12\n\rApplyDocDelta\x10\x90\x03\x12\x12\n\rInitW\
-    orkspace\x10\xe8\x07J\xab\x08\n\x06\x12\x04\0\0\x1c\x01\n\x08\n\x01\x0c\
-    \x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x1c\x01\n\n\n\x03\x05\0\
-    \x01\x12\x03\x02\x05\x13\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x18\n\
-    \x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\x13\n\x0c\n\x05\x05\0\x02\0\
-    \x02\x12\x03\x03\x16\x17\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x19\n\
-    \x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x05\0\x02\
-    \x01\x02\x12\x03\x04\x17\x18\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\
-    \x17\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\x12\n\x0c\n\x05\x05\0\
-    \x02\x02\x02\x12\x03\x05\x15\x16\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\
-    \x04\x18\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x13\n\x0c\n\x05\
-    \x05\0\x02\x03\x02\x12\x03\x06\x16\x17\n\x0b\n\x04\x05\0\x02\x04\x12\x03\
-    \x07\x04\x16\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x11\n\x0c\n\
-    \x05\x05\0\x02\x04\x02\x12\x03\x07\x14\x15\n\x0b\n\x04\x05\0\x02\x05\x12\
-    \x03\x08\x04\x1a\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x15\n\x0c\
-    \n\x05\x05\0\x02\x05\x02\x12\x03\x08\x18\x19\n\x0b\n\x04\x05\0\x02\x06\
-    \x12\x03\t\x04\x14\n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\t\x04\r\n\x0c\n\
-    \x05\x05\0\x02\x06\x02\x12\x03\t\x10\x13\n\x0b\n\x04\x05\0\x02\x07\x12\
-    \x03\n\x04\x14\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\n\x04\r\n\x0c\n\x05\
-    \x05\0\x02\x07\x02\x12\x03\n\x10\x13\n\x0b\n\x04\x05\0\x02\x08\x12\x03\
-    \x0b\x04\x12\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\x0b\x04\x0b\n\x0c\n\
-    \x05\x05\0\x02\x08\x02\x12\x03\x0b\x0e\x11\n\x0b\n\x04\x05\0\x02\t\x12\
-    \x03\x0c\x04\x14\n\x0c\n\x05\x05\0\x02\t\x01\x12\x03\x0c\x04\r\n\x0c\n\
-    \x05\x05\0\x02\t\x02\x12\x03\x0c\x10\x13\n\x0b\n\x04\x05\0\x02\n\x12\x03\
-    \r\x04\x15\n\x0c\n\x05\x05\0\x02\n\x01\x12\x03\r\x04\x0e\n\x0c\n\x05\x05\
-    \0\x02\n\x02\x12\x03\r\x11\x14\n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x0e\x04\
-    \x13\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\x0e\x04\x0c\n\x0c\n\x05\x05\0\
-    \x02\x0b\x02\x12\x03\x0e\x0f\x12\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x0f\
-    \x04\x15\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\x03\x0f\x04\x0e\n\x0c\n\x05\
-    \x05\0\x02\x0c\x02\x12\x03\x0f\x11\x14\n\x0b\n\x04\x05\0\x02\r\x12\x03\
-    \x10\x04\x15\n\x0c\n\x05\x05\0\x02\r\x01\x12\x03\x10\x04\x0e\n\x0c\n\x05\
-    \x05\0\x02\r\x02\x12\x03\x10\x11\x14\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\
-    \x11\x04\x18\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\x03\x11\x04\x11\n\x0c\n\
-    \x05\x05\0\x02\x0e\x02\x12\x03\x11\x14\x17\n\x0b\n\x04\x05\0\x02\x0f\x12\
-    \x03\x12\x04\x13\n\x0c\n\x05\x05\0\x02\x0f\x01\x12\x03\x12\x04\x0c\n\x0c\
-    \n\x05\x05\0\x02\x0f\x02\x12\x03\x12\x0f\x12\n\x0b\n\x04\x05\0\x02\x10\
-    \x12\x03\x13\x04\x13\n\x0c\n\x05\x05\0\x02\x10\x01\x12\x03\x13\x04\x0c\n\
-    \x0c\n\x05\x05\0\x02\x10\x02\x12\x03\x13\x0f\x12\n\x0b\n\x04\x05\0\x02\
-    \x11\x12\x03\x14\x04\x14\n\x0c\n\x05\x05\0\x02\x11\x01\x12\x03\x14\x04\r\
-    \n\x0c\n\x05\x05\0\x02\x11\x02\x12\x03\x14\x10\x13\n\x0b\n\x04\x05\0\x02\
-    \x12\x12\x03\x15\x04\x14\n\x0c\n\x05\x05\0\x02\x12\x01\x12\x03\x15\x04\r\
-    \n\x0c\n\x05\x05\0\x02\x12\x02\x12\x03\x15\x10\x13\n\x0b\n\x04\x05\0\x02\
-    \x13\x12\x03\x16\x04\x17\n\x0c\n\x05\x05\0\x02\x13\x01\x12\x03\x16\x04\
-    \x10\n\x0c\n\x05\x05\0\x02\x13\x02\x12\x03\x16\x13\x16\n\x0b\n\x04\x05\0\
-    \x02\x14\x12\x03\x17\x04\x16\n\x0c\n\x05\x05\0\x02\x14\x01\x12\x03\x17\
-    \x04\x0f\n\x0c\n\x05\x05\0\x02\x14\x02\x12\x03\x17\x12\x15\n\x0b\n\x04\
-    \x05\0\x02\x15\x12\x03\x18\x04\x15\n\x0c\n\x05\x05\0\x02\x15\x01\x12\x03\
-    \x18\x04\x0e\n\x0c\n\x05\x05\0\x02\x15\x02\x12\x03\x18\x11\x14\n\x0b\n\
-    \x04\x05\0\x02\x16\x12\x03\x19\x04\x14\n\x0c\n\x05\x05\0\x02\x16\x01\x12\
-    \x03\x19\x04\r\n\x0c\n\x05\x05\0\x02\x16\x02\x12\x03\x19\x10\x13\n\x0b\n\
-    \x04\x05\0\x02\x17\x12\x03\x1a\x04\x18\n\x0c\n\x05\x05\0\x02\x17\x01\x12\
-    \x03\x1a\x04\x11\n\x0c\n\x05\x05\0\x02\x17\x02\x12\x03\x1a\x14\x17\n\x0b\
-    \n\x04\x05\0\x02\x18\x12\x03\x1b\x04\x19\n\x0c\n\x05\x05\0\x02\x18\x01\
-    \x12\x03\x1b\x04\x11\n\x0c\n\x05\x05\0\x02\x18\x02\x12\x03\x1b\x14\x18b\
-    \x06proto3\
+    e\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\x1a\n\x16CreateDefa\
+    ultWorkspace\x10\x06\x12\r\n\tCreateApp\x10e\x12\r\n\tDeleteApp\x10f\x12\
+    \x0b\n\x07ReadApp\x10g\x12\r\n\tUpdateApp\x10h\x12\x0f\n\nCreateView\x10\
+    \xc9\x01\x12\r\n\x08ReadView\x10\xca\x01\x12\x0f\n\nUpdateView\x10\xcb\
+    \x01\x12\x0f\n\nDeleteView\x10\xcc\x01\x12\x12\n\rDuplicateView\x10\xcd\
+    \x01\x12\r\n\x08CopyLink\x10\xce\x01\x12\r\n\x08OpenView\x10\xcf\x01\x12\
+    \x0e\n\tCloseView\x10\xd0\x01\x12\x0e\n\tReadTrash\x10\xac\x02\x12\x11\n\
+    \x0cPutbackTrash\x10\xad\x02\x12\x10\n\x0bDeleteTrash\x10\xae\x02\x12\
+    \x0f\n\nRestoreAll\x10\xaf\x02\x12\x0e\n\tDeleteAll\x10\xb0\x02\x12\x12\
+    \n\rApplyDocDelta\x10\x90\x03\x12\x12\n\rInitWorkspace\x10\xe8\x07J\xd4\
+    \x08\n\x06\x12\x04\0\0\x1d\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
+    \x05\0\x12\x04\x02\0\x1d\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x13\n\
+    \x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\x05\x05\0\x02\0\x01\
+    \x12\x03\x03\x04\x13\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x16\x17\n\
+    \x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x19\n\x0c\n\x05\x05\0\x02\x01\
+    \x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x17\
+    \x18\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x17\n\x0c\n\x05\x05\0\x02\
+    \x02\x01\x12\x03\x05\x04\x12\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\
+    \x15\x16\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x18\n\x0c\n\x05\x05\0\
+    \x02\x03\x01\x12\x03\x06\x04\x13\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\
+    \x06\x16\x17\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\
+    \x05\0\x02\x04\x01\x12\x03\x07\x04\x11\n\x0c\n\x05\x05\0\x02\x04\x02\x12\
+    \x03\x07\x14\x15\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x1a\n\x0c\n\
+    \x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x15\n\x0c\n\x05\x05\0\x02\x05\x02\
+    \x12\x03\x08\x18\x19\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x1f\n\x0c\n\
+    \x05\x05\0\x02\x06\x01\x12\x03\t\x04\x1a\n\x0c\n\x05\x05\0\x02\x06\x02\
+    \x12\x03\t\x1d\x1e\n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x14\n\x0c\n\
+    \x05\x05\0\x02\x07\x01\x12\x03\n\x04\r\n\x0c\n\x05\x05\0\x02\x07\x02\x12\
+    \x03\n\x10\x13\n\x0b\n\x04\x05\0\x02\x08\x12\x03\x0b\x04\x14\n\x0c\n\x05\
+    \x05\0\x02\x08\x01\x12\x03\x0b\x04\r\n\x0c\n\x05\x05\0\x02\x08\x02\x12\
+    \x03\x0b\x10\x13\n\x0b\n\x04\x05\0\x02\t\x12\x03\x0c\x04\x12\n\x0c\n\x05\
+    \x05\0\x02\t\x01\x12\x03\x0c\x04\x0b\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\
+    \x0c\x0e\x11\n\x0b\n\x04\x05\0\x02\n\x12\x03\r\x04\x14\n\x0c\n\x05\x05\0\
+    \x02\n\x01\x12\x03\r\x04\r\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\r\x10\x13\
+    \n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x0e\x04\x15\n\x0c\n\x05\x05\0\x02\x0b\
+    \x01\x12\x03\x0e\x04\x0e\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x0e\x11\
+    \x14\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x0f\x04\x13\n\x0c\n\x05\x05\0\x02\
+    \x0c\x01\x12\x03\x0f\x04\x0c\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x0f\
+    \x0f\x12\n\x0b\n\x04\x05\0\x02\r\x12\x03\x10\x04\x15\n\x0c\n\x05\x05\0\
+    \x02\r\x01\x12\x03\x10\x04\x0e\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x10\
+    \x11\x14\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\x11\x04\x15\n\x0c\n\x05\x05\0\
+    \x02\x0e\x01\x12\x03\x11\x04\x0e\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\
+    \x11\x11\x14\n\x0b\n\x04\x05\0\x02\x0f\x12\x03\x12\x04\x18\n\x0c\n\x05\
+    \x05\0\x02\x0f\x01\x12\x03\x12\x04\x11\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\
+    \x03\x12\x14\x17\n\x0b\n\x04\x05\0\x02\x10\x12\x03\x13\x04\x13\n\x0c\n\
+    \x05\x05\0\x02\x10\x01\x12\x03\x13\x04\x0c\n\x0c\n\x05\x05\0\x02\x10\x02\
+    \x12\x03\x13\x0f\x12\n\x0b\n\x04\x05\0\x02\x11\x12\x03\x14\x04\x13\n\x0c\
+    \n\x05\x05\0\x02\x11\x01\x12\x03\x14\x04\x0c\n\x0c\n\x05\x05\0\x02\x11\
+    \x02\x12\x03\x14\x0f\x12\n\x0b\n\x04\x05\0\x02\x12\x12\x03\x15\x04\x14\n\
+    \x0c\n\x05\x05\0\x02\x12\x01\x12\x03\x15\x04\r\n\x0c\n\x05\x05\0\x02\x12\
+    \x02\x12\x03\x15\x10\x13\n\x0b\n\x04\x05\0\x02\x13\x12\x03\x16\x04\x14\n\
+    \x0c\n\x05\x05\0\x02\x13\x01\x12\x03\x16\x04\r\n\x0c\n\x05\x05\0\x02\x13\
+    \x02\x12\x03\x16\x10\x13\n\x0b\n\x04\x05\0\x02\x14\x12\x03\x17\x04\x17\n\
+    \x0c\n\x05\x05\0\x02\x14\x01\x12\x03\x17\x04\x10\n\x0c\n\x05\x05\0\x02\
+    \x14\x02\x12\x03\x17\x13\x16\n\x0b\n\x04\x05\0\x02\x15\x12\x03\x18\x04\
+    \x16\n\x0c\n\x05\x05\0\x02\x15\x01\x12\x03\x18\x04\x0f\n\x0c\n\x05\x05\0\
+    \x02\x15\x02\x12\x03\x18\x12\x15\n\x0b\n\x04\x05\0\x02\x16\x12\x03\x19\
+    \x04\x15\n\x0c\n\x05\x05\0\x02\x16\x01\x12\x03\x19\x04\x0e\n\x0c\n\x05\
+    \x05\0\x02\x16\x02\x12\x03\x19\x11\x14\n\x0b\n\x04\x05\0\x02\x17\x12\x03\
+    \x1a\x04\x14\n\x0c\n\x05\x05\0\x02\x17\x01\x12\x03\x1a\x04\r\n\x0c\n\x05\
+    \x05\0\x02\x17\x02\x12\x03\x1a\x10\x13\n\x0b\n\x04\x05\0\x02\x18\x12\x03\
+    \x1b\x04\x18\n\x0c\n\x05\x05\0\x02\x18\x01\x12\x03\x1b\x04\x11\n\x0c\n\
+    \x05\x05\0\x02\x18\x02\x12\x03\x1b\x14\x17\n\x0b\n\x04\x05\0\x02\x19\x12\
+    \x03\x1c\x04\x19\n\x0c\n\x05\x05\0\x02\x19\x01\x12\x03\x1c\x04\x11\n\x0c\
+    \n\x05\x05\0\x02\x19\x02\x12\x03\x1c\x14\x18b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 0
rust-lib/flowy-workspace/src/protobuf/proto/event.proto

@@ -7,6 +7,7 @@ enum WorkspaceEvent {
     DeleteWorkspace = 3;
     OpenWorkspace = 4;
     ReadWorkspaceApps = 5;
+    CreateDefaultWorkspace = 6;
     CreateApp = 101;
     DeleteApp = 102;
     ReadApp = 103;

+ 5 - 2
rust-lib/flowy-workspace/src/services/app_controller.rs

@@ -44,10 +44,13 @@ impl AppController {
     }
 
     #[tracing::instrument(level = "debug", skip(self, params), fields(name = %params.name) err)]
-    pub(crate) async fn create_app(&self, params: CreateAppParams) -> Result<App, WorkspaceError> {
+    pub(crate) async fn create_app_from_params(&self, params: CreateAppParams) -> Result<App, WorkspaceError> {
         let app = self.create_app_on_server(params).await?;
-        let conn = &*self.database.db_connection()?;
+        self.create_app(app).await
+    }
 
+    pub(crate) async fn create_app(&self, app: App) -> Result<App, WorkspaceError> {
+        let conn = &*self.database.db_connection()?;
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
             let _ = self.save_app(app.clone(), &*conn)?;
             let _ = notify_apps_changed(&app.workspace_id, self.trash_can.clone(), conn)?;

+ 2 - 2
rust-lib/flowy-workspace/src/services/server/mod.rs

@@ -13,10 +13,10 @@ use crate::{
         workspace::{
             CreateWorkspaceParams,
             DeleteWorkspaceParams,
-            QueryWorkspaceParams,
             RepeatedWorkspace,
             UpdateWorkspaceParams,
             Workspace,
+            WorkspaceIdentifier,
         },
     },
     errors::WorkspaceError,
@@ -36,7 +36,7 @@ pub trait WorkspaceServerAPI {
     fn read_workspace(
         &self,
         token: &str,
-        params: QueryWorkspaceParams,
+        params: WorkspaceIdentifier,
     ) -> ResultFuture<RepeatedWorkspace, WorkspaceError>;
 
     fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError>;

+ 2 - 2
rust-lib/flowy-workspace/src/services/server/server_api.rs

@@ -6,10 +6,10 @@ use crate::{
         workspace::{
             CreateWorkspaceParams,
             DeleteWorkspaceParams,
-            QueryWorkspaceParams,
             RepeatedWorkspace,
             UpdateWorkspaceParams,
             Workspace,
+            WorkspaceIdentifier,
         },
     },
     errors::WorkspaceError,
@@ -59,7 +59,7 @@ impl WorkspaceServerAPI for WorkspaceServer {
     fn read_workspace(
         &self,
         token: &str,
-        params: QueryWorkspaceParams,
+        params: WorkspaceIdentifier,
     ) -> ResultFuture<RepeatedWorkspace, WorkspaceError> {
         let token = token.to_owned();
         let url = self.config.workspace_url();

+ 2 - 2
rust-lib/flowy-workspace/src/services/server/server_api_mock.rs

@@ -6,10 +6,10 @@ use crate::{
         workspace::{
             CreateWorkspaceParams,
             DeleteWorkspaceParams,
-            QueryWorkspaceParams,
             RepeatedWorkspace,
             UpdateWorkspaceParams,
             Workspace,
+            WorkspaceIdentifier,
         },
     },
     errors::WorkspaceError,
@@ -39,7 +39,7 @@ impl WorkspaceServerAPI for WorkspaceServerMock {
     fn read_workspace(
         &self,
         _token: &str,
-        _params: QueryWorkspaceParams,
+        _params: WorkspaceIdentifier,
     ) -> ResultFuture<RepeatedWorkspace, WorkspaceError> {
         ResultFuture::new(async {
             let repeated_workspace = RepeatedWorkspace { items: vec![] };

+ 6 - 2
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -52,8 +52,12 @@ impl ViewController {
     }
 
     #[tracing::instrument(level = "debug", skip(self, params), fields(name = %params.name), err)]
-    pub(crate) async fn create_view(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
+    pub(crate) async fn create_view_from_params(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
         let view = self.create_view_on_server(params.clone()).await?;
+        self.create_view(view).await
+    }
+
+    pub(crate) async fn create_view(&self, view: View) -> Result<View, WorkspaceError> {
         let conn = &*self.database.db_connection()?;
         let trash_can = self.trash_can.clone();
 
@@ -130,7 +134,7 @@ impl ViewController {
             data: delta_data.data,
         };
 
-        let _ = self.create_view(duplicate_params).await?;
+        let _ = self.create_view_from_params(duplicate_params).await?;
         Ok(())
     }
 

+ 18 - 11
rust-lib/flowy-workspace/src/services/workspace_controller.rs

@@ -1,16 +1,14 @@
-use std::sync::Arc;
-
-use flowy_database::SqliteConnection;
-use flowy_infra::kv::KV;
-
 use crate::{
-    entities::{app::RepeatedApp, workspace::*},
     errors::*,
     module::{WorkspaceDatabase, WorkspaceUser},
     notify::*,
     services::{helper::spawn, read_local_workspace_apps, server::Server, AppController, TrashCan, ViewController},
     sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql},
 };
+use flowy_database::SqliteConnection;
+use flowy_infra::kv::KV;
+use flowy_workspace_infra::entities::{app::RepeatedApp, workspace::*};
+use std::sync::Arc;
 
 pub struct WorkspaceController {
     pub user: Arc<dyn WorkspaceUser>,
@@ -51,8 +49,15 @@ impl WorkspaceController {
         Ok(())
     }
 
-    pub(crate) async fn create_workspace(&self, params: CreateWorkspaceParams) -> Result<Workspace, WorkspaceError> {
+    pub(crate) async fn create_workspace_from_params(
+        &self,
+        params: CreateWorkspaceParams,
+    ) -> Result<Workspace, WorkspaceError> {
         let workspace = self.create_workspace_on_server(params.clone()).await?;
+        self.create_workspace(workspace).await
+    }
+
+    pub(crate) async fn create_workspace(&self, workspace: Workspace) -> Result<Workspace, WorkspaceError> {
         let user_id = self.user.user_id()?;
         let token = self.user.token()?;
         let workspace_table = WorkspaceTable::new(workspace.clone(), &user_id);
@@ -78,6 +83,8 @@ impl WorkspaceController {
             Ok(())
         })?;
 
+        set_current_workspace(&workspace.id);
+
         Ok(workspace)
     }
 
@@ -121,7 +128,7 @@ impl WorkspaceController {
         Ok(())
     }
 
-    pub(crate) async fn open_workspace(&self, params: QueryWorkspaceParams) -> Result<Workspace, WorkspaceError> {
+    pub(crate) async fn open_workspace(&self, params: WorkspaceIdentifier) -> Result<Workspace, WorkspaceError> {
         let user_id = self.user.user_id()?;
         let conn = self.database.db_connection()?;
         if let Some(workspace_id) = params.workspace_id.clone() {
@@ -135,7 +142,7 @@ impl WorkspaceController {
 
     pub(crate) async fn read_workspaces(
         &self,
-        params: QueryWorkspaceParams,
+        params: WorkspaceIdentifier,
     ) -> Result<RepeatedWorkspace, WorkspaceError> {
         let user_id = self.user.user_id()?;
         let workspaces =
@@ -147,7 +154,7 @@ impl WorkspaceController {
     pub(crate) async fn read_current_workspace(&self) -> Result<Workspace, WorkspaceError> {
         let workspace_id = get_current_workspace()?;
         let user_id = self.user.user_id()?;
-        let params = QueryWorkspaceParams {
+        let params = WorkspaceIdentifier {
             workspace_id: Some(workspace_id.clone()),
         };
         let workspace = self.read_local_workspace(workspace_id, &user_id, &*self.database.db_connection()?)?;
@@ -256,7 +263,7 @@ impl WorkspaceController {
     }
 
     #[tracing::instrument(level = "debug", skip(self), err)]
-    fn read_workspaces_on_server(&self, user_id: String, params: QueryWorkspaceParams) -> Result<(), WorkspaceError> {
+    fn read_workspaces_on_server(&self, user_id: String, params: WorkspaceIdentifier) -> Result<(), WorkspaceError> {
         let (token, server) = self.token_with_server()?;
         let workspace_sql = self.workspace_sql.clone();
         let app_ctrl = self.app_controller.clone();