diff --git a/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt b/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt
index 6196b8582aaf176ec17cd7ee5c1fb78d0b92d09b..555ab446f4bc5e907beb2c533435782ad7070556 100644
--- a/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt
+++ b/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt
@@ -6,8 +6,8 @@ import androidx.core.content.getSystemService
 import androidx.core.net.ConnectivityManagerCompat
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.test.task.BaseNotificationTest
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 class NotificationsBackgroundRestrictionsTest @Inject constructor(
@@ -23,7 +23,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor(
                             R.string.settings_troubleshoot_test_bg_restricted_failed,
                             "RESTRICT_BACKGROUND_STATUS_ENABLED"
                         )
-                        status = NotificationTestStatus.FAILED
+                        status = TaskStatus.FAILED
                         quickFix = null
                     }
 
@@ -32,7 +32,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor(
                             R.string.settings_troubleshoot_test_bg_restricted_success,
                             "RESTRICT_BACKGROUND_STATUS_WHITELISTED"
                         )
-                        status = NotificationTestStatus.SUCCESS
+                        status = TaskStatus.SUCCESS
                         quickFix = null
                     }
 
@@ -41,7 +41,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor(
                             R.string.settings_troubleshoot_test_bg_restricted_success,
                             "RESTRICT_BACKGROUND_STATUS_DISABLED"
                         )
-                        status = NotificationTestStatus.SUCCESS
+                        status = TaskStatus.SUCCESS
                         quickFix = null
                     }
                 }
@@ -50,7 +50,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor(
                     R.string.settings_troubleshoot_test_bg_restricted_success,
                     ""
                 )
-                status = NotificationTestStatus.SUCCESS
+                status = TaskStatus.SUCCESS
                 quickFix = null
             }
         }
diff --git a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt
index c1f865524e1011c9e89b93ad3862a25da71d19a5..8200414359039dac25cf8c15ac7b8e32c0a37986 100644
--- a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt
+++ b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt
@@ -3,10 +3,10 @@ package org.futo.circles.notifications.test
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.feature.notifications.FcmHelper
 import org.futo.circles.feature.notifications.test.task.BaseNotificationTest
-import org.futo.circles.model.NotificationTestStatus
 import org.matrix.android.sdk.api.session.pushers.PusherState
 import javax.inject.Inject
 
@@ -17,11 +17,11 @@ class NotificationTestTokenRegistration @Inject constructor(
 
     override fun perform() {
         val fcmToken = fcmHelper.getFcmToken() ?: run {
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
             return
         }
         val session = MatrixSessionProvider.currentSession ?: run {
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
             return
         }
         val pushers = session.pushersService().getPushers().filter {
@@ -32,11 +32,11 @@ class NotificationTestTokenRegistration @Inject constructor(
                 R.string.settings_troubleshoot_test_token_registration_failed,
                 context.getString(R.string.unexpected_error)
             )
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
         } else {
             description =
                 context.getString(R.string.settings_troubleshoot_test_token_registration_success)
-            status = NotificationTestStatus.SUCCESS
+            status = TaskStatus.SUCCESS
         }
     }
 }
diff --git a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt
index e2d6c8fb372efa8c5f2512ebcd2fdd6749746ea3..801d3c6fc5fb8db4ff7b50f6e33e2327308e3d7d 100644
--- a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt
+++ b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt
@@ -4,9 +4,9 @@ import android.content.Context
 import com.google.firebase.messaging.FirebaseMessaging
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.FcmHelper
 import org.futo.circles.feature.notifications.test.task.BaseNotificationTest
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 class NotificationsTestFirebaseToken @Inject constructor(
@@ -19,7 +19,7 @@ class NotificationsTestFirebaseToken @Inject constructor(
             FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
                 if (!task.isSuccessful) {
                     description = task.exception?.localizedMessage ?: "Unknown"
-                    status = NotificationTestStatus.FAILED
+                    status = TaskStatus.FAILED
                 } else {
                     task.result?.let { token ->
                         val tok = token.take(8) + "********************"
@@ -29,7 +29,7 @@ class NotificationsTestFirebaseToken @Inject constructor(
                         )
                         fcmHelper.storeFcmToken(token)
                     }
-                    status = NotificationTestStatus.SUCCESS
+                    status = TaskStatus.SUCCESS
                 }
                 updateTestInfo()
             }
@@ -38,7 +38,7 @@ class NotificationsTestFirebaseToken @Inject constructor(
                 R.string.settings_troubleshoot_test_fcm_failed,
                 e.localizedMessage
             )
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
             updateTestInfo()
         }
     }
diff --git a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt
index 30c84cd30553c6baba689a7b9bdbb893bde6e2ae..b77e8aa343f1bc60f4124595ffc16ad1b6ac4f02 100644
--- a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt
+++ b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt
@@ -5,8 +5,8 @@ import com.google.android.gms.common.ConnectionResult
 import com.google.android.gms.common.GoogleApiAvailability
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.test.task.BaseNotificationTest
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 class NotificationsTestPlayServices @Inject constructor(
@@ -20,13 +20,13 @@ class NotificationsTestPlayServices @Inject constructor(
             quickFix = null
             description =
                 context.getString(R.string.settings_troubleshoot_test_play_services_success)
-            status = NotificationTestStatus.SUCCESS
+            status = TaskStatus.SUCCESS
         } else {
             description = context.getString(
                 R.string.settings_troubleshoot_test_play_services_failed,
                 apiAvailability.getErrorString(resultCode)
             )
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
         }
     }
 }
diff --git a/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt b/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt
index 98957d7791a1ebfe131ff5c22bdeccb038748cb3..c563754a068a311f3ecd035c53e81ee166d6c58c 100644
--- a/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt
+++ b/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt
@@ -5,14 +5,15 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.withContext
-import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.mapping.toRoomInfo
-import org.futo.circles.core.model.CIRCLE_TAG
+import org.futo.circles.core.model.CIRCLES_SPACE_ACCOUNT_DATA_KEY
 import org.futo.circles.core.model.TIMELINE_TYPE
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.utils.UserUtils
+import org.futo.circles.core.utils.getJoinedRoomById
 import org.futo.circles.core.utils.getTimelineRoomFor
-import org.futo.circles.core.utils.isCircleShared
+import org.futo.circles.core.workspace.SharedCircleDataSource
+import org.futo.circles.core.workspace.SpacesTreeAccountDataSource
 import org.futo.circles.mapping.toInviteCircleListItem
 import org.futo.circles.mapping.toJoinedCircleListItem
 import org.futo.circles.model.CircleListItem
@@ -24,7 +25,10 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import javax.inject.Inject
 
-class CirclesDataSource @Inject constructor() {
+class CirclesDataSource @Inject constructor(
+    private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource,
+    private val sharedCircleDataSource: SharedCircleDataSource
+) {
 
     fun getCirclesFlow() = combine(
         MatrixSessionProvider.getSessionOrThrow().roomService()
@@ -40,7 +44,9 @@ class CirclesDataSource @Inject constructor() {
             list.filter { isInviteToCircleTimeline(it) }.map { it.toInviteCircleListItem() }
         val joinedCircles = list.filter { isJoinedCircle(it) }
         val sharedCircles =
-            joinedCircles.filter { joinedCircle -> isCircleShared(joinedCircle.roomId) }
+            joinedCircles.filter { joinedCircle ->
+                sharedCircleDataSource.isCircleShared(joinedCircle.roomId)
+            }
         val privateCircles = joinedCircles - sharedCircles.toSet()
         val requests = getKnockRequestToSharedTimelines(joinedCircles)
 
@@ -57,8 +63,14 @@ class CirclesDataSource @Inject constructor() {
         return displayList
     }
 
-    private fun isJoinedCircle(summary: RoomSummary) =
-        summary.hasTag(CIRCLE_TAG) && summary.membership == Membership.JOIN
+    fun isJoinedCircle(summary: RoomSummary): Boolean {
+        if (summary.roomId == sharedCircleDataSource.getSharedCirclesSpaceId()) return false
+        val circlesSpaceId = spacesTreeAccountDataSource.getRoomIdByKey(
+            CIRCLES_SPACE_ACCOUNT_DATA_KEY
+        ) ?: return false
+        return getJoinedRoomById(circlesSpaceId)?.roomSummary()?.spaceChildren?.map { it.childRoomId }
+            ?.contains(summary.roomId) == true
+    }
 
     private fun isInviteToCircleTimeline(summary: RoomSummary) =
         summary.roomType == TIMELINE_TYPE && summary.membership == Membership.INVITE
diff --git a/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt b/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt
index ad2e5dc0dd6018f3a8c50cc41f6007f2e022ad39..68fb17e3917ece6938365122292b1541ce1b52a6 100644
--- a/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt
+++ b/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt
@@ -53,9 +53,7 @@ class CirclesViewModel @Inject constructor(
         launchBg {
             val result = createResult {
                 if (getTimelineRoomFor(circleId) == null) {
-                    createTimelineLoadingLiveData.postValue(
-                        LoadingData(R.string.creating_timeline, total = 0)
-                    )
+                    createTimelineLoadingLiveData.postValue(LoadingData(R.string.creating_timeline))
                     val name =
                         MatrixSessionProvider.getSessionOrThrow().getRoomSummary(circleId)?.name
                     createRoomDataSource.createCircleTimeline(circleId, name)
diff --git a/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt b/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt
index 301c7872e0f78e9ec268588d1e4176c715f2f6b4..1a5baa16d458602cc68e0eefd6b42df09a0864f0 100644
--- a/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt
+++ b/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt
@@ -22,7 +22,7 @@ class AcceptCircleInviteDataSource @Inject constructor(
     suspend fun acceptCircleInvite(selectedCircles: List<SelectableRoomListItem>) = createResult {
         session?.roomService()?.joinRoom(roomId)
         selectedCircles.forEach { circle ->
-            roomRelationsBuilder.setInvitedCircleRelations(roomId, circle.id)
+            roomRelationsBuilder.setInvitedRoomRelations(roomId, circle.id)
         }
     }
 
diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesDataSource.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesDataSource.kt
deleted file mode 100644
index 15695a2438ce3405987fef23a33e9c82e50b64cd..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesDataSource.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.futo.circles.feature.circles.setup
-
-import android.content.Context
-import android.net.Uri
-import androidx.lifecycle.MutableLiveData
-import dagger.hilt.android.qualifiers.ApplicationContext
-import org.futo.circles.R
-import org.futo.circles.core.extensions.notEmptyDisplayName
-import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.model.SetupCircleListItem
-import org.matrix.android.sdk.api.session.getUser
-import javax.inject.Inject
-
-class SetupCirclesDataSource @Inject constructor(
-    @ApplicationContext private val context: Context
-) {
-
-    val circlesLiveData = MutableLiveData(getInitialCirclesList())
-
-    private fun getInitialCirclesList(): List<SetupCircleListItem> =
-        context.resources.getStringArray(R.array.setup_circles_list).mapIndexed { i, name ->
-            SetupCircleListItem(
-                id = i,
-                name = name,
-                userName = getUserName()
-            )
-        }
-
-    private fun getUserName(): String {
-        val session = MatrixSessionProvider.currentSession
-        val userId = session?.myUserId ?: return ""
-        return session.getUser(userId)?.notEmptyDisplayName() ?: ""
-    }
-
-    fun addCirclesCoverImage(id: Int, uri: Uri) {
-        val list = circlesLiveData.value?.map {
-            if (it.id == id) it.copy(coverUri = uri) else it
-        } ?: emptyList()
-
-        circlesLiveData.postValue(list)
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesFragment.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesFragment.kt
deleted file mode 100644
index dc62708b987819aa51e7900f610b736573669677..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesFragment.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.futo.circles.feature.circles.setup
-
-import android.os.Bundle
-import android.view.View
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.viewModels
-import androidx.navigation.fragment.findNavController
-import androidx.recyclerview.widget.DividerItemDecoration
-import by.kirich1409.viewbindingdelegate.viewBinding
-import dagger.hilt.android.AndroidEntryPoint
-import org.futo.circles.R
-import org.futo.circles.core.extensions.navigateSafe
-import org.futo.circles.core.extensions.observeData
-import org.futo.circles.core.extensions.observeResponse
-import org.futo.circles.core.extensions.showError
-import org.futo.circles.core.extensions.showSuccess
-import org.futo.circles.core.fragment.HasLoadingState
-import org.futo.circles.core.model.LoadingData
-import org.futo.circles.core.picker.helper.MediaPickerHelper
-import org.futo.circles.core.view.LoadingDialog
-import org.futo.circles.databinding.FragmentSetupCirclesBinding
-import org.futo.circles.feature.circles.setup.list.SetupCirclesAdapter
-import org.futo.circles.model.SetupCircleListItem
-
-@AndroidEntryPoint
-class SetupCirclesFragment : Fragment(R.layout.fragment_setup_circles), HasLoadingState {
-
-    override val fragment: Fragment = this
-    private val viewModel by viewModels<SetupCirclesViewModel>()
-    private val binding by viewBinding(FragmentSetupCirclesBinding::bind)
-    private val listAdapter by lazy { SetupCirclesAdapter(::onCircleListItemClicked) }
-    private val mediaPickerHelper = MediaPickerHelper(this, isGalleryAvailable = false)
-    private val loadingDialog by lazy { LoadingDialog(requireContext()) }
-
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        super.onViewCreated(view, savedInstanceState)
-        setupViews()
-        setupObservers()
-    }
-
-    private fun setupViews() {
-        with(binding) {
-            rvSetupCircles.apply {
-                addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
-                adapter = listAdapter
-            }
-            btnSkip.setOnClickListener { navigateToBottomMenuScreen() }
-            btnSave.setOnClickListener {
-                showLoading()
-                viewModel.createCircles()
-            }
-        }
-    }
-
-    private fun setupObservers() {
-        viewModel.circlesLiveData.observeData(this, ::setCirclesList)
-        viewModel.createCirclesResponseLiveData.observeResponse(this,
-            success = {
-                loadingDialog.dismiss()
-                showSuccess(getString(R.string.circles_created))
-                navigateToBottomMenuScreen()
-            },
-            error = {
-                showError(it)
-                loadingDialog.dismiss()
-            }
-        )
-    }
-
-    private fun setCirclesList(list: List<SetupCircleListItem>) {
-        listAdapter.submitList(list)
-    }
-
-    private fun onCircleListItemClicked(circle: SetupCircleListItem) {
-        mediaPickerHelper.showMediaPickerDialog(
-            onImageSelected = { id, uri -> viewModel.addImageForCircle(id, uri) },
-            id = circle.id
-        )
-    }
-
-    private fun showLoading() {
-        startLoading(binding.btnSave)
-        loadingDialog.handleLoading(
-            LoadingData(
-                total = 0,
-                messageId = R.string.configuring_workspace,
-                isLoading = true
-            )
-        )
-    }
-
-    private fun navigateToBottomMenuScreen() {
-        findNavController().navigateSafe(SetupCirclesFragmentDirections.toHomeFragment())
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesViewModel.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesViewModel.kt
deleted file mode 100644
index c9675b1694f2996d79cd123b08eacbcb8c554aaa..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesViewModel.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.futo.circles.feature.circles.setup
-
-import android.net.Uri
-import androidx.lifecycle.ViewModel
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.delay
-import org.futo.circles.core.CREATE_ROOM_DELAY
-import org.futo.circles.core.SingleEventLiveData
-import org.futo.circles.core.extensions.Response
-import org.futo.circles.core.extensions.createResult
-import org.futo.circles.core.extensions.launchBg
-import org.futo.circles.core.room.CreateRoomDataSource
-import javax.inject.Inject
-
-@HiltViewModel
-class SetupCirclesViewModel @Inject constructor(
-    private val setupCirclesDataSource: SetupCirclesDataSource,
-    private val createRoomDataSource: CreateRoomDataSource
-) : ViewModel() {
-
-    val circlesLiveData = setupCirclesDataSource.circlesLiveData
-    val createCirclesResponseLiveData = SingleEventLiveData<Response<Unit?>>()
-
-    fun createCircles() {
-        val circlesList = circlesLiveData.value ?: return
-        val lastItemIndex = circlesList.size - 1
-        launchBg {
-            val response = createResult {
-                circlesList.forEachIndexed { i, item ->
-                    createRoomDataSource.createCircleWithTimeline(
-                        name = item.name,
-                        iconUri = item.coverUri,
-                        null, false
-                    )
-                    if (i != lastItemIndex) delay(CREATE_ROOM_DELAY)
-                }
-            }
-            createCirclesResponseLiveData.postValue(response)
-        }
-    }
-
-    fun addImageForCircle(id: Int?, uri: Uri) {
-        id?.let { setupCirclesDataSource.addCirclesCoverImage(it, uri) }
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesAdapter.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesAdapter.kt
deleted file mode 100644
index 661baab8d99773d8ef4decf0f88efa3e62b7bc0d..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesAdapter.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.futo.circles.feature.circles.setup.list
-
-
-import android.view.ViewGroup
-import org.futo.circles.core.list.BaseRvAdapter
-import org.futo.circles.model.SetupCircleListItem
-
-class SetupCirclesAdapter(
-    private val onCircleClicked: (SetupCircleListItem) -> Unit
-) : BaseRvAdapter<SetupCircleListItem, SetupCirclesViewHolder>(DefaultIdEntityCallback()) {
-
-    override fun onCreateViewHolder(
-        parent: ViewGroup,
-        viewType: Int
-    ): SetupCirclesViewHolder = SetupCirclesViewHolder(
-        parent = parent,
-        onCircleClicked = { position -> onCircleClicked(getItem(position)) }
-    )
-
-    override fun onBindViewHolder(holder: SetupCirclesViewHolder, position: Int) {
-        holder.bind(getItem(position))
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesViewHolder.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesViewHolder.kt
deleted file mode 100644
index d290d4a1d05de311360020a5971c18cfdf227b5a..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesViewHolder.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.futo.circles.feature.circles.setup.list
-
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import org.futo.circles.R
-import org.futo.circles.core.extensions.onClick
-import org.futo.circles.core.list.ViewBindingHolder
-import org.futo.circles.databinding.ListItemSetupCircleBinding
-import org.futo.circles.model.SetupCircleListItem
-
-class SetupCirclesViewHolder(
-    parent: ViewGroup,
-    onCircleClicked: (Int) -> Unit
-) : RecyclerView.ViewHolder(inflate(parent, ListItemSetupCircleBinding::inflate)) {
-
-    private companion object : ViewBindingHolder
-
-    private val binding = baseBinding as ListItemSetupCircleBinding
-
-    init {
-        onClick(itemView) { position -> onCircleClicked(position) }
-    }
-
-    fun bind(data: SetupCircleListItem) {
-        with(binding) {
-            data.coverUri?.let { ivCircleCover.setImageURI(it) }
-                ?: ivCircleCover.setImageResource(R.drawable.add_image_placeholder)
-
-            tvCircleName.text = data.name
-            tvUserName.text = data.userName
-        }
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt b/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt
index afc90db1a750107d37f60753668e31a2f29474fa..66f853d2c27a720611e53b3ed36408876e21c867 100644
--- a/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt
+++ b/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt
@@ -18,19 +18,22 @@ import by.kirich1409.viewbindingdelegate.viewBinding
 import dagger.hilt.android.AndroidEntryPoint
 import org.futo.circles.MainActivity
 import org.futo.circles.R
+import org.futo.circles.auth.feature.workspace.WorkspaceDialogFragment
 import org.futo.circles.core.SHARE_PROFILE_URL_PREFIX
 import org.futo.circles.core.SHARE_ROOM_URL_PREFIX
 import org.futo.circles.core.extensions.navigateSafe
 import org.futo.circles.core.extensions.observeData
+import org.futo.circles.core.extensions.observeResponse
 import org.futo.circles.core.extensions.setSupportActionBar
 import org.futo.circles.core.model.CircleRoomTypeArg
 import org.futo.circles.core.model.GROUP_TYPE
+import org.futo.circles.core.model.LoadingData
 import org.futo.circles.core.model.TIMELINE_TYPE
 import org.futo.circles.core.picker.helper.RuntimePermissionHelper
 import org.futo.circles.core.provider.MatrixSessionProvider
+import org.futo.circles.core.view.LoadingDialog
 import org.futo.circles.databinding.FragmentBottomNavigationBinding
 import org.futo.circles.gallery.feature.backup.service.MediaBackupServiceManager
-import org.futo.circles.core.notices.SystemNoticesCountSharedViewModel
 import org.matrix.android.sdk.api.session.getRoomSummary
 import javax.inject.Inject
 
@@ -48,7 +51,7 @@ class HomeFragment : Fragment(R.layout.fragment_bottom_navigation), DeepLinkInte
         RuntimePermissionHelper(this, Manifest.permission.POST_NOTIFICATIONS)
 
     private val viewModel by viewModels<HomeViewModel>()
-    private val systemNoticesCountViewModel by activityViewModels<SystemNoticesCountSharedViewModel>()
+    private val loadingDialog by lazy { LoadingDialog(requireContext()) }
 
     @Inject
     lateinit var mediaBackupServiceManager: MediaBackupServiceManager
@@ -59,6 +62,7 @@ class HomeFragment : Fragment(R.layout.fragment_bottom_navigation), DeepLinkInte
             binding.bottomNavigationView.setupWithNavController(controller)
             setupToolBar(controller)
         }
+        loadingDialog.handleLoading(LoadingData(org.futo.circles.auth.R.string.validating_workspace))
         setupObservers()
         registerPushNotifications()
         handleDeepLinks()
@@ -112,19 +116,15 @@ class HomeFragment : Fragment(R.layout.fragment_bottom_navigation), DeepLinkInte
     }
 
     private fun setupObservers() {
-        systemNoticesCountViewModel.systemNoticesCountLiveData?.observeData(this) {
-            val count = it ?: 0
-            binding.bottomNavigationView.getOrCreateBadge(R.id.settings_nav_graph).apply {
-                isVisible = count > 0
-                number = count
-            }
-        }
         viewModel.inviteIntoSharedSpaceLiveData?.observeData(this) {
             viewModel.autoAcceptInviteOnKnock(it)
         }
         viewModel.mediaBackupSettingsLiveData?.observeData(this) {
             mediaBackupServiceManager.bindMediaServiceIfNeeded(requireContext(), it)
         }
+        viewModel.validateWorkspaceResultLiveData.observeResponse(this,
+            error = { WorkspaceDialogFragment().show(childFragmentManager, "workspace") },
+            onRequestInvoked = { loadingDialog.dismiss() })
     }
 
     private fun registerPushNotifications() {
diff --git a/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt b/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt
index 7cd83d21d5469bc6e7309bc67f5f6c93bc17911b..a8fcde94838226bdd1158789548dc31a4f8951aa 100644
--- a/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt
+++ b/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt
@@ -4,13 +4,14 @@ import androidx.lifecycle.ViewModel
 import androidx.lifecycle.map
 import androidx.lifecycle.viewModelScope
 import dagger.hilt.android.lifecycle.HiltViewModel
+import org.futo.circles.auth.feature.workspace.data_source.ConfigureWorkspaceDataSource
+import org.futo.circles.auth.feature.workspace.data_source.WorkspaceTasksProvider
+import org.futo.circles.core.SingleEventLiveData
+import org.futo.circles.core.extensions.Response
+import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.extensions.launchBg
-import org.futo.circles.core.model.CIRCLE_TAG
 import org.futo.circles.core.model.GROUP_TYPE
-import org.futo.circles.core.model.SharedCirclesSpace
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.room.CreateRoomDataSource
-import org.futo.circles.core.utils.getSharedCirclesSpaceId
 import org.futo.circles.feature.notifications.PushersManager
 import org.futo.circles.feature.notifications.ShortcutsHandler
 import org.futo.circles.gallery.feature.backup.RoomAccountDataSource
@@ -23,11 +24,13 @@ import javax.inject.Inject
 @HiltViewModel
 class HomeViewModel @Inject constructor(
     private val pushersManager: PushersManager,
-    private val createRoomDataSource: CreateRoomDataSource,
+    private val workspaceTasksProvider: WorkspaceTasksProvider,
+    private val workspaceDataSource: ConfigureWorkspaceDataSource,
     roomAccountDataSource: RoomAccountDataSource,
     shortcutsHandler: ShortcutsHandler
 ) : ViewModel() {
 
+    val validateWorkspaceResultLiveData = SingleEventLiveData<Response<Unit>>()
     val mediaBackupSettingsLiveData = roomAccountDataSource.getMediaBackupSettingsLive()
     val inviteIntoSharedSpaceLiveData = MatrixSessionProvider.currentSession?.roomService()
         ?.getRoomSummariesLive(roomSummaryQueryParams {
@@ -37,14 +40,22 @@ class HomeViewModel @Inject constructor(
 
     init {
         shortcutsHandler.observeRoomsAndBuildShortcuts(viewModelScope)
-        createSharedCirclesSpaceIfNotExist()
+        validateWorkspace()
     }
 
-    private fun createSharedCirclesSpaceIfNotExist() {
-        if (getSharedCirclesSpaceId() != null) return
-        launchBg { createRoomDataSource.createRoom(SharedCirclesSpace()) }
+    private fun validateWorkspace() = launchBg {
+        val tasks = workspaceTasksProvider.getMandatoryTasks()
+        tasks.forEach { item ->
+            val validationResponse = createResult { workspaceDataSource.validate(item.room) }
+            (validationResponse as? Response.Error)?.let {
+                validateWorkspaceResultLiveData.postValue(Response.Error(""))
+                return@launchBg
+            }
+        }
+        validateWorkspaceResultLiveData.postValue(Response.Success(Unit))
     }
 
+
     fun registerPushNotifications() {
         pushersManager.registerPushNotifications()
     }
@@ -56,16 +67,10 @@ class HomeViewModel @Inject constructor(
     }
 
 
-    private fun getParentSpaceIdForRoom(summary: RoomSummary): String? {
-        val circles = MatrixSessionProvider.currentSession?.roomService()
-            ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null })
-            ?.filter { item -> item.hasTag(CIRCLE_TAG) } ?: emptyList()
+    private fun getParentSpaceIdForRoom(summary: RoomSummary): String? =
+        summary.spaceParents?.firstOrNull { it.roomSummary?.membership == Membership.JOIN }
+            ?.roomSummary?.roomId
 
-        val parentCircle =
-            circles.firstOrNull { it.spaceChildren?.firstOrNull { it.childRoomId == summary.roomId } != null }
-
-        return parentCircle?.roomId
-    }
 
     fun autoAcceptInviteOnKnock(roomIds: List<String>) {
         MatrixSessionProvider.currentSession?.let { session ->
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt
index a219f65bcecb9071bfc16c563d6c579d912fc66c..52ab4690dcb542dd39fda88a803b87853444b58f 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt
@@ -9,9 +9,9 @@ import org.futo.circles.core.extensions.setIsVisible
 import org.futo.circles.core.extensions.visible
 import org.futo.circles.core.list.ViewBindingHolder
 import org.futo.circles.core.list.context
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.databinding.ListItemNotificationTestBinding
 import org.futo.circles.model.NotificationTestListItem
-import org.futo.circles.model.NotificationTestStatus
 
 class NotificationTestViewHolder(
     parent: ViewGroup,
@@ -32,12 +32,12 @@ class NotificationTestViewHolder(
             tvMessage.text = data.message
             btnFix.setIsVisible(data.hasFix)
             when (data.status) {
-                NotificationTestStatus.RUNNING -> {
+                TaskStatus.RUNNING -> {
                     ivTestStatus.gone()
                     testProgress.visible()
                 }
 
-                NotificationTestStatus.IDLE -> {
+                TaskStatus.IDLE -> {
                     ivTestStatus.gone()
                     testProgress.gone()
                 }
@@ -46,7 +46,7 @@ class NotificationTestViewHolder(
                     ivTestStatus.visible()
                     testProgress.gone()
                     ivTestStatus.setImageResource(
-                        if (data.status == NotificationTestStatus.FAILED) R.drawable.ic_error
+                        if (data.status == TaskStatus.FAILED) R.drawable.ic_error
                         else R.drawable.ic_check_circle
                     )
                 }
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt
index 8fce20c40f0023af793b4c937f61c6dfa39cabec..a6d940ce95a0a4b1b29ad682172d745f1e4f9cc7 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt
@@ -6,8 +6,7 @@ import org.futo.circles.model.NotificationTestListItem
 
 class NotificationsTestAdapter(
     private val onFixClicked: (Int) -> Unit,
-) :
-    BaseRvAdapter<NotificationTestListItem, NotificationTestViewHolder>(DefaultIdEntityCallback()) {
+) : BaseRvAdapter<NotificationTestListItem, NotificationTestViewHolder>(DefaultIdEntityCallback()) {
 
     override fun onCreateViewHolder(
         parent: ViewGroup,
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt
index 20abd59406c25e871340a5f057aafefe139ace10..460e738180d16a94fe0ea1c5e46d7e12ca5334f1 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt
@@ -1,20 +1,20 @@
 package org.futo.circles.feature.notifications.test.task
 
 import androidx.annotation.StringRes
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.model.NotificationTestListItem
-import org.futo.circles.model.NotificationTestStatus
 
 abstract class BaseNotificationTest(@StringRes val titleResId: Int) {
 
     protected var description: String = ""
     protected var quickFix: NotificationQuickFix? = null
-    protected var status: NotificationTestStatus = NotificationTestStatus.IDLE
+    protected var status: TaskStatus = TaskStatus.IDLE
     protected abstract fun perform()
 
     private var onTestUpdateListener: ((NotificationTestListItem) -> Unit)? = null
     fun runTest(updateListener: (NotificationTestListItem) -> Unit) {
         onTestUpdateListener = updateListener
-        status = NotificationTestStatus.RUNNING
+        status = TaskStatus.RUNNING
         description = ""
         quickFix = null
         updateTestInfo()
@@ -23,7 +23,7 @@ abstract class BaseNotificationTest(@StringRes val titleResId: Int) {
     }
 
     fun runFix() {
-        status = NotificationTestStatus.RUNNING
+        status = TaskStatus.RUNNING
         description = ""
         quickFix = null
         updateTestInfo()
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt
index 42c072dc646680d6959a3806bf5542bf56da23df..f596fc2df553aa377e95b47a98ae71177f02a817 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt
@@ -7,8 +7,8 @@ import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import org.futo.circles.R
 import org.futo.circles.core.extensions.coroutineScope
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.model.NotificationTestStatus
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.pushrules.RuleIds
 import org.matrix.android.sdk.api.session.pushrules.RuleKind
@@ -27,7 +27,7 @@ class NotificationAccountSettingsTest @Inject constructor(@ApplicationContext pr
                 description =
                     context.getString(R.string.settings_troubleshoot_test_account_settings_success)
                 quickFix = null
-                status = NotificationTestStatus.SUCCESS
+                status = TaskStatus.SUCCESS
             } else {
                 description =
                     context.getString(R.string.settings_troubleshoot_test_account_settings_failed)
@@ -45,10 +45,10 @@ class NotificationAccountSettingsTest @Inject constructor(@ApplicationContext pr
                         }
                     }
                 }
-                status = NotificationTestStatus.SUCCESS
+                status = TaskStatus.SUCCESS
             }
         } else {
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
         }
     }
 }
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt
index fcfb261c8292cd74f043d63c68a4861ba495d84c..955cc894b6c8250d4174788b72570bfcc24b0d4e 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt
@@ -3,9 +3,9 @@ package org.futo.circles.feature.notifications.test.task
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.FcmHelper
 import org.futo.circles.feature.notifications.PushersManager
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 
@@ -33,6 +33,6 @@ class NotificationAvailableUnifiedDistributorsTest @Inject constructor(
                 quantity
             )
         }
-        status = NotificationTestStatus.SUCCESS
+        status = TaskStatus.SUCCESS
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt
index 38c63b6548070fcf4f6a8fc044478db9e38a048b..72a2a04a8afed71055d1fecb0aa22e298631140d 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt
@@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.PushersManager
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 
@@ -18,7 +18,7 @@ class NotificationCurrentPushDistributorTest @Inject constructor(
             R.string.settings_troubleshoot_test_current_distributor,
             pushersManager.getCurrentDistributorName()
         )
-        status = NotificationTestStatus.SUCCESS
+        status = TaskStatus.SUCCESS
     }
 
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt
index c10de78d1a24de2f322f1c3b53ba504450b5b555..3a8dfc86544aeb4920c386cea334713495ec91df 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt
@@ -9,8 +9,8 @@ import org.futo.circles.R
 import org.futo.circles.core.ErrorParser
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.extensions.coroutineScope
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.PushersManager
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 class NotificationFromPushGatewayTest @Inject constructor(
@@ -32,17 +32,17 @@ class NotificationFromPushGatewayTest @Inject constructor(
                         if (pushReceived) {
                             description =
                                 context.getString(R.string.settings_troubleshoot_test_push_loop_success)
-                            status = NotificationTestStatus.SUCCESS
+                            status = TaskStatus.SUCCESS
                         } else {
                             description =
                                 context.getString(R.string.settings_troubleshoot_test_push_loop_waiting_for_push)
-                            status = NotificationTestStatus.RUNNING
+                            status = TaskStatus.RUNNING
                         }
                         updateTestInfo()
                     },
                     {
                         description = ErrorParser.getErrorMessage(it)
-                        status = NotificationTestStatus.FAILED
+                        status = TaskStatus.FAILED
                         updateTestInfo()
                     }
                 )
@@ -54,7 +54,7 @@ class NotificationFromPushGatewayTest @Inject constructor(
         pushReceived = true
         description =
             context.getString(R.string.settings_troubleshoot_test_push_loop_success)
-        status = NotificationTestStatus.SUCCESS
+        status = TaskStatus.SUCCESS
         updateTestInfo()
     }
 }
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt
index 5fbf45468e9d95c0da557be743ff321877d9e4fd..64a97f2daa2b0ab66993defbb50c87057acb657c 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt
@@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.model.NotificationTestStatus
 import org.futo.circles.model.toNotificationAction
 import org.matrix.android.sdk.api.session.pushrules.RuleIds
 import org.matrix.android.sdk.api.session.pushrules.getActions
@@ -43,12 +43,12 @@ class NotificationPushRulesSettingsTest @Inject constructor(
         if (oneOrMoreRuleIsOff) {
             description =
                 context.getString(R.string.settings_troubleshoot_test_bing_settings_failed)
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
         } else {
             description = if (oneOrMoreRuleAreSilent) {
                 context.getString(R.string.settings_troubleshoot_test_bing_settings_success_with_warn)
             } else ""
-            status = NotificationTestStatus.SUCCESS
+            status = TaskStatus.SUCCESS
         }
     }
 }
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt
index 7bc36c365b5f53c0b04b27187840e65bdbfb0e34..c5792bdaa345ecf58029b6b21c60ef344679a141 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt
@@ -9,7 +9,7 @@ import androidx.core.app.NotificationManagerCompat
 import androidx.core.content.ContextCompat
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
-import org.futo.circles.model.NotificationTestStatus
+import org.futo.circles.core.model.TaskStatus
 import javax.inject.Inject
 
 class NotificationSystemSettingsTest @Inject constructor(
@@ -21,7 +21,7 @@ class NotificationSystemSettingsTest @Inject constructor(
             description =
                 context.getString(R.string.settings_troubleshoot_test_system_settings_success)
             quickFix = null
-            status = NotificationTestStatus.SUCCESS
+            status = TaskStatus.SUCCESS
         } else {
             description =
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && isNotificationsPermissionGranted(
@@ -32,7 +32,7 @@ class NotificationSystemSettingsTest @Inject constructor(
                 } else {
                     context.getString(R.string.settings_troubleshoot_test_system_settings_failed)
                 }
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
         }
     }
 
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt
index 782ae8bc11cf2acd1bdd03bfe6de398f40cf8124..44dc73bfd1225076039fee6e4c65b951c08d7b6f 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt
@@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.NotificationUtils
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 
@@ -17,14 +17,14 @@ class NotificationTestSend @Inject constructor(
         notificationUtils.displayDiagnosticNotification()
         description =
             context.getString(R.string.settings_troubleshoot_test_notification_notice)
-        status = NotificationTestStatus.IDLE
+        status = TaskStatus.IDLE
     }
 
     override fun onTestPushClicked() {
         description =
             context.getString(R.string.settings_troubleshoot_test_notification_notification_clicked)
         quickFix = null
-        status = NotificationTestStatus.SUCCESS
+        status = TaskStatus.SUCCESS
         updateTestInfo()
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt
index 98cb85bdbf2d298ab1229b69beb558931931e617..2ab66041e94a591e48a558fed525a2fec7104d5e 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt
@@ -3,9 +3,9 @@ package org.futo.circles.feature.notifications.test.task
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.feature.notifications.PushersManager
-import org.futo.circles.model.NotificationTestStatus
 import org.matrix.android.sdk.api.session.pushers.PusherState
 import javax.inject.Inject
 
@@ -16,11 +16,11 @@ class NotificationsEndpointAsTokenRegistrationTest @Inject constructor(
 
     override fun perform() {
         val endpoint = pushersManager.getEndpointOrToken() ?: run {
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
             return
         }
         val session = MatrixSessionProvider.currentSession ?: run {
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
             return
         }
         val pushers = session.pushersService().getPushers().filter {
@@ -31,11 +31,11 @@ class NotificationsEndpointAsTokenRegistrationTest @Inject constructor(
                 R.string.settings_troubleshoot_test_endpoint_registration_failed,
                 context.getString(R.string.unexpected_error)
             )
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
         } else {
             description =
                 context.getString(R.string.settings_troubleshoot_test_endpoint_registration_success)
-            status = NotificationTestStatus.SUCCESS
+            status = TaskStatus.SUCCESS
         }
     }
 }
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt
index 5e039839e47a9a26daea1af57c8470585dabeb4d..fa853dc7a26327b7fcd50eb262e7e0c4a2cb01ff 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt
@@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.PushersManager
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 class NotificationsUnifiedPushEndpointTest @Inject constructor(
@@ -19,11 +19,11 @@ class NotificationsUnifiedPushEndpointTest @Inject constructor(
                 R.string.settings_troubleshoot_test_current_endpoint_success,
                 endpoint
             )
-            status = NotificationTestStatus.SUCCESS
+            status = TaskStatus.SUCCESS
         } else {
             description =
                 context.getString(R.string.settings_troubleshoot_test_current_endpoint_failed)
-            status = NotificationTestStatus.FAILED
+            status = TaskStatus.FAILED
         }
     }
 }
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt
index 59175abfd29737c51aab2d099e811b5105ceab16..7453c1db2132031aafc29220d3287bcde88a192d 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt
@@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
+import org.futo.circles.core.model.TaskStatus
 import org.futo.circles.feature.notifications.PushersManager
-import org.futo.circles.model.NotificationTestStatus
 import javax.inject.Inject
 
 class NotificationsUnifiedPushGatewayTest @Inject constructor(
@@ -17,6 +17,6 @@ class NotificationsUnifiedPushGatewayTest @Inject constructor(
             R.string.settings_troubleshoot_test_current_gateway,
             pushersManager.getPushGateway()
         )
-        status = NotificationTestStatus.SUCCESS
+        status = TaskStatus.SUCCESS
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt b/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt
index d4cc88f3fcb85afc64e7c770d36423d1987f2ac8..b93d28a58addba8b84b8d48bef597d842b75f462 100644
--- a/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt
+++ b/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt
@@ -11,8 +11,7 @@ import kotlinx.coroutines.withContext
 import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.select_users.SearchUserDataSource
-import org.futo.circles.core.utils.getSharedCircleFor
-import org.futo.circles.core.utils.getSharedCirclesSpaceId
+import org.futo.circles.core.workspace.SharedCircleDataSource
 import org.futo.circles.mapping.toPeopleUserListItem
 import org.futo.circles.model.PeopleHeaderItem
 import org.futo.circles.model.PeopleItemType
@@ -24,11 +23,12 @@ import org.matrix.android.sdk.api.session.user.model.User
 import javax.inject.Inject
 
 class PeopleDataSource @Inject constructor(
-    private val searchUserDataSource: SearchUserDataSource
+    private val searchUserDataSource: SearchUserDataSource,
+    private val sharedCircleDataSource: SharedCircleDataSource
 ) {
 
     private val session = MatrixSessionProvider.currentSession
-    private val profileRoomId = getSharedCirclesSpaceId() ?: ""
+    private val profileRoomId = sharedCircleDataSource.getSharedCirclesSpaceId() ?: ""
 
     suspend fun acceptFollowRequest(userId: String) = createResult {
         session?.roomService()?.getRoom(profileRoomId)?.membershipService()?.invite(userId)
@@ -127,12 +127,12 @@ class PeopleDataSource @Inject constructor(
     }
 
     private fun isMyFollower(userId: String): Boolean {
-        val mySharedCircleMembers = getSharedCirclesSpaceId()?.let {
-            session?.getRoom(it)?.roomSummary()?.otherMemberIds
-        } ?: emptyList()
+        val mySharedCircleMembers =
+            session?.getRoom(profileRoomId)?.roomSummary()?.otherMemberIds ?: emptyList()
         return mySharedCircleMembers.contains(userId)
     }
 
-    private fun amIFollowing(userId: String) = getSharedCircleFor(userId) != null
+    private fun amIFollowing(userId: String) =
+        sharedCircleDataSource.getSharedCircleFor(userId) != null
 
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt b/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt
index 716e420f1cc7232fef8923c9b6590ede3c85fe54..4a234e39a5263b69f0e4ca52a5757633a228820f 100644
--- a/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt
+++ b/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt
@@ -3,10 +3,12 @@ package org.futo.circles.feature.people
 import org.futo.circles.core.extensions.Response
 import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.utils.getSharedCircleFor
+import org.futo.circles.core.workspace.SharedCircleDataSource
 import javax.inject.Inject
 
-class UserOptionsDataSource @Inject constructor() {
+class UserOptionsDataSource @Inject constructor(
+    private val sharedCircleDataSource: SharedCircleDataSource
+) {
 
     val ignoredUsersLiveData =
         MatrixSessionProvider.currentSession?.userService()?.getIgnoredUsersLive()
@@ -19,10 +21,11 @@ class UserOptionsDataSource @Inject constructor() {
         MatrixSessionProvider.currentSession?.userService()?.unIgnoreUserIds(listOf(userId))
     }
 
-    fun amIFollowingUser(userId: String): Boolean = getSharedCircleFor(userId) != null
+    fun amIFollowingUser(userId: String): Boolean =
+        sharedCircleDataSource.getSharedCircleFor(userId) != null
 
     suspend fun unFollowUser(userId: String): Response<Unit?> = createResult {
         MatrixSessionProvider.currentSession?.roomService()
-            ?.leaveRoom(getSharedCircleFor(userId)?.roomId ?: "")
+            ?.leaveRoom(sharedCircleDataSource.getSharedCircleFor(userId)?.roomId ?: "")
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt b/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt
index 1d8234ae48d918dc1daa4e309d2cbd362e88a645..677e3c57faa025c123f9ce3ba9e86614805e90f1 100644
--- a/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt
+++ b/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt
@@ -13,7 +13,7 @@ import org.futo.circles.core.extensions.getOrThrow
 import org.futo.circles.core.extensions.getRoomOwners
 import org.futo.circles.core.model.TIMELINE_TYPE
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.utils.getSharedCircleFor
+import org.futo.circles.core.workspace.SharedCircleDataSource
 import org.futo.circles.mapping.toTimelineRoomListItem
 import org.futo.circles.model.TimelineHeaderItem
 import org.futo.circles.model.TimelineListItem
@@ -26,7 +26,8 @@ import javax.inject.Inject
 
 @ViewModelScoped
 class UserDataSource @Inject constructor(
-    savedStateHandle: SavedStateHandle
+    savedStateHandle: SavedStateHandle,
+    private val sharedCircleDataSource: SharedCircleDataSource
 ) {
 
     private val userId: String = savedStateHandle.getOrThrow("userId")
@@ -70,7 +71,7 @@ class UserDataSource @Inject constructor(
         .map { list -> filterUsersTimelines(list) }.asFlow()
 
     private suspend fun getAllSharedTimelinesFlow() = session.roomService().getRoomSummaryLive(
-        getSharedCircleFor(userId)?.roomId ?: ""
+        sharedCircleDataSource.getSharedCircleFor(userId)?.roomId ?: ""
     ).asFlow().map { sharedSummary ->
         sharedSummary.getOrNull()?.let { mapSharedTimelines(it) } ?: emptyList()
     }
diff --git a/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt b/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt
index 2e8ff781d7df991a2d7e23cdc628d54f1599f985..8b625ae69546a8056bef67f5e56cf241814c892b 100644
--- a/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt
+++ b/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt
@@ -13,12 +13,13 @@ import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.flowOn
 import org.futo.circles.core.extensions.getOrThrow
 import org.futo.circles.core.mapping.toSelectableRoomListItem
-import org.futo.circles.core.model.CIRCLE_TAG
 import org.futo.circles.core.model.CircleRoomTypeArg
 import org.futo.circles.core.model.GALLERY_TYPE
 import org.futo.circles.core.model.GROUP_TYPE
 import org.futo.circles.core.model.SelectableRoomListItem
 import org.futo.circles.core.provider.MatrixSessionProvider
+import org.futo.circles.core.workspace.SharedCircleDataSource
+import org.futo.circles.feature.circles.CirclesDataSource
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
@@ -26,7 +27,8 @@ import javax.inject.Inject
 
 @ViewModelScoped
 class SelectRoomsDataSource @Inject constructor(
-    savedStateHandle: SavedStateHandle
+    savedStateHandle: SavedStateHandle,
+    private val circleDataSource: CirclesDataSource
 ) {
 
     val ordinal = savedStateHandle.getOrThrow<Int>(SelectRoomsFragment.TYPE_ORDINAL)
@@ -45,7 +47,7 @@ class SelectRoomsDataSource @Inject constructor(
         }.flowOn(Dispatchers.IO).distinctUntilChanged()
 
     private fun getRoomsFlowWithType(): Flow<List<RoomSummary>> = when (roomType) {
-        CircleRoomTypeArg.Circle -> getFilteredRoomsFlow { it.hasTag(CIRCLE_TAG) && it.membership == Membership.JOIN }
+        CircleRoomTypeArg.Circle -> getFilteredRoomsFlow { circleDataSource.isJoinedCircle(it) }
         CircleRoomTypeArg.Group -> getFilteredRoomsFlow { (it.roomType == GROUP_TYPE && it.membership == Membership.JOIN) }
         CircleRoomTypeArg.Photo -> getFilteredRoomsFlow { (it.roomType == GALLERY_TYPE && it.membership == Membership.JOIN) }
     }
diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt
index 6b0de4a53231070786e0b9b59a42d3385135a0a3..e8a3f3d145de0f1bd25965c8df153d710e9875ae 100644
--- a/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt
+++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt
@@ -22,7 +22,6 @@ import org.futo.circles.core.extensions.showSuccess
 import org.futo.circles.core.extensions.withConfirmation
 import org.futo.circles.core.model.DeactivateAccount
 import org.futo.circles.core.model.LoadingData
-import org.futo.circles.core.notices.SystemNoticesCountSharedViewModel
 import org.futo.circles.core.provider.PreferencesProvider
 import org.futo.circles.core.view.LoadingDialog
 import org.futo.circles.databinding.FragmentSettingsBinding
@@ -33,7 +32,6 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
 
     private val binding by viewBinding(FragmentSettingsBinding::bind)
     private val viewModel by viewModels<SettingsViewModel>()
-    private val systemNoticesCountViewModel by activityViewModels<SystemNoticesCountSharedViewModel>()
     private val loadingDialog by lazy { LoadingDialog(requireContext()) }
     private val preferencesProvider by lazy { PreferencesProvider(requireContext()) }
     private val navigator by lazy { SettingsNavigator(this) }
@@ -46,44 +44,43 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
 
     private fun setupViews() {
         with(binding) {
-            tvLogout.setOnClickListener { withConfirmation(LogOut()) { viewModel.logOut() } }
+            tvLogout.setOnClickListener {
+                withConfirmation(LogOut()) {
+                    loadingDialog.handleLoading(LoadingData(R.string.log_out))
+                    viewModel.logOut()
+                }
+            }
             tvSwitchUser.setOnClickListener { withConfirmation(SwitchUser()) { (activity as? MainActivity)?.stopSyncAndRestart() } }
             ivProfile.setOnClickListener { navigator.navigateToProfile() }
             tvChangePassword.setOnClickListener { viewModel.handleChangePasswordFlow() }
             tvDeactivate.setOnClickListener {
                 withConfirmation(DeactivateAccount()) {
-                    loadingDialog.handleLoading(LoadingData(total = 0))
+                    loadingDialog.handleLoading(LoadingData())
                     viewModel.deactivateAccount()
                 }
             }
             tvLoginSessions.setOnClickListener { navigator.navigateToActiveSessions() }
-            lSystemNotices.setOnClickListener { navigator.navigateToSystemNotices() }
             tvClearCache.setOnClickListener { viewModel.clearCash(requireContext()) }
             tvVersion.setOnLongClickListener { toggleDeveloperMode(); true }
             tvPushNotifications.setOnClickListener { navigator.navigateToPushSettings() }
-            ivShareProfile.setOnClickListener { navigator.navigateToShareProfile() }
+            ivShareProfile.setOnClickListener { navigator.navigateToShareProfile(viewModel.getSharedCircleSpaceId()) }
         }
         setVersion()
     }
 
     private fun setupObservers() {
         viewModel.logOutLiveData.observeResponse(this,
-            success = { clearSessionAndRestart() }
+            success = { clearSessionAndRestart() },
+            onRequestInvoked = { loadingDialog.dismiss() }
         )
         viewModel.profileLiveData.observeData(this) {
             it.getOrNull()?.let { bindProfile(it) }
         }
-        viewModel.loadingLiveData.observeData(this) {
-            loadingDialog.handleLoading(it)
-        }
         viewModel.deactivateLiveData.observeResponse(this,
             success = { clearSessionAndRestart() },
             error = { showError(getString(org.futo.circles.auth.R.string.invalid_auth)) },
             onRequestInvoked = { loadingDialog.dismiss() }
         )
-        systemNoticesCountViewModel.systemNoticesCountLiveData?.observeData(this) {
-            binding.ivNoticesCount.setCount(it ?: 0)
-        }
         viewModel.startReAuthEventLiveData.observeData(this) {
             navigator.navigateToReAuthStages()
         }
diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt
index ae245082367ec9aa4ef3a1c2189d26edaba9b632..1e095afa621d733b329e2fdcd63a11c4c3551f79 100644
--- a/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt
+++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt
@@ -4,8 +4,6 @@ import androidx.navigation.fragment.findNavController
 import org.futo.circles.R
 import org.futo.circles.core.extensions.navigateSafe
 import org.futo.circles.core.extensions.showError
-import org.futo.circles.core.utils.getSharedCirclesSpaceId
-import org.futo.circles.core.utils.getSystemNoticesRoomId
 
 class SettingsNavigator(private val fragment: SettingsFragment) {
 
@@ -19,16 +17,6 @@ class SettingsNavigator(private val fragment: SettingsFragment) {
             .navigateSafe(SettingsFragmentDirections.toActiveSessionsDialogFragment())
     }
 
-    fun navigateToSystemNotices() {
-        val systemNoticesRoomId = getSystemNoticesRoomId() ?: run {
-            fragment.showError(fragment.getString(org.futo.circles.core.R.string.system_notices_room_not_found))
-            return
-        }
-        fragment.findNavController().navigateSafe(
-            SettingsFragmentDirections.toSystemNoticesDialogFragment(systemNoticesRoomId)
-        )
-    }
-
     fun navigateToMatrixChangePassword() {
         fragment.findNavController()
             .navigateSafe(SettingsFragmentDirections.toChangePasswordDialogFragment())
@@ -44,8 +32,8 @@ class SettingsNavigator(private val fragment: SettingsFragment) {
             .navigateSafe(SettingsFragmentDirections.toReAuthStagesDialogFragment())
     }
 
-    fun navigateToShareProfile() {
-        val sharedSpaceId = getSharedCirclesSpaceId() ?: kotlin.run {
+    fun navigateToShareProfile(sharedSpaceId: String?) {
+        sharedSpaceId ?: kotlin.run {
             fragment.showError(
                 fragment.requireContext().getString(R.string.shared_circles_space_not_found)
             )
diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt
index deac30615ed3162f400e29716c339a330026efb5..38a26546737f4241dd648e71a3d26c77bef98e27 100644
--- a/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt
+++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt
@@ -8,16 +8,17 @@ import org.futo.circles.core.SingleEventLiveData
 import org.futo.circles.core.extensions.Response
 import org.futo.circles.core.extensions.launchBg
 import org.futo.circles.core.utils.LauncherActivityUtils
+import org.futo.circles.core.workspace.SharedCircleDataSource
 import javax.inject.Inject
 
 @HiltViewModel
 class SettingsViewModel @Inject constructor(
     private val settingsDataSource: SettingsDataSource,
-    private val logoutDataSource: LogoutDataSource
+    private val logoutDataSource: LogoutDataSource,
+    private val sharedCircleDataSource: SharedCircleDataSource
 ) : ViewModel() {
 
     val profileLiveData = settingsDataSource.profileLiveData
-    val loadingLiveData = logoutDataSource.loadingLiveData
     val passPhraseLoadingLiveData = settingsDataSource.passPhraseLoadingLiveData
     val startReAuthEventLiveData = settingsDataSource.startReAuthEventLiveData
     val logOutLiveData = SingleEventLiveData<Response<Unit?>>()
@@ -58,4 +59,6 @@ class SettingsViewModel @Inject constructor(
         launchBg { LauncherActivityUtils.clearCache(context) }
         clearCacheLiveData.postValue(Unit)
     }
+
+    fun getSharedCircleSpaceId(): String? = sharedCircleDataSource.getSharedCirclesSpaceId()
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt b/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt
index 162c2c9298d64c91f5c7e4e1a90ca19119846cdf..880d34cbce39c0e7db5bbf9e9eb6be48dffc055f 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt
+++ b/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt
@@ -15,7 +15,7 @@ object UploadMediaProgressHelper {
                 when (state) {
                     ContentUploadStateTracker.State.CompressingImage -> {
                         loadingView.visible()
-                        loadingView.setMessage(R.string.compressing)
+                        loadingView.setProgress(LoadingData(R.string.compressing))
                     }
 
                     is ContentUploadStateTracker.State.CompressingVideo -> {
diff --git a/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt b/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt
index dd6e844ccf44ed3c6b27f1d1a4823f5c78d034cc..82aa257167aaee2a05f353045791558dad928ff8 100644
--- a/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt
+++ b/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt
@@ -1,11 +1,12 @@
 package org.futo.circles.model
 
 import org.futo.circles.core.list.IdEntity
+import org.futo.circles.core.model.TaskStatus
 
 data class NotificationTestListItem(
     val titleId: Int,
     val message: String,
-    val status: NotificationTestStatus,
+    val status: TaskStatus,
     val hasFix: Boolean
 ) : IdEntity<Int> {
     override val id: Int = titleId
diff --git a/app/src/main/java/org/futo/circles/model/NotificationTestStatus.kt b/app/src/main/java/org/futo/circles/model/NotificationTestStatus.kt
deleted file mode 100644
index 56abc6886353a041c5f41630e83dbfb98c494c21..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/model/NotificationTestStatus.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.futo.circles.model
-
-enum class NotificationTestStatus {
-    IDLE,
-    RUNNING,
-    SUCCESS,
-    FAILED
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/model/PeopleListItem.kt b/app/src/main/java/org/futo/circles/model/PeopleListItem.kt
index ca5d9b2d2f904ec2f8b292107e4d0c0412ed5f1d..4247cdaf0ac49d0d697f8b81827dca3a432c148b 100644
--- a/app/src/main/java/org/futo/circles/model/PeopleListItem.kt
+++ b/app/src/main/java/org/futo/circles/model/PeopleListItem.kt
@@ -15,7 +15,7 @@ data class PeopleHeaderItem(
     override val id: String = titleRes.toString()
 
     companion object {
-        val friends = PeopleHeaderItem(R.string.friends)
+        val friends = PeopleHeaderItem(org.futo.circles.auth.R.string.friends)
         val followersUsersHeader = PeopleHeaderItem(R.string.followers)
         val followingUsersHeader = PeopleHeaderItem(R.string.following)
         val knownUsersHeader = PeopleHeaderItem(R.string.known_users)
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
index 519dc47064000f3e5c29d920c15086e02632a615..f36e2bf229a3e2dc93f76dac7b77c58df8f7c24c 100644
--- a/app/src/main/res/layout/fragment_settings.xml
+++ b/app/src/main/res/layout/fragment_settings.xml
@@ -121,79 +121,48 @@
                 android:layout_height="wrap_content"
                 android:text="@string/notifications" />
 
-            <org.futo.circles.core.view.SettingsMenuItemView
+            <TextView
                 android:id="@+id/tvPushNotifications"
+                style="@style/settingMenuItem"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                app:optionIcon="@drawable/ic_notifications"
-                app:optionName="@string/push_notifications" />
-
-
-            <androidx.constraintlayout.widget.ConstraintLayout
-                android:id="@+id/lSystemNotices"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:background="?selectableItemBackground"
-                android:clickable="true"
-                android:focusable="true">
-
-                <TextView
-                    android:id="@+id/tvSystemNotices"
-                    style="@style/settingMenuItem"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:background="@null"
-                    android:clickable="false"
-                    android:paddingEnd="8dp"
-                    android:text="@string/system_notices"
-                    app:drawableStartCompat="@drawable/ic_error"
-                    app:layout_constraintBottom_toBottomOf="parent"
-                    app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toTopOf="parent"
-                    tools:ignore="RtlSymmetry" />
-
-                <org.futo.circles.core.view.NotificationCounterView
-                    android:id="@+id/ivNoticesCount"
-                    android:layout_width="18dp"
-                    android:layout_height="0dp"
-                    android:layout_marginTop="2dp"
-                    android:background="@android:color/holo_red_dark"
-                    android:visibility="gone"
-                    app:layout_constraintStart_toEndOf="@id/tvSystemNotices"
-                    app:layout_constraintTop_toTopOf="parent"
-                    tools:visibility="visible" />
-
-
-            </androidx.constraintlayout.widget.ConstraintLayout>
+                android:text="@string/push_notifications"
+                app:drawableStartCompat="@drawable/ic_notifications" />
 
             <TextView
                 style="@style/settingMenuHeader"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/account" />
+                android:text="@string/session" />
 
             <org.futo.circles.core.view.SettingsMenuItemView
-                android:id="@+id/tvChangePassword"
+                android:id="@+id/tvLoginSessions"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                app:optionIcon="@drawable/ic_lock"
-                app:optionName="@string/change_password" />
+                app:optionIcon="@drawable/ic_phone"
+                app:optionName="@string/login_sessions" />
 
 
-            <org.futo.circles.core.view.SettingsMenuItemView
-                android:id="@+id/tvLoginSessions"
+            <TextView
+                android:id="@+id/tvClearCache"
+                style="@style/settingMenuItem"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                app:optionIcon="@drawable/ic_phone"
-                app:optionName="@string/login_sessions" />
+                android:text="@string/clear_cache_and_reload"
+                app:drawableStartCompat="@drawable/ic_reload" />
 
+            <TextView
+                style="@style/settingMenuHeader"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/account" />
 
             <org.futo.circles.core.view.SettingsMenuItemView
-                android:id="@+id/tvClearCache"
+                android:id="@+id/tvChangePassword"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                app:optionIcon="@drawable/ic_reload"
-                app:optionName="@string/clear_cache_and_reload" />
+                app:optionIcon="@drawable/ic_lock"
+                app:optionName="@string/change_password" />
 
 
             <org.futo.circles.core.view.SettingsMenuItemView
diff --git a/app/src/main/res/layout/fragment_setup_circles.xml b/app/src/main/res/layout/fragment_setup_circles.xml
deleted file mode 100644
index 9e3a40256a8609d71d3795b9df73bdbb9233bcc5..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/fragment_setup_circles.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-
-    <com.google.android.material.appbar.MaterialToolbar
-        android:id="@+id/toolbar"
-        android:layout_width="0dp"
-        android:layout_height="?attr/actionBarSize"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:title="@string/setup_circles"
-        app:titleCentered="true" />
-
-    <View
-        android:id="@+id/toolbarDivider"
-        android:layout_width="0dp"
-        android:layout_height="@dimen/divider_height"
-        android:background="@color/divider_color"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/toolbar" />
-
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/guidelineStart"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        app:layout_constraintGuide_begin="36dp" />
-
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/guidelineEnd"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        app:layout_constraintGuide_end="36dp" />
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/rvSetupCircles"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
-        app:layout_constraintBottom_toTopOf="@id/tvEncryptionWarning"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/toolbarDivider" />
-
-    <TextView
-        android:id="@+id/tvEncryptionWarning"
-        style="@style/footNote"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="16dp"
-        android:drawablePadding="8dp"
-        android:text="@string/circle_encryption_warning"
-        android:textColor="@color/yellow"
-        app:drawableStartCompat="@drawable/ic_info"
-        app:drawableTint="@color/yellow"
-        app:layout_constraintBottom_toTopOf="@id/btnSave"
-        app:layout_constraintEnd_toEndOf="@id/guidelineEnd"
-        app:layout_constraintStart_toStartOf="@id/guidelineStart" />
-
-    <org.futo.circles.core.view.LoadingButton
-        android:id="@+id/btnSave"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="24dp"
-        android:layout_marginTop="16dp"
-        android:layout_marginBottom="24dp"
-        android:text="@string/save"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="@id/guidelineEnd"
-        app:layout_constraintStart_toEndOf="@id/btnSkip" />
-
-    <com.google.android.material.button.MaterialButton
-        android:id="@+id/btnSkip"
-        style="@style/NegativeButtonStyle"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:text="@string/skip"
-        app:layout_constraintBottom_toBottomOf="@id/btnSave"
-        app:layout_constraintEnd_toStartOf="@id/btnSave"
-        app:layout_constraintStart_toStartOf="@id/guidelineStart" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_setup_circle.xml b/app/src/main/res/layout/list_item_setup_circle.xml
deleted file mode 100644
index 06ae73afb675c6ee4b13666cc4170688ebe354ab..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/list_item_setup_circle.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="?selectableItemBackground"
-    android:clickable="true"
-    android:focusable="true"
-    android:padding="4dp">
-
-
-    <com.google.android.material.imageview.ShapeableImageView
-        android:id="@+id/ivCircleCover"
-        android:layout_width="@dimen/group_icon_size"
-        android:layout_height="@dimen/group_icon_size"
-        android:scaleType="centerCrop"
-        android:src="@drawable/add_image_placeholder"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.GroupIconRadius" />
-
-    <TextView
-        android:id="@+id/tvCircleName"
-        style="@style/title2"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:gravity="center"
-        android:lines="1"
-        app:layout_constraintBottom_toTopOf="@id/tvUserName"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@id/ivCircleCover"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintVertical_chainStyle="packed"
-        tools:text="texsdt" />
-
-    <TextView
-        android:id="@+id/tvUserName"
-        style="@style/subheadline"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="4dp"
-        android:ellipsize="end"
-        android:gravity="center"
-        android:lines="1"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="@id/tvCircleName"
-        app:layout_constraintTop_toBottomOf="@id/tvCircleName"
-        tools:text="texsdt" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph_start_host.xml b/app/src/main/res/navigation/nav_graph_start_host.xml
index 2786cacc4ed47989321accf1d8441e449d03cfd6..419cdf7644f6508a507d49ed08438e90b173a10f 100644
--- a/app/src/main/res/navigation/nav_graph_start_host.xml
+++ b/app/src/main/res/navigation/nav_graph_start_host.xml
@@ -54,18 +54,6 @@
         </action>
     </fragment>
 
-    <fragment
-        android:id="@+id/setupCirclesFragment"
-        android:name="org.futo.circles.feature.circles.setup.SetupCirclesFragment"
-        android:label="SetupCirclesFragment"
-        tools:layout="@layout/fragment_setup_circles">
-        <action
-            android:id="@+id/to_homeFragment"
-            app:destination="@id/homeFragment"
-            app:popUpTo="@id/setupCirclesFragment"
-            app:popUpToInclusive="true" />
-    </fragment>
-
     <include app:graph="@navigation/nav_graph_auth" />
 
     <dialog
diff --git a/app/src/main/res/navigation/settings_nav_graph.xml b/app/src/main/res/navigation/settings_nav_graph.xml
index 18e838fedbccb5547e14a613d2794c2f08395bf7..f4e9516a4a7bc25e34d310253aa49db3ca94e132 100644
--- a/app/src/main/res/navigation/settings_nav_graph.xml
+++ b/app/src/main/res/navigation/settings_nav_graph.xml
@@ -19,22 +19,6 @@
         <action
             android:id="@+id/to_activeSessionsDialogFragment"
             app:destination="@id/log_in_sessions_nav_graph" />
-        <action
-            android:id="@+id/to_systemNoticesDialogFragment"
-            app:destination="@id/systemNoticesDialogFragment">
-
-            <argument
-                android:name="roomId"
-                app:argType="string"
-                app:nullable="false" />
-
-            <argument
-                android:name="type"
-                android:defaultValue="Group"
-                app:argType="org.futo.circles.core.model.CircleRoomTypeArg"
-                app:nullable="false" />
-
-        </action>
         <action
             android:id="@+id/to_reAuthStagesDialogFragment"
             app:destination="@id/reAuthStagesDialogFragment" />
@@ -68,22 +52,6 @@
         android:name="org.futo.circles.auth.feature.change_password.ChangePasswordDialogFragment"
         android:label="ChangePasswordDialogFragment"
         tools:layout="@layout/dialog_fragment_change_password" />
-    <dialog
-        android:id="@+id/systemNoticesDialogFragment"
-        android:name="org.futo.circles.core.notices.SystemNoticesDialogFragment"
-        tools:layout="@layout/dialog_fragment_system_notices">
-
-        <argument
-            android:name="roomId"
-            app:argType="string"
-            app:nullable="false" />
-
-        <argument
-            android:name="type"
-            app:argType="org.futo.circles.core.model.CircleRoomTypeArg"
-            app:nullable="false" />
-
-    </dialog>
 
     <dialog
         android:id="@+id/shareRoomDialogFragment"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 57661aa9dd34eb225ff47962361132abbd0c786f..8557874102522cc5ccc2c15d3a1b3d2b371551c8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -26,22 +26,12 @@
     <string name="create_new_group">Create new group</string>
     <string name="create_new_circle">Create new circle</string>
     <string name="create">Create</string>
-    <string name="group_name">Group name</string>
-    <string name="circle_name">Circle name</string>
-    <string name="group_topic_optional">Group topic (optional)</string>
-    <string name="group_topic">Group topic</string>
-    <string name="setup_circles">Setup Circles</string>
-    <string name="circle_encryption_warning">NOTE: Circle name and cover image are not encrypted</string>
-    <string name="friends">Friends</string>
-    <string name="family">Family</string>
-    <string name="community">Community</string>
     <string name="circles_created">Circles created</string>
     <string name="private_circles">Private Circles</string>
     <string name="log_out">Log out</string>
     <string name="others">Others</string>
     <string name="following_format">Following %d</string>
     <string name="followed_by_format">Followed by %d</string>
-    <string name="group_encryption_warning">NOTE: Group name, topic and cover image are not encrypted</string>
     <string name="create_post">Create post</string>
     <string name="create_poll">Create poll</string>
     <string name="send">Send</string>
@@ -81,8 +71,6 @@
     <string name="hundred">100</string>
     <string name="severity_formatter">Severity: %d</string>
     <string name="add_reaction">Add reaction</string>
-    <string name="remove_from_this_circle_but_do_not_unfollow">Remove from this circle, but do not unfollow</string>
-    <string name="unfollow_completely_remove_from_all_circles">Unfollow completely (remove from all circles)</string>
     <string name="unfollow">Unfollow</string>
     <string name="requested_to_follow_format">%s requested to follow</string>
     <string name="requested_to_join">Requested to join</string>
@@ -125,11 +113,6 @@
     <string name="add_link">Add link</string>
     <string name="switch_user">Switch User</string>
     <string name="search_people">Search people</string>
-    <string name="circle_type">Circle type</string>
-    <string name="public_type">Public</string>
-    <string name="private_type">Private</string>
-    <string name="public_circle_explanation">Other users can ask to join</string>
-    <string name="private_circle_explanation">Accessible only by your invitation</string>
     <string name="request_sent">Request sent</string>
     <string name="wants_to_follow_you">wants to follow you</string>
     <string name="notification_unknown_room_name">Room</string>
@@ -207,7 +190,6 @@
     <string name="unifiedpush_distributors_dialog_title">Choose how to receive notifications</string>
     <string name="thread_format">%s (thread)</string>
     <string name="unexpected_error">Something went wrong</string>
-    <string name="configuring_workspace">Configuring workspace</string>
     <string name="shared_circles">Shared Circles</string>
     <string name="save">Save</string>
     <string name="joined_members_count">Joined members: %d</string>
@@ -226,6 +208,8 @@
     <string name="circles_empty_message">Create your first Circle</string>
     <string name="people_empty_message">Members of Circles and Groups you are joined will be shown here</string>
     <string name="creating_timeline">Creating timeline</string>
+    <string name="group_topic_optional">Group topic (optional)</string>
+    <string name="session">Session</string>
 
     <string-array name="report_categories">
         <item>@string/crude_language</item>
@@ -241,12 +225,6 @@
         <item>@string/other_prohibited_content</item>
     </string-array>
 
-    <string-array name="setup_circles_list">
-        <item>@string/friends</item>
-        <item>@string/family</item>
-        <item>@string/community</item>
-    </string-array>
-
     <plurals name="notification_compat_summary_line_for_room">
         <item quantity="one">%1$s: %2$d message</item>
         <item quantity="other">%1$s: %2$d messages</item>
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt
index 8bc23a8487f70b27db2c21618bcca8e59be9ffc3..95ce658c1636f8e22e635f765ca84d1b08645504 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt
@@ -1,30 +1,13 @@
 package org.futo.circles.auth.feature.log_in.log_out
 
-import androidx.lifecycle.MutableLiveData
-import org.futo.circles.auth.R
 import org.futo.circles.core.extensions.createResult
-import org.futo.circles.core.model.LoadingData
 import org.futo.circles.core.provider.MatrixSessionProvider
 import javax.inject.Inject
 
 class LogoutDataSource @Inject constructor() {
 
-    private val session = MatrixSessionProvider.getSessionOrThrow()
-
-    val loadingLiveData = MutableLiveData<LoadingData>()
-    private val loadingData = LoadingData(total = 0)
-
-
     suspend fun logOut() = createResult {
-        loadingLiveData.postValue(
-            loadingData.apply {
-                messageId = R.string.log_out
-                isLoading = true
-            }
-        )
-        session.signOutService().signOut(true)
-        loadingLiveData.postValue(loadingData.apply { isLoading = false })
+        MatrixSessionProvider.getSessionOrThrow().signOutService().signOut(true)
     }
 
-
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt
index 7e940c2afe00975ec49068c1eb95a96e3391f814..4b0999d38f2aa46a7270270245ec1e08fdf97797 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt
@@ -17,7 +17,6 @@ import org.futo.circles.auth.base.LoginStageNavigationEvent
 import org.futo.circles.auth.databinding.FragmentLoginStagesBinding
 import org.futo.circles.auth.feature.log_in.recovery.EnterPassPhraseDialog
 import org.futo.circles.auth.feature.log_in.recovery.EnterPassPhraseDialogListener
-import org.futo.circles.core.CirclesAppConfig
 import org.futo.circles.core.extensions.navigateSafe
 import org.futo.circles.core.extensions.observeData
 import org.futo.circles.core.extensions.observeResponse
@@ -79,15 +78,11 @@ class LogInStagesFragment : Fragment(R.layout.fragment_login_stages),
         viewModel.passPhraseLoadingLiveData.observeData(this) {
             loadingDialog.handleLoading(it)
         }
-        viewModel.spacesTreeLoadingLiveData.observeData(this) {
-            loadingDialog.handleLoading(it)
-        }
         viewModel.loginNavigationLiveData.observeData(this) { event ->
             when (event) {
-                LoginNavigationEvent.Main -> navigateToBottomMenuFragment()
-                LoginNavigationEvent.SetupCircles -> navigateToSetupCirclesOrHome()
+                LoginNavigationEvent.Main -> navigateToHome()
                 LoginNavigationEvent.PassPhrase -> showPassPhraseDialog()
-                else -> navigateToBottomMenuFragment()
+                else -> navigateToHome()
             }
         }
         viewModel.messageEventLiveData.observeData(this) { messageId ->
@@ -123,19 +118,10 @@ class LogInStagesFragment : Fragment(R.layout.fragment_login_stages),
             }
     }
 
-    private fun navigateToBottomMenuFragment() {
+    private fun navigateToHome() {
         findNavController().navigateSafe(LogInStagesFragmentDirections.toHomeFragment())
     }
 
-    private fun navigateToSetupCirclesOrHome() {
-        findNavController().navigateSafe(
-            if (CirclesAppConfig.isSetupCirclesEnabled)
-                LogInStagesFragmentDirections.toSetupCirclesFragment()
-            else
-                LogInStagesFragmentDirections.toHomeFragment()
-        )
-    }
-
     private fun showDiscardDialog() {
         showDialog(
             titleResIdRes = R.string.discard_current_login_progress,
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt
index 15cae3d1ffa3fc409e96fce24572af654b46a632..f94e6f2528d4b2aad732b561c92f31706eb246ff 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt
@@ -14,27 +14,24 @@ import org.futo.circles.core.extensions.Response
 import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.provider.MatrixInstanceProvider
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.room.CoreSpacesTreeBuilder
 import org.matrix.android.sdk.api.auth.registration.RegistrationResult
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.util.JsonDict
 import javax.inject.Inject
 import javax.inject.Singleton
 
-enum class LoginNavigationEvent { Main, SetupCircles, PassPhrase }
+enum class LoginNavigationEvent { Main, PassPhrase }
 
 @Singleton
 class LoginStagesDataSource @Inject constructor(
     @ApplicationContext private val context: Context,
     private val restoreBackupDataSource: RestoreBackupDataSource,
-    private val coreSpacesTreeBuilder: CoreSpacesTreeBuilder,
     private val encryptionAlgorithmHelper: EncryptionAlgorithmHelper,
     private val createPassPhraseDataSource: CreatePassPhraseDataSource
 ) : BaseLoginStagesDataSource(context) {
 
     val loginNavigationLiveData = SingleEventLiveData<LoginNavigationEvent>()
     val passPhraseLoadingLiveData = restoreBackupDataSource.loadingLiveData
-    val spacesTreeLoadingLiveData = coreSpacesTreeBuilder.loadingLiveData
     val messageEventLiveData = SingleEventLiveData<Int>()
 
     override suspend fun performLoginStage(
@@ -113,17 +110,12 @@ class LoginStagesDataSource @Inject constructor(
     private suspend fun handleRestoreResult(restoreResult: Response<Unit>): Response<Unit> {
         when (restoreResult) {
             is Response.Error -> loginNavigationLiveData.postValue(LoginNavigationEvent.PassPhrase)
-            is Response.Success -> createSpacesTreeIfNotExist()
+            is Response.Success -> navigateToMain()
         }
         return restoreResult
     }
 
-    suspend fun createSpacesTreeIfNotExist() {
-        val isCirclesCreated = coreSpacesTreeBuilder.isCirclesHierarchyCreated()
-        if (!isCirclesCreated) createResult { coreSpacesTreeBuilder.createCoreSpacesTree() }
-        loginNavigationLiveData.postValue(
-            if (isCirclesCreated) LoginNavigationEvent.Main
-            else LoginNavigationEvent.SetupCircles
-        )
+    fun navigateToMain() {
+        loginNavigationLiveData.postValue(LoginNavigationEvent.Main)
     }
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt
index 2b98a27c77aa0a092b0b8e573f6e5c66332c2817..610bf135a5491f278f8e915eadf65cd604da49e4 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt
@@ -17,7 +17,6 @@ class LoginStagesViewModel @Inject constructor(
     val restoreKeysLiveData = org.futo.circles.core.SingleEventLiveData<Response<Unit>>()
     val loginNavigationLiveData = loginStagesDataSource.loginNavigationLiveData
     val passPhraseLoadingLiveData = loginStagesDataSource.passPhraseLoadingLiveData
-    val spacesTreeLoadingLiveData = loginStagesDataSource.spacesTreeLoadingLiveData
     val messageEventLiveData = loginStagesDataSource.messageEventLiveData
 
     fun restoreBackupWithPassPhrase(passphrase: String) {
@@ -41,7 +40,7 @@ class LoginStagesViewModel @Inject constructor(
     }
 
     fun onDoNotRestoreBackup() {
-        launchBg { loginStagesDataSource.createSpacesTreeIfNotExist() }
+        loginStagesDataSource.navigateToMain()
     }
 
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt
index 1a93ce63e0c0ee9ba74ea6fa6e8b0701a22f6178..145a87cc560062cfb1a744248644eb9b26e854bb 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt
@@ -27,12 +27,7 @@ class CreatePassPhraseDataSource @Inject constructor(
     val loadingLiveData = MutableLiveData<LoadingData>()
 
     suspend fun createPassPhraseBackup() {
-        loadingLiveData.postValue(
-            LoadingData(
-                total = 0,
-                messageId = R.string.generating_recovery_key
-            )
-        )
+        loadingLiveData.postValue(LoadingData(messageId = R.string.generating_recovery_key))
         val keyBackupPrivateKey = generateRandomPrivateKey()
         val backupCreationInfo = awaitCallback {
             keysBackupService.prepareKeysBackupVersion(keyBackupPrivateKey, it)
@@ -49,7 +44,7 @@ class CreatePassPhraseDataSource @Inject constructor(
     }
 
     suspend fun changeBsSpekePassword4SKey() {
-        loadingLiveData.postValue(LoadingData(total = 0, messageId = R.string.creating_backup))
+        loadingLiveData.postValue(LoadingData(messageId = R.string.creating_backup))
         ssssDataSource.replaceBsSpeke4SKey()
         loadingLiveData.postValue(LoadingData(isLoading = false))
     }
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt
index bc4330ed24c7398cc1b436940cfac027383b9e14..761dc679a9db9fb908c6981ecf8a1cb818640c07 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt
@@ -10,7 +10,6 @@ import by.kirich1409.viewbindingdelegate.viewBinding
 import dagger.hilt.android.AndroidEntryPoint
 import org.futo.circles.auth.R
 import org.futo.circles.auth.databinding.FragmentSetupProfileBinding
-import org.futo.circles.core.CirclesAppConfig
 import org.futo.circles.core.extensions.getText
 import org.futo.circles.core.extensions.navigateSafe
 import org.futo.circles.core.extensions.observeData
@@ -35,7 +34,7 @@ class SetupProfileFragment : Fragment(R.layout.fragment_setup_profile), HasLoadi
 
     private fun setupViews() {
         with(binding) {
-            btnSkip.setOnClickListener { navigateToSetupCirclesOrHome() }
+            btnSkip.setOnClickListener { navigateToHome() }
             btnSave.setOnClickListener {
                 startLoading(btnSave)
                 viewModel.saveProfileInfo(tilDisplayName.getText())
@@ -62,17 +61,12 @@ class SetupProfileFragment : Fragment(R.layout.fragment_setup_profile), HasLoadi
         }
         viewModel.saveProfileResponseLiveData.observeResponse(
             this,
-            success = { navigateToSetupCirclesOrHome() }
+            success = { navigateToHome() }
         )
     }
 
-    private fun navigateToSetupCirclesOrHome() {
-        findNavController().navigateSafe(
-            if (CirclesAppConfig.isSetupCirclesEnabled)
-                SetupProfileFragmentDirections.toSetupCirclesFragment()
-            else
-                SetupProfileFragmentDirections.toHomeFragment()
-        )
+    private fun navigateToHome() {
+        findNavController().navigateSafe(SetupProfileFragmentDirections.toHomeFragment())
     }
 
     private fun setSaveButtonEnabled() {
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt
index d7c75f5b7bc6b26dd0296196eb2fa22f2357c7d9..df076973c395c64e2a216cbbfff25325934c0c13 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt
@@ -14,7 +14,6 @@ import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.provider.MatrixInstanceProvider
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.provider.PreferencesProvider
-import org.futo.circles.core.room.CoreSpacesTreeBuilder
 import org.matrix.android.sdk.api.auth.registration.RegistrationResult
 import org.matrix.android.sdk.api.auth.registration.Stage
 import org.matrix.android.sdk.api.session.Session
@@ -27,7 +26,6 @@ enum class SignUpNavigationEvents { TokenValidation, Subscription, AcceptTerm, V
 @Singleton
 class SignUpDataSource @Inject constructor(
     @ApplicationContext private val context: Context,
-    private val coreSpacesTreeBuilder: CoreSpacesTreeBuilder,
     private val createPassPhraseDataSource: CreatePassPhraseDataSource,
     private val preferencesProvider: PreferencesProvider
 ) {
@@ -36,7 +34,6 @@ class SignUpDataSource @Inject constructor(
     val navigationLiveData = SingleEventLiveData<SignUpNavigationEvents>()
     val finishRegistrationLiveData = SingleEventLiveData<Response<Unit>>()
     val passPhraseLoadingLiveData = createPassPhraseDataSource.loadingLiveData
-    val spaceTreeLoadingLiveData = coreSpacesTreeBuilder.loadingLiveData
 
     val stagesToComplete = mutableListOf<Stage>()
 
@@ -117,7 +114,6 @@ class SignUpDataSource @Inject constructor(
         MatrixSessionProvider.awaitForSessionStart(session)
         preferencesProvider.setShouldShowAllExplanations()
         createPassPhraseDataSource.createPassPhraseBackup()
-        coreSpacesTreeBuilder.createCoreSpacesTree()
         BSSpekeClientProvider.clear()
     }
 
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt
index bd780308449cc10cb08ff01bceba439192794929..e0a6a229aa011fce81cffac7cc2147255acb89ba 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt
@@ -47,7 +47,7 @@ class SignUpFragment : Fragment(R.layout.fragment_sign_up),
             handleNavigation(it)
         }
         viewModel.finishRegistrationLiveData.observeResponse(this,
-            success = { navigateToSetupProfile() },
+            success = { navigateToConfigureWorspace() },
             error = { message ->
                 showError(message)
                 loadingDialog.dismiss()
@@ -56,9 +56,6 @@ class SignUpFragment : Fragment(R.layout.fragment_sign_up),
         viewModel.passPhraseLoadingLiveData.observeData(this) {
             loadingDialog.handleLoading(it)
         }
-        viewModel.spaceTreeLoadingLiveData.observeData(this) {
-            loadingDialog.handleLoading(it)
-        }
     }
 
 
@@ -96,8 +93,8 @@ class SignUpFragment : Fragment(R.layout.fragment_sign_up),
         }
     }
 
-    private fun navigateToSetupProfile() {
-        findNavController().navigateSafe(SignUpFragmentDirections.toSetupProfileFragment())
+    private fun navigateToConfigureWorspace() {
+        findNavController().navigateSafe(SignUpFragmentDirections.toConfigureWorkspace())
     }
 
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt
index e47ecf65446861a51ecc9c24d460040c09cb109a..039bc2140d3cb7fd01c5e9e704fb3e3cc87efc02 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt
@@ -11,7 +11,6 @@ class SignUpViewModel @Inject constructor(
 
     val subtitleLiveData = datasource.subtitleLiveData
     val passPhraseLoadingLiveData = datasource.passPhraseLoadingLiveData
-    val spaceTreeLoadingLiveData = datasource.spaceTreeLoadingLiveData
     val finishRegistrationLiveData = datasource.finishRegistrationLiveData
     val navigationLiveData = datasource.navigationLiveData
 
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..071bc2ba0aea567ce2da51476a781778943ea9fa
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceFragment.kt
@@ -0,0 +1,96 @@
+package org.futo.circles.auth.feature.workspace
+
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import androidx.core.os.bundleOf
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.DividerItemDecoration
+import by.kirich1409.viewbindingdelegate.viewBinding
+import dagger.hilt.android.AndroidEntryPoint
+import org.futo.circles.auth.R
+import org.futo.circles.auth.databinding.FragmentConfigureWorkspaceBinding
+import org.futo.circles.auth.feature.workspace.list.WorkspaceTasksListAdapter
+import org.futo.circles.core.extensions.navigateSafe
+import org.futo.circles.core.extensions.observeData
+import org.futo.circles.core.extensions.observeResponse
+import org.futo.circles.core.extensions.showError
+import org.futo.circles.core.fragment.HasLoadingState
+
+@AndroidEntryPoint
+class ConfigureWorkspaceFragment : Fragment(R.layout.fragment_configure_workspace),
+    HasLoadingState {
+
+    override val fragment: Fragment = this
+    private val viewModel by viewModels<ConfigureWorkspaceViewModel>()
+
+    private val binding by viewBinding(FragmentConfigureWorkspaceBinding::bind)
+
+    private val tasksAdapter by lazy {
+        WorkspaceTasksListAdapter { viewModel.onOptionalTaskSelectionChanged(it) }
+    }
+
+    private var configureWorkspaceListener: ConfigureWorkspaceListener? = null
+
+    override fun onAttach(context: Context) {
+        super.onAttach(context)
+        configureWorkspaceListener = (parentFragment as? ConfigureWorkspaceListener)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        setupViews()
+        setupObservers()
+    }
+
+    private fun setupViews() {
+        with(binding) {
+            val shouldValidate = arguments?.getBoolean(SHOULD_VALIDATE) ?: false
+            toolbar.title =
+                getString(if (shouldValidate) R.string.validating_workspace else R.string.configure_workspace)
+
+            if (shouldValidate) startLoading(btbConfigure)
+
+            rvWorkspaceTasks.apply {
+                adapter = tasksAdapter
+                addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
+            }
+            btbConfigure.setOnClickListener {
+                startLoading(btbConfigure)
+                viewModel.createWorkspace()
+            }
+        }
+    }
+
+    private fun setupObservers() {
+        viewModel.tasksLiveData.observeData(this) {
+            tasksAdapter.submitList(it)
+        }
+        viewModel.workspaceResultLiveData.observeResponse(this,
+            success = {
+                configureWorkspaceListener?.onWorkspaceConfigured() ?: kotlin.run {
+                    findNavController()
+                        .navigateSafe(ConfigureWorkspaceFragmentDirections.toSetupProfileFragment())
+                }
+            },
+            error = {
+                showError(it)
+                binding.btbConfigure.setText(getString(R.string.retry))
+            })
+        viewModel.validateWorkspaceResultLiveData.observeResponse(this,
+            success = { configureWorkspaceListener?.onWorkspaceConfigured() },
+            error = {
+                binding.toolbar.title = getString(R.string.configure_workspace)
+            }
+        )
+    }
+
+    companion object {
+        const val SHOULD_VALIDATE = "should_validate"
+        fun create(shouldValidate: Boolean) = ConfigureWorkspaceFragment().apply {
+            arguments = bundleOf(SHOULD_VALIDATE to shouldValidate)
+        }
+    }
+}
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceListener.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceListener.kt
new file mode 100644
index 0000000000000000000000000000000000000000..62e6b2d453f55b4828746d879df8c1c5799ee0be
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceListener.kt
@@ -0,0 +1,6 @@
+package org.futo.circles.auth.feature.workspace
+
+interface ConfigureWorkspaceListener {
+    fun onWorkspaceConfigured()
+
+}
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5725dc656df6a57c59580c3771ae1d2ca9e3c5f8
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceViewModel.kt
@@ -0,0 +1,103 @@
+package org.futo.circles.auth.feature.workspace
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.futo.circles.auth.feature.workspace.data_source.ConfigureWorkspaceDataSource
+import org.futo.circles.auth.feature.workspace.data_source.WorkspaceTasksProvider
+import org.futo.circles.auth.model.MandatoryWorkspaceTask
+import org.futo.circles.auth.model.OptionalWorkspaceTask
+import org.futo.circles.core.SingleEventLiveData
+import org.futo.circles.core.extensions.Response
+import org.futo.circles.core.extensions.createResult
+import org.futo.circles.core.extensions.launchBg
+import org.futo.circles.core.model.TaskStatus
+import javax.inject.Inject
+
+@HiltViewModel
+class ConfigureWorkspaceViewModel @Inject constructor(
+    savedStateHandle: SavedStateHandle,
+    workspaceTasksProvider: WorkspaceTasksProvider,
+    private val workspaceDataSource: ConfigureWorkspaceDataSource
+) : ViewModel() {
+
+    private val shouldValidate =
+        savedStateHandle.get<Boolean>(ConfigureWorkspaceFragment.SHOULD_VALIDATE) ?: false
+    val tasksLiveData = MutableLiveData(
+        if (shouldValidate) workspaceTasksProvider.getMandatoryTasks()
+        else workspaceTasksProvider.getFullTasksList()
+    )
+    val workspaceResultLiveData = SingleEventLiveData<Response<Unit>>()
+    val validateWorkspaceResultLiveData = SingleEventLiveData<Response<Unit>>()
+
+    init {
+        if (shouldValidate) validateWorkspace()
+    }
+
+    private fun validateWorkspace() = launchBg {
+        val tasks = tasksLiveData.value?.toMutableList() ?: mutableListOf()
+        var hasError = false
+        tasks.forEachIndexed { i, item ->
+            updateTaskStatus(i, TaskStatus.RUNNING)
+            when (createResult { workspaceDataSource.validate(item.room) }) {
+                is Response.Error -> {
+                    hasError = true
+                    updateTaskStatus(i, TaskStatus.FAILED)
+                }
+
+                is Response.Success -> updateTaskStatus(i, TaskStatus.SUCCESS)
+            }
+        }
+        validateWorkspaceResultLiveData.postValue(
+            if (hasError) Response.Error("") else Response.Success(Unit)
+        )
+    }
+
+    fun createWorkspace() = launchBg {
+        val tasks = tasksLiveData.value?.toMutableList() ?: mutableListOf()
+        tasks.forEachIndexed { i, item ->
+            (item as? OptionalWorkspaceTask)?.let { if (!it.isSelected) return@forEachIndexed }
+            if (item.status == TaskStatus.SUCCESS) return@forEachIndexed
+
+            updateTaskStatus(i, TaskStatus.RUNNING)
+            when (val result = createResult { workspaceDataSource.performCreateOrFix(item.room) }) {
+                is Response.Error -> {
+                    updateTaskStatus(i, TaskStatus.FAILED)
+                    workspaceResultLiveData.postValue(result)
+                    return@launchBg
+                }
+
+                is Response.Success -> updateTaskStatus(i, TaskStatus.SUCCESS)
+            }
+        }
+        workspaceResultLiveData.postValue(Response.Success(Unit))
+    }
+
+    fun onOptionalTaskSelectionChanged(optionalWorkspaceTask: OptionalWorkspaceTask) {
+        val newList = tasksLiveData.value?.toMutableList()?.apply {
+            val index = indexOf(optionalWorkspaceTask).takeIf { it != -1 } ?: return
+            add(index, optionalWorkspaceTask.copy(isSelected = !optionalWorkspaceTask.isSelected))
+            remove(optionalWorkspaceTask)
+        }
+        tasksLiveData.value = newList
+    }
+
+    private suspend fun updateTaskStatus(index: Int, status: TaskStatus) {
+        val tasks = tasksLiveData.value?.toMutableList() ?: mutableListOf()
+        val task = tasks.getOrNull(index) ?: return
+        val newList = tasks.toMutableList().apply {
+            add(
+                index, when (task) {
+                    is MandatoryWorkspaceTask -> task.copy(status = status)
+                    is OptionalWorkspaceTask -> task.copy(status = status)
+                }
+            )
+            remove(task)
+        }
+        withContext(Dispatchers.Main) { tasksLiveData.value = newList }
+    }
+
+}
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/WorkspaceDialogFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/WorkspaceDialogFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..388f0dc0cf690353e6e6d14a1c9c4410484e5d5c
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/WorkspaceDialogFragment.kt
@@ -0,0 +1,32 @@
+package org.futo.circles.auth.feature.workspace
+
+import android.os.Bundle
+import android.view.View
+import dagger.hilt.android.AndroidEntryPoint
+import org.futo.circles.auth.R
+import org.futo.circles.auth.databinding.DialogFragmentWorkspaceBinding
+import org.futo.circles.core.extensions.showSuccess
+import org.futo.circles.core.fragment.BaseFullscreenDialogFragment
+
+@AndroidEntryPoint
+class WorkspaceDialogFragment :
+    BaseFullscreenDialogFragment(DialogFragmentWorkspaceBinding::inflate),
+    ConfigureWorkspaceListener {
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        isCancelable = false
+        addConfigureWorkspaceFragment()
+    }
+
+    private fun addConfigureWorkspaceFragment() {
+        childFragmentManager.beginTransaction()
+            .replace(R.id.lContainer, ConfigureWorkspaceFragment.create(true))
+            .commitAllowingStateLoss()
+    }
+
+    override fun onWorkspaceConfigured() {
+        showSuccess(getString(R.string.workspace_configured))
+        dismiss()
+    }
+}
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8c8d1f2b423d70be568d297200ad74bb58becc05
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt
@@ -0,0 +1,105 @@
+package org.futo.circles.auth.feature.workspace.data_source
+
+import kotlinx.coroutines.delay
+import org.futo.circles.core.model.CirclesRoom
+import org.futo.circles.core.provider.MatrixSessionProvider
+import org.futo.circles.core.room.CreateRoomDataSource
+import org.futo.circles.core.room.RoomRelationsBuilder
+import org.futo.circles.core.utils.getJoinedRoomById
+import org.futo.circles.core.workspace.SpacesTreeAccountDataSource
+import org.matrix.android.sdk.api.session.room.Room
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
+import javax.inject.Inject
+
+class ConfigureWorkspaceDataSource @Inject constructor(
+    private val createRoomDataSource: CreateRoomDataSource,
+    private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource,
+    private val roomRelationsBuilder: RoomRelationsBuilder
+) {
+
+    suspend fun performCreateOrFix(room: CirclesRoom) {
+        var roomId = addIdToAccountDataIfRoomExistWithTag(room)
+        if (roomId == null) roomId = getJoinedRoomIdFromAccountData(room)
+        if (roomId == null) createRoomWithAccountDataRecordIfNeed(room)
+        else {
+            try {
+                getJoinedRoomById(roomId)?.let { validateRelations(room.parentAccountDataKey, it) }
+            } catch (_: Exception) {
+                val parentRoomId =
+                    room.parentAccountDataKey?.let { spacesTreeAccountDataSource.getRoomIdByKey(it) }
+                parentRoomId?.let { roomRelationsBuilder.setRelations(roomId, parentRoomId) }
+            }
+        }
+    }
+
+    fun validate(room: CirclesRoom) {
+        val accountDataKey = room.accountDataKey ?: return
+        val roomId = spacesTreeAccountDataSource.getRoomIdByKey(accountDataKey)
+            ?: throw IllegalArgumentException("No account data record for key $accountDataKey")
+        val joinedRoom = getJoinedRoomById(roomId)
+            ?: throw IllegalArgumentException("No joined room for id $roomId found")
+        validateRelations(room.parentAccountDataKey, joinedRoom)
+    }
+
+    private fun validateRelations(parentAccountDataKey: String?, joinedRoom: Room) {
+        val parentKey = parentAccountDataKey ?: return
+        val parentRoomId =
+            spacesTreeAccountDataSource.getRoomIdByKey(parentKey) ?: throw IllegalArgumentException(
+                "No account data record for parent with key $parentKey"
+            )
+        val joinedParentRoom = getJoinedRoomById(parentRoomId)
+            ?: throw IllegalArgumentException("No joined parent room for id $parentKey found")
+
+        val childHasRelationToParent = joinedRoom.asSpace()
+            ?.spaceSummary()?.spaceParents?.mapNotNull { it.parentId }
+            ?.contains(parentRoomId) == true
+
+        if (!childHasRelationToParent)
+            throw IllegalArgumentException("Missing child to parent relations")
+
+        val parentHasRelationToChild = joinedParentRoom.asSpace()
+            ?.spaceSummary()?.spaceChildren?.map { it.childRoomId }
+            ?.contains(joinedRoom.roomId) == true
+
+        if (!parentHasRelationToChild)
+            throw IllegalArgumentException("Missing parent to child relations")
+    }
+
+    private suspend fun addIdToAccountDataIfRoomExistWithTag(room: CirclesRoom): String? {
+        val tag = room.getTag() ?: return null
+        val key = room.accountDataKey ?: return null
+        val roomId = getJoinedRoomIdByTag(tag) ?: return null
+        spacesTreeAccountDataSource.updateSpacesConfigAccountData(key, roomId)
+        return roomId
+    }
+
+    private fun getJoinedRoomIdByTag(tag: String): String? {
+        val session = MatrixSessionProvider.currentSession ?: return null
+        return session.roomService().getRoomSummaries(roomSummaryQueryParams {
+            excludeType = null
+            memberships = listOf(Membership.JOIN)
+        }).firstOrNull { it.hasTag(tag) }?.roomId
+    }
+
+    private fun getJoinedRoomIdFromAccountData(room: CirclesRoom): String? {
+        val key = room.accountDataKey ?: return null
+        val roomId = spacesTreeAccountDataSource.getRoomIdByKey(key) ?: return null
+        getJoinedRoomById(roomId) ?: return null
+        return roomId
+    }
+
+    private suspend fun createRoomWithAccountDataRecordIfNeed(room: CirclesRoom): String {
+        val roomId = createRoomDataSource.createRoom(room)
+        room.accountDataKey?.let { key ->
+            spacesTreeAccountDataSource.updateSpacesConfigAccountData(key, roomId)
+        }
+        delay(CREATE_ROOM_DELAY)
+        return roomId
+    }
+
+    private companion object {
+        private const val CREATE_ROOM_DELAY = 1000L
+    }
+
+}
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/WorkspaceTasksProvider.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/WorkspaceTasksProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..928e884f90a329e29ef27188600c0f751a27b934
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/WorkspaceTasksProvider.kt
@@ -0,0 +1,49 @@
+package org.futo.circles.auth.feature.workspace.data_source
+
+import org.futo.circles.auth.R
+import org.futo.circles.auth.model.MandatoryWorkspaceTask
+import org.futo.circles.auth.model.OptionalWorkspaceTask
+import org.futo.circles.auth.model.WorkspaceTask
+import org.futo.circles.core.model.Circle
+import org.futo.circles.core.model.CirclesSpace
+import org.futo.circles.core.model.Gallery
+import org.futo.circles.core.model.GroupsSpace
+import org.futo.circles.core.model.PeopleSpace
+import org.futo.circles.core.model.PhotosSpace
+import org.futo.circles.core.model.RootSpace
+import org.futo.circles.core.model.SharedCirclesSpace
+import javax.inject.Inject
+
+class WorkspaceTasksProvider @Inject constructor() {
+
+    fun getFullTasksList() = mutableListOf<WorkspaceTask>().apply {
+        addAll(getMandatoryTasks())
+        addAll(getOptionalTasks())
+    }
+
+    fun getMandatoryTasks() = listOf(
+        MandatoryWorkspaceTask(RootSpace(), R.string.root_space_description),
+        MandatoryWorkspaceTask(CirclesSpace(), R.string.circles_space_description),
+        MandatoryWorkspaceTask(GroupsSpace(), R.string.groups_space_description),
+        MandatoryWorkspaceTask(PhotosSpace(), R.string.galleries_space_description),
+        MandatoryWorkspaceTask(PeopleSpace(), R.string.people_space_description),
+        MandatoryWorkspaceTask(SharedCirclesSpace(), R.string.profile_space_description)
+    )
+
+    private fun getOptionalTasks() = listOf(
+        OptionalWorkspaceTask(
+            Gallery(nameId = org.futo.circles.core.R.string.photos),
+            R.string.photos_room_description
+        ),
+        OptionalWorkspaceTask(
+            Circle(nameId = R.string.friends),
+            R.string.friends_circle_description
+        ),
+        OptionalWorkspaceTask(Circle(nameId = R.string.family), R.string.family_circle_description),
+        OptionalWorkspaceTask(
+            Circle(nameId = R.string.community),
+            R.string.community_circle_description
+        )
+    )
+
+}
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTaskViewHolder.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTaskViewHolder.kt
new file mode 100644
index 0000000000000000000000000000000000000000..711a3287a379b0421f338cc6038f2996611e6b7f
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTaskViewHolder.kt
@@ -0,0 +1,97 @@
+package org.futo.circles.auth.feature.workspace.list
+
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.ProgressBar
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.RecyclerView
+import org.futo.circles.auth.R
+import org.futo.circles.auth.databinding.ListItemMandatoryWorkspaceTaskBinding
+import org.futo.circles.auth.databinding.ListItemOptionalWorkspaceTaskBinding
+import org.futo.circles.core.extensions.gone
+import org.futo.circles.core.extensions.onClick
+import org.futo.circles.core.extensions.visible
+import org.futo.circles.core.list.ViewBindingHolder
+import org.futo.circles.core.list.context
+import org.futo.circles.auth.model.OptionalWorkspaceTask
+import org.futo.circles.core.model.TaskStatus
+import org.futo.circles.auth.model.WorkspaceTask
+
+
+abstract class WorkspaceTaskViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+    abstract fun bind(data: WorkspaceTask)
+
+    protected fun bindStatus(status: TaskStatus, ivStatus: ImageView, vTaskProgress: ProgressBar) {
+        when (status) {
+            TaskStatus.RUNNING -> {
+                ivStatus.gone()
+                vTaskProgress.visible()
+            }
+
+            TaskStatus.IDLE -> {
+                ivStatus.gone()
+                vTaskProgress.gone()
+            }
+
+            else -> {
+                vTaskProgress.gone()
+                ivStatus.apply {
+                    visible()
+                    setImageResource(
+                        if (status == TaskStatus.FAILED) org.futo.circles.core.R.drawable.ic_error
+                        else org.futo.circles.core.R.drawable.ic_check_circle
+                    )
+                    setColorFilter(
+                        ContextCompat.getColor(
+                            context,
+                            if (status == TaskStatus.FAILED) R.color.red
+                            else R.color.blue
+                        )
+                    )
+                }
+            }
+        }
+    }
+
+}
+
+class MandatoryWorkspaceTaskViewHolder(
+    parent: ViewGroup,
+) : WorkspaceTaskViewHolder(inflate(parent, ListItemMandatoryWorkspaceTaskBinding::inflate)) {
+
+    private companion object : ViewBindingHolder
+
+    private val binding = baseBinding as ListItemMandatoryWorkspaceTaskBinding
+
+    override fun bind(data: WorkspaceTask) {
+        with(binding) {
+            data.room.nameId?.let { tvName.text = context.getString(it) }
+            tvMessage.text = context.getString(data.descriptionResId)
+            bindStatus(data.status, ivTaskStatus, taskProgress)
+        }
+    }
+}
+
+class OptionalWorkspaceTaskViewHolder(
+    parent: ViewGroup,
+    onItemClicked: (Int) -> Unit
+) : WorkspaceTaskViewHolder(inflate(parent, ListItemOptionalWorkspaceTaskBinding::inflate)) {
+
+    private companion object : ViewBindingHolder
+
+    private val binding = baseBinding as ListItemOptionalWorkspaceTaskBinding
+
+    init {
+        onClick(binding.rootItem) { onItemClicked(it) }
+    }
+
+    override fun bind(data: WorkspaceTask) {
+        with(binding.lTask) {
+            data.room.nameId?.let { tvName.text = context.getString(it) }
+            tvMessage.text = context.getString(data.descriptionResId)
+            bindStatus(data.status, ivTaskStatus, taskProgress)
+        }
+        binding.taskCheck.isChecked = (data as? OptionalWorkspaceTask)?.isSelected ?: false
+    }
+}
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTasksListAdapter.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTasksListAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1c3ab190243c7d6b400f361de2a03643b6171890
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTasksListAdapter.kt
@@ -0,0 +1,40 @@
+package org.futo.circles.auth.feature.workspace.list
+
+import android.view.ViewGroup
+import org.futo.circles.core.list.BaseRvAdapter
+import org.futo.circles.auth.model.MandatoryWorkspaceTask
+import org.futo.circles.auth.model.OptionalWorkspaceTask
+import org.futo.circles.auth.model.WorkspaceTask
+
+private enum class WorkspaceTaskViewType { Mandatory, Optional }
+
+class WorkspaceTasksListAdapter(
+    private val onOptionalItemClicked: (OptionalWorkspaceTask) -> Unit
+) : BaseRvAdapter<WorkspaceTask, WorkspaceTaskViewHolder>(DefaultIdEntityCallback()) {
+
+    override fun getItemViewType(position: Int): Int = when (getItem(position)) {
+        is MandatoryWorkspaceTask -> WorkspaceTaskViewType.Mandatory.ordinal
+        is OptionalWorkspaceTask -> WorkspaceTaskViewType.Optional.ordinal
+    }
+
+    override fun onCreateViewHolder(
+        parent: ViewGroup,
+        viewType: Int
+    ) = when (WorkspaceTaskViewType.values()[viewType]) {
+        WorkspaceTaskViewType.Mandatory -> MandatoryWorkspaceTaskViewHolder(parent = parent)
+
+        WorkspaceTaskViewType.Optional -> OptionalWorkspaceTaskViewHolder(
+            parent = parent,
+            onItemClicked = { position ->
+                (getItem(position) as? OptionalWorkspaceTask)?.let {
+                    onOptionalItemClicked.invoke(it)
+                }
+            }
+        )
+    }
+
+    override fun onBindViewHolder(holder: WorkspaceTaskViewHolder, position: Int) {
+        holder.bind(getItem(position))
+    }
+
+}
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/model/WorkspaceTask.kt b/auth/src/main/java/org/futo/circles/auth/model/WorkspaceTask.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c6815d089c3d00f89b8bc0db9933ca2c5043baa8
--- /dev/null
+++ b/auth/src/main/java/org/futo/circles/auth/model/WorkspaceTask.kt
@@ -0,0 +1,29 @@
+package org.futo.circles.auth.model
+
+import org.futo.circles.core.list.IdEntity
+import org.futo.circles.core.model.CirclesRoom
+import org.futo.circles.core.model.TaskStatus
+
+sealed class WorkspaceTask(
+    open val room: CirclesRoom,
+    open val descriptionResId: Int,
+    open val status: TaskStatus
+) : IdEntity<Int>
+
+
+data class MandatoryWorkspaceTask(
+    override val room: CirclesRoom,
+    override val descriptionResId: Int,
+    override val status: TaskStatus = TaskStatus.IDLE
+) : WorkspaceTask(room, descriptionResId, status) {
+    override val id: Int = descriptionResId
+}
+
+data class OptionalWorkspaceTask(
+    override val room: CirclesRoom,
+    override val descriptionResId: Int,
+    override val status: TaskStatus = TaskStatus.IDLE,
+    val isSelected: Boolean = true
+) : WorkspaceTask(room, descriptionResId, status) {
+    override val id: Int = descriptionResId
+}
\ No newline at end of file
diff --git a/auth/src/main/res/layout/dialog_fragment_workspace.xml b/auth/src/main/res/layout/dialog_fragment_workspace.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1b88477e231734b97709bd709e9eef02929cd74b
--- /dev/null
+++ b/auth/src/main/res/layout/dialog_fragment_workspace.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/lContainer"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/auth/src/main/res/layout/fragment_configure_workspace.xml b/auth/src/main/res/layout/fragment_configure_workspace.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7ad151308cfa272c72be76d654cd29358a6ee5c6
--- /dev/null
+++ b/auth/src/main/res/layout/fragment_configure_workspace.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.google.android.material.appbar.MaterialToolbar
+        android:id="@+id/toolbar"
+        android:layout_width="0dp"
+        android:layout_height="?attr/actionBarSize"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:title="@string/configure_workspace"
+        app:titleCentered="true" />
+
+    <View
+        android:id="@+id/toolbarDivider"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/divider_height"
+        android:background="@color/divider_color"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/toolbar" />
+
+    <TextView
+        android:id="@+id/tvMessage"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:gravity="center_horizontal"
+        android:text="@string/setup_workspace_message"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/toolbarDivider" />
+
+    <View
+        android:id="@+id/messageDivider"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/divider_height"
+        android:layout_marginTop="8dp"
+        android:background="@color/divider_color"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/tvMessage" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/rvWorkspaceTasks"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+        app:layout_constraintBottom_toTopOf="@id/buttonDivider"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/messageDivider" />
+
+    <View
+        android:id="@+id/buttonDivider"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/divider_height"
+        android:layout_marginBottom="8dp"
+        android:background="@color/divider_color"
+        app:layout_constraintBottom_toTopOf="@id/btbConfigure"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <org.futo.circles.core.view.LoadingButton
+        android:id="@+id/btbConfigure"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginHorizontal="36dp"
+        android:layout_marginBottom="16dp"
+        android:text="@string/configure"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/auth/src/main/res/layout/list_item_mandatory_workspace_task.xml b/auth/src/main/res/layout/list_item_mandatory_workspace_task.xml
new file mode 100644
index 0000000000000000000000000000000000000000..84a748e6971714c3bd19bf2782c22756d5dbba62
--- /dev/null
+++ b/auth/src/main/res/layout/list_item_mandatory_workspace_task.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/lRoot"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingHorizontal="8dp"
+    android:paddingVertical="4dp">
+
+
+    <TextView
+        android:id="@+id/tvName"
+        style="@style/body"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="36dp"
+        android:ellipsize="end"
+        android:lines="1"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="Android01" />
+
+    <TextView
+        android:id="@+id/tvMessage"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="36dp"
+        android:ellipsize="end"
+        android:maxLines="4"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/tvName"
+        tools:text="Android01" />
+
+    <ProgressBar
+        android:id="@+id/taskProgress"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        app:layout_constraintBottom_toBottomOf="@id/tvMessage"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <ImageView
+        android:id="@+id/ivTaskStatus"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_check_circle"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="@id/tvMessage"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:tint="@color/blue"
+        tools:visibility="visible" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/auth/src/main/res/layout/list_item_optional_workspace_task.xml b/auth/src/main/res/layout/list_item_optional_workspace_task.xml
new file mode 100644
index 0000000000000000000000000000000000000000..249fa5323d43f9c2689683cef35811244a8a239b
--- /dev/null
+++ b/auth/src/main/res/layout/list_item_optional_workspace_task.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/rootItem"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?selectableItemBackground"
+    android:clickable="true"
+    android:focusable="true">
+
+
+    <com.google.android.material.checkbox.MaterialCheckBox
+        android:id="@+id/taskCheck"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clickable="false"
+        android:padding="-3dp"
+        android:focusable="false"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+
+    <include
+        android:id="@+id/lTask"
+        layout="@layout/list_item_mandatory_workspace_task"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/taskCheck" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/auth/src/main/res/layout/list_item_setup_circle.xml b/auth/src/main/res/layout/list_item_setup_circle.xml
deleted file mode 100644
index 06ae73afb675c6ee4b13666cc4170688ebe354ab..0000000000000000000000000000000000000000
--- a/auth/src/main/res/layout/list_item_setup_circle.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="?selectableItemBackground"
-    android:clickable="true"
-    android:focusable="true"
-    android:padding="4dp">
-
-
-    <com.google.android.material.imageview.ShapeableImageView
-        android:id="@+id/ivCircleCover"
-        android:layout_width="@dimen/group_icon_size"
-        android:layout_height="@dimen/group_icon_size"
-        android:scaleType="centerCrop"
-        android:src="@drawable/add_image_placeholder"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.GroupIconRadius" />
-
-    <TextView
-        android:id="@+id/tvCircleName"
-        style="@style/title2"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:gravity="center"
-        android:lines="1"
-        app:layout_constraintBottom_toTopOf="@id/tvUserName"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@id/ivCircleCover"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintVertical_chainStyle="packed"
-        tools:text="texsdt" />
-
-    <TextView
-        android:id="@+id/tvUserName"
-        style="@style/subheadline"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="4dp"
-        android:ellipsize="end"
-        android:gravity="center"
-        android:lines="1"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="@id/tvCircleName"
-        app:layout_constraintTop_toBottomOf="@id/tvCircleName"
-        tools:text="texsdt" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/auth/src/main/res/navigation/nav_graph_auth.xml b/auth/src/main/res/navigation/nav_graph_auth.xml
index 130ebbc3140b4318758efaf5e6dbf5659dfdd311..70937bba43d1467a34a17b41f04db31465c5ffb6 100644
--- a/auth/src/main/res/navigation/nav_graph_auth.xml
+++ b/auth/src/main/res/navigation/nav_graph_auth.xml
@@ -32,11 +32,6 @@
             app:destination="@id/homeFragment"
             app:popUpTo="@id/logInFragment"
             app:popUpToInclusive="true" />
-        <action
-            android:id="@+id/to_setupCirclesFragment"
-            app:destination="@id/setupCirclesFragment"
-            app:popUpTo="@id/logInFragment"
-            app:popUpToInclusive="true" />
     </fragment>
     <fragment
         android:id="@+id/signUpFragment"
@@ -44,8 +39,8 @@
         android:label="Sign up"
         tools:layout="@layout/fragment_sign_up">
         <action
-            android:id="@+id/to_setupProfileFragment"
-            app:destination="@id/setupProfileFragment"
+            android:id="@+id/to_ConfigureWorkspace"
+            app:destination="@id/configureWorkspaceFragment"
             app:popUpTo="@id/logInFragment"
             app:popUpToInclusive="true" />
     </fragment>
@@ -54,15 +49,21 @@
         android:name="org.futo.circles.auth.feature.profile.setup.SetupProfileFragment"
         android:label="SetupProfileFragment"
         tools:layout="@layout/fragment_setup_profile">
-        <action
-            android:id="@+id/to_setupCirclesFragment"
-            app:destination="@id/setupCirclesFragment"
-            app:popUpTo="@id/setupProfileFragment"
-            app:popUpToInclusive="true" />
+
         <action
             android:id="@+id/to_homeFragment"
             app:destination="@id/homeFragment"
             app:popUpTo="@id/setupProfileFragment"
             app:popUpToInclusive="true" />
     </fragment>
+    <fragment
+        android:id="@+id/configureWorkspaceFragment"
+        android:name="org.futo.circles.auth.feature.workspace.ConfigureWorkspaceFragment"
+        tools:layout="@layout/fragment_configure_workspace">
+        <action
+            android:id="@+id/to_setupProfileFragment"
+            app:destination="@id/setupProfileFragment"
+            app:popUpTo="@id/configureWorkspaceFragment"
+            app:popUpToInclusive="true" />
+    </fragment>
 </navigation>
diff --git a/auth/src/main/res/values/ids.xml b/auth/src/main/res/values/ids.xml
index a3af135fe696c984e82c231d67b9955a9ccac20f..fdc7badf4aca669f2de11019221d4254bc9cf6b4 100644
--- a/auth/src/main/res/values/ids.xml
+++ b/auth/src/main/res/values/ids.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <item name="homeFragment" type="id" />
-    <item name="setupCirclesFragment" type="id" />
 </resources>
\ No newline at end of file
diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml
index 8f380577d5c6dcc0a5d2f470f407da6becb97377..d8fbe864450d30a3ef00547a89d50bf6afc032b3 100644
--- a/auth/src/main/res/values/strings.xml
+++ b/auth/src/main/res/values/strings.xml
@@ -123,6 +123,27 @@
     <string name="got_it">Got it</string>
     <string name="groups">Groups</string>
     <string name="circles">Circles</string>
+    <string name="create">Create</string>
+    <string name="friends">Friends</string>
+    <string name="family">Family</string>
+    <string name="community">Community</string>
+    <string name="retry">Retry</string>
+    <string name="workspace_configured">Workspace configured</string>
+    <string name="validating_workspace">Validating workspace</string>
+    <string name="configure_workspace">Configure workspace</string>
+    <string name="setup_workspace_message">In order to use app we needs to configure your workspace. \nWe will create root spaces listed below and setup all the necessary relations between them.</string>
+    <string name="root_space_description">Root space of workspace hierarchy</string>
+    <string name="groups_space_description">Space which will contain all the Groups</string>
+    <string name="circles_space_description">Space which will contain all the Circles</string>
+    <string name="galleries_space_description">Space which will contain all the Galleries</string>
+    <string name="people_space_description">Space which will contain all the connected users</string>
+    <string name="profile_space_description">Space which will contain all your public Circles. Other users will be able to ask to join this space to follow you</string>
+    <string name="photos_room_description">Optional: Photos gallery room for your media. You will be able to create it anytime</string>
+    <string name="friends_circle_description">Optional: Circle to follow your friends timelines. You will be able to create it anytime</string>
+    <string name="family_circle_description">Optional: Circle to follow your family members timelines. You will be able to create it anytime</string>
+    <string name="community_circle_description">Optional: Circle to follow other people timelines. You will be able to create it anytime</string>
+
+
     <string name="circle_explanation"><![CDATA[Tip: A <b>circle</b> works like a secure, private version of Facebook or Twitter.  Everyone posts to their own timeline, and you see posts from all the timelines that you\'re following.
 <br/><br/>A circle is a good way to share things with lots of people who don\'t all know each other, but they all know you.
 <br/><br/>For example, think about all the aunts and uncles and cousins from the different sides of your family.
@@ -132,6 +153,7 @@ Or, think about all of your friends across all of the places you\'ve ever lived.
 <br/><br/>Everyone in the group posts to the same timeline, and everyone in the group can see every post.
 <br/><br/>For example, you might want to create a group for your book club, or your sports team, or your scout troop.
 <br/><br/>If you want to share with lots of different people who <i>don\'t</i> all know each other, then you should invite those people to follow you in a <b>Circle</b> instead.]]></string>
+    <string name="configure">Configure</string>
 
     <plurals name="days">
         <item quantity="one">%1$d day</item>
diff --git a/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt b/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt
index 9e3cc66bccf97de53dc1418dc4c2f88953080ac8..25844cca32f78c621fa4ab64f247cb2929358afd 100644
--- a/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt
+++ b/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt
@@ -28,9 +28,6 @@ object CirclesAppConfig {
     var isRageshakeEnabled = false
         private set
 
-    var isSetupCirclesEnabled = true
-        private set
-
     data class Initializer(
         private var appId: String? = null,
         private var version: String? = null,
@@ -40,8 +37,7 @@ object CirclesAppConfig {
         private var euDomain: String? = null,
         private var subscriptionEnabled: Boolean = false,
         private var mediaBackupEnabled: Boolean = false,
-        private var rageshakeEnabled: Boolean = false,
-        private var setupCirclesEnabled: Boolean = true
+        private var rageshakeEnabled: Boolean = false
     ) {
 
         fun buildConfigInfo(appId: String, version: String, flavour: String = "empty") =
@@ -64,8 +60,6 @@ object CirclesAppConfig {
 
         fun isRageshakeEnabled(isEnabled: Boolean) = apply { this.rageshakeEnabled = isEnabled }
 
-        fun isSetupCirclesEnabled(isEnabled: Boolean) =
-            apply { this.setupCirclesEnabled = isEnabled }
 
         fun init() {
             CirclesAppConfig.appId = appId?.takeIf { it.isNotEmpty() }
@@ -89,7 +83,6 @@ object CirclesAppConfig {
             isSubscriptionsEnabled = subscriptionEnabled
             isMediaBackupEnabled = mediaBackupEnabled
             isRageshakeEnabled = rageshakeEnabled
-            isSetupCirclesEnabled = setupCirclesEnabled
         }
     }
 
diff --git a/core/src/main/java/org/futo/circles/core/Constants.kt b/core/src/main/java/org/futo/circles/core/Constants.kt
index 39e98ad311819411e420ae7cb2d9ef279010df8a..c2f77bf1f789f91143e0a1892773c554346a51c0 100644
--- a/core/src/main/java/org/futo/circles/core/Constants.kt
+++ b/core/src/main/java/org/futo/circles/core/Constants.kt
@@ -3,9 +3,6 @@ package org.futo.circles.core
 import org.futo.circles.core.provider.MatrixSessionProvider
 
 const val FILE_PROVIDER_AUTHORITY_EXTENSION = ".provider"
-const val CREATE_ROOM_DELAY = 1000L
-const val SYSTEM_NOTICES_TAG = "m.server_notice"
-const val DEFAULT_USER_PREFIX = "@notices:"
 
 const val MediaCaptionFieldKey = "caption"
 
diff --git a/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt b/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt
index a3cf3985514c67a214f46851d247682838f4ce6a..6ff976ec2d83ddf57ba3ecedbdd75b7657c670ac 100644
--- a/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt
+++ b/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt
@@ -3,6 +3,7 @@ package org.futo.circles.core.extensions
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.LiveData
 import org.futo.circles.core.ErrorParser
+import org.futo.circles.core.fragment.HasLoadingState
 
 fun <T> LiveData<Response<T>>.observeResponse(
     fragment: Fragment,
@@ -13,7 +14,7 @@ fun <T> LiveData<Response<T>>.observeResponse(
     observe(fragment.viewLifecycleOwner) {
         it ?: return@observe
         onRequestInvoked?.invoke()
-            ?: run { (fragment as? org.futo.circles.core.fragment.HasLoadingState)?.stopLoading() }
+            ?: run { (fragment as? HasLoadingState)?.stopLoading() }
         when (it) {
             is Response.Success -> success(it.data)
             is Response.Error -> error?.invoke(it.message)
diff --git a/core/src/main/java/org/futo/circles/core/extensions/MatrixRoomExtensions.kt b/core/src/main/java/org/futo/circles/core/extensions/MatrixRoomExtensions.kt
deleted file mode 100644
index 32fe60b2b7539c43d9aa4f68a6858fde80b18aa5..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/extensions/MatrixRoomExtensions.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.futo.circles.core.extensions
-
-import org.futo.circles.core.model.TIMELINE_TYPE
-import org.futo.circles.core.provider.MatrixSessionProvider
-import org.matrix.android.sdk.api.session.getRoom
-import org.matrix.android.sdk.api.session.room.Room
-
-fun Room.getTimelineRoom(): Room? {
-    val session = MatrixSessionProvider.currentSession ?: return null
-    val childId = roomSummary()?.spaceChildren?.firstOrNull {
-        val room = session.getRoom(it.childRoomId)?.roomSummary()
-        room?.inviterId == null && room?.roomType == TIMELINE_TYPE
-    }?.childRoomId
-    return childId?.let { session.getRoom(it) }
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt b/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt
index 1ca9f7ce0d9b4a39cd895847801e65e3d93f2ce1..c1f407d144dcee506ce9641b340eda376cd51371 100644
--- a/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt
+++ b/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt
@@ -6,7 +6,6 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.flow.mapLatest
-import org.futo.circles.core.DEFAULT_USER_PREFIX
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.content.ContentUrlResolver
 import org.matrix.android.sdk.api.session.getUser
@@ -43,20 +42,10 @@ fun Session.resolveUrl(
 
 fun Session.getUserIdsToExclude() = mutableListOf(
     myUserId,
-    DEFAULT_USER_PREFIX + getServerDomain()
+    "@notices:" + getServerDomain()
 ).toSet()
 
 fun Session.getServerDomain() = myUserId.substringAfter(":")
 
-fun Session.getKnownUsersFlow() =
-    roomService().getRoomSummariesLive(roomSummaryQueryParams { excludeType = null }).asFlow()
-        .mapLatest { roomSummaries ->
-            val knowUsers = mutableSetOf<User>()
-            roomSummaries.forEach { summary ->
-                summary.otherMemberIds.forEach { knowUsers.add(getOrFetchUser(it)) }
-            }
-            knowUsers.toList().filterNot { getUserIdsToExclude().contains(it.userId) }
-        }
-
 suspend fun Session.getOrFetchUser(userId: String): User =
     getUser(userId) ?: userService().resolveUser(userId)
diff --git a/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt b/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt
index 8e2d33b6dc91fa00468b3c7258a003fb8a6e9822..1b89b8a5ba157080955663615420525b12092f41 100644
--- a/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt
+++ b/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt
@@ -6,96 +6,119 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
 import org.matrix.android.sdk.api.session.room.model.RoomType
 
 private const val orgPrefix = "org.futo"
-private const val CIRCLES_SPACE_TAG = "$orgPrefix.space.circles"
-const val SHARED_CIRCLES_SPACE_TAG = "$orgPrefix.space.circles.shared"
-private const val GROUPS_SPACE_TAG = "$orgPrefix.space.groups"
-const val PHOTOS_SPACE_TAG = "$orgPrefix.space.photos"
-const val ROOT_SPACE_TAG = "$orgPrefix.space.root"
-const val CIRCLE_TAG = "$orgPrefix.social.circle"
 
 const val GROUP_TYPE = "$orgPrefix.social.group"
 const val GALLERY_TYPE = "$orgPrefix.social.gallery"
 const val TIMELINE_TYPE = "$orgPrefix.social.timeline"
 
+const val ROOT_SPACE_ACCOUNT_DATA_KEY = "root"
+const val CIRCLES_SPACE_ACCOUNT_DATA_KEY = "circles"
+const val PROFILE_SPACE_ACCOUNT_DATA_KEY = "profile"
+const val PHOTOS_SPACE_ACCOUNT_DATA_KEY = "galleries"
+const val PEOPLE_SPACE_ACCOUNT_DATA_KEY = "people"
+const val GROUPS_SPACE_ACCOUNT_DATA_KEY = "groups"
+
 
 sealed class CirclesRoom(
     @StringRes open val nameId: Int?,
-    open val tag: String?,
-    open val parentTag: String?,
+    open val parentAccountDataKey: String?,
     open val type: String?,
-    open val joinRules: RoomJoinRules?
+    open val joinRules: RoomJoinRules?,
+    open val accountDataKey: String?
 ) {
     fun isSpace(): Boolean = type == RoomType.SPACE
+
+    open fun getTag(): String? = null
 }
 
 data class RootSpace(
     override val nameId: Int? = R.string.root_space_name,
-    override val tag: String? = ROOT_SPACE_TAG,
-    override val parentTag: String? = null,
+    override val parentAccountDataKey: String? = null,
     override val type: String? = RoomType.SPACE,
-    override val joinRules: RoomJoinRules? = null
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+    override val joinRules: RoomJoinRules? = null,
+    override val accountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) {
+    override fun getTag(): String = "$orgPrefix.space.root"
+}
 
 data class CirclesSpace(
     override val nameId: Int? = R.string.circles_space_name,
-    override val tag: String? = CIRCLES_SPACE_TAG,
-    override val parentTag: String? = ROOT_SPACE_TAG,
+    override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY,
     override val type: String? = RoomType.SPACE,
-    override val joinRules: RoomJoinRules? = null
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+    override val joinRules: RoomJoinRules? = null,
+    override val accountDataKey: String? = CIRCLES_SPACE_ACCOUNT_DATA_KEY
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) {
+    override fun getTag(): String = "$orgPrefix.space.circles"
+}
 
 data class SharedCirclesSpace(
     override val nameId: Int? = R.string.shared_circles,
-    override val tag: String? = SHARED_CIRCLES_SPACE_TAG,
-    override val parentTag: String? = CIRCLES_SPACE_TAG,
+    override val parentAccountDataKey: String? = CIRCLES_SPACE_ACCOUNT_DATA_KEY,
     override val type: String? = RoomType.SPACE,
-    override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+    override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK,
+    override val accountDataKey: String? = PROFILE_SPACE_ACCOUNT_DATA_KEY
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) {
+    override fun getTag(): String = "$orgPrefix.space.circles.shared"
+}
 
 data class PhotosSpace(
     override val nameId: Int? = R.string.photos_space_name,
-    override val tag: String? = PHOTOS_SPACE_TAG,
-    override val parentTag: String? = ROOT_SPACE_TAG,
+    override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY,
     override val type: String? = RoomType.SPACE,
-    override val joinRules: RoomJoinRules? = null
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+    override val joinRules: RoomJoinRules? = null,
+    override val accountDataKey: String? = PHOTOS_SPACE_ACCOUNT_DATA_KEY
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) {
+    override fun getTag(): String = "$orgPrefix.space.photos"
+}
+
+data class PeopleSpace(
+    override val nameId: Int? = R.string.peopel_space_name,
+    override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY,
+    override val type: String? = RoomType.SPACE,
+    override val joinRules: RoomJoinRules? = null,
+    override val accountDataKey: String? = PEOPLE_SPACE_ACCOUNT_DATA_KEY
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) {
+
+    override fun getTag(): String = "$orgPrefix.space.people"
+}
 
 data class GroupsSpace(
     override val nameId: Int? = R.string.groups_space_name,
-    override val tag: String? = GROUPS_SPACE_TAG,
-    override val parentTag: String? = ROOT_SPACE_TAG,
+    override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY,
     override val type: String? = RoomType.SPACE,
-    override val joinRules: RoomJoinRules? = null
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+    override val joinRules: RoomJoinRules? = null,
+    override val accountDataKey: String? = GROUPS_SPACE_ACCOUNT_DATA_KEY
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) {
+
+    override fun getTag(): String = "$orgPrefix.space.groups"
+}
 
 data class Circle(
     override val nameId: Int? = null,
-    override val tag: String? = CIRCLE_TAG,
-    override val parentTag: String? = CIRCLES_SPACE_TAG,
+    override val parentAccountDataKey: String? = CIRCLES_SPACE_ACCOUNT_DATA_KEY,
     override val type: String? = RoomType.SPACE,
     override val joinRules: RoomJoinRules? = null
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null) {
+    override fun getTag(): String = "$orgPrefix.social.circle"
+}
 
 data class Group(
     override val nameId: Int? = null,
-    override val tag: String? = null,
-    override val parentTag: String? = GROUPS_SPACE_TAG,
+    override val parentAccountDataKey: String? = GROUPS_SPACE_ACCOUNT_DATA_KEY,
     override val type: String? = GROUP_TYPE,
     override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null)
 
 data class Gallery(
     override val nameId: Int? = null,
-    override val tag: String? = null,
-    override val parentTag: String? = PHOTOS_SPACE_TAG,
+    override val parentAccountDataKey: String? = PHOTOS_SPACE_ACCOUNT_DATA_KEY,
     override val type: String? = GALLERY_TYPE,
     override val joinRules: RoomJoinRules? = RoomJoinRules.INVITE
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null)
 
 data class Timeline(
     override val nameId: Int? = null,
-    override val tag: String? = null,
-    override val parentTag: String? = null,
+    override val parentAccountDataKey: String? = null,
     override val type: String? = TIMELINE_TYPE,
     override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK
-) : CirclesRoom(nameId, tag, parentTag, type, joinRules)
\ No newline at end of file
+) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null)
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/model/LoadingData.kt b/core/src/main/java/org/futo/circles/core/model/LoadingData.kt
index d49f5e49bd6b5f97c29ea74f7197af56f67c85e2..746fa0bcd3218d2d600aa436f907130fd157a38a 100644
--- a/core/src/main/java/org/futo/circles/core/model/LoadingData.kt
+++ b/core/src/main/java/org/futo/circles/core/model/LoadingData.kt
@@ -6,6 +6,6 @@ import org.futo.circles.core.R
 data class LoadingData(
     @StringRes var messageId: Int = R.string.loading,
     var progress: Int = 0,
-    var total: Int = 100,
+    var total: Int = 0,
     var isLoading: Boolean = true
 )
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/model/SystemNoticeListItem.kt b/core/src/main/java/org/futo/circles/core/model/SystemNoticeListItem.kt
deleted file mode 100644
index 934e1108720683510b8b8eb99749c8e05bd5e25c..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/model/SystemNoticeListItem.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.futo.circles.core.model
-
-import org.futo.circles.core.list.IdEntity
-
-data class SystemNoticeListItem(
-    override val id: String,
-    val message: String,
-    val time: Long
-) : IdEntity<String>
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/model/TaskStatus.kt b/core/src/main/java/org/futo/circles/core/model/TaskStatus.kt
new file mode 100644
index 0000000000000000000000000000000000000000..368708d192b499075fa3ef4c38562e582cc552ef
--- /dev/null
+++ b/core/src/main/java/org/futo/circles/core/model/TaskStatus.kt
@@ -0,0 +1,8 @@
+package org.futo.circles.core.model
+
+enum class TaskStatus {
+    IDLE,
+    RUNNING,
+    SUCCESS,
+    FAILED
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesCountSharedViewModel.kt b/core/src/main/java/org/futo/circles/core/notices/SystemNoticesCountSharedViewModel.kt
deleted file mode 100644
index 62a4db05cc3e42ce6ed80264d30760a46a1cee2a..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesCountSharedViewModel.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.futo.circles.core.notices
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.map
-import dagger.hilt.android.lifecycle.HiltViewModel
-import org.futo.circles.core.DEFAULT_USER_PREFIX
-import org.futo.circles.core.SYSTEM_NOTICES_TAG
-import org.futo.circles.core.extensions.launchBg
-import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.utils.UserUtils
-import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.session.room.model.Membership
-import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
-import javax.inject.Inject
-
-@HiltViewModel
-class SystemNoticesCountSharedViewModel @Inject constructor() : ViewModel() {
-
-    val systemNoticesCountLiveData = MatrixSessionProvider.currentSession?.roomService()
-        ?.getRoomSummariesLive(roomSummaryQueryParams())
-        ?.map { list -> list.firstOrNull { it.hasTag(SYSTEM_NOTICES_TAG) }?.notificationCount }
-
-    init {
-        autoAcceptNoticeRoomInvite()
-    }
-
-    private fun autoAcceptNoticeRoomInvite() {
-        val session = MatrixSessionProvider.currentSession ?: return
-        session.roomService().getRoomSummaries(roomSummaryQueryParams {
-            memberships = listOf(Membership.INVITE)
-        }).firstOrNull { it.inviterId == getNoticesUserId(session) }?.let {
-            launchBg { session.roomService().joinRoom(it.roomId) }
-        }
-    }
-
-    private fun getNoticesUserId(session: Session): String {
-        val domain = UserUtils.getServerDomain(session.myUserId)
-        return DEFAULT_USER_PREFIX + domain
-    }
-
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesDialogFragment.kt b/core/src/main/java/org/futo/circles/core/notices/SystemNoticesDialogFragment.kt
deleted file mode 100644
index 7f22b92c66e91c186b60c3103ef98c17bea058c7..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesDialogFragment.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.futo.circles.core.notices
-
-import android.os.Bundle
-import android.view.View
-import androidx.fragment.app.viewModels
-import dagger.hilt.android.AndroidEntryPoint
-import org.futo.circles.core.databinding.DialogFragmentSystemNoticesBinding
-import org.futo.circles.core.extensions.observeData
-import org.futo.circles.core.fragment.BaseFullscreenDialogFragment
-import org.futo.circles.core.notices.list.SystemNoticesTimelineAdapter
-
-@AndroidEntryPoint
-class SystemNoticesDialogFragment :
-    BaseFullscreenDialogFragment(DialogFragmentSystemNoticesBinding::inflate) {
-
-    private val viewModel by viewModels<SystemNoticesTimelineViewModel>()
-
-    private val binding by lazy {
-        getBinding() as DialogFragmentSystemNoticesBinding
-    }
-
-    private val listAdapter by lazy {
-        SystemNoticesTimelineAdapter { viewModel.loadMore() }
-    }
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        super.onViewCreated(view, savedInstanceState)
-        setupViews()
-        setupObservers()
-    }
-
-    private fun setupViews() {
-        binding.rvTimeline.adapter = listAdapter
-    }
-
-    private fun setupObservers() {
-        viewModel.systemNoticesTimelineEventsLiveData.observeData(this) {
-            listAdapter.submitList(it)
-        }
-    }
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesTimelineViewModel.kt b/core/src/main/java/org/futo/circles/core/notices/SystemNoticesTimelineViewModel.kt
deleted file mode 100644
index feba6b2bade39ec350bbf8c2b5a3dadfa5b39e38..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesTimelineViewModel.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.futo.circles.core.notices
-
-import androidx.lifecycle.map
-import dagger.hilt.android.lifecycle.HiltViewModel
-import org.futo.circles.core.model.PostContentType
-import org.futo.circles.core.model.SystemNoticeListItem
-import org.futo.circles.core.model.TextContent
-import org.futo.circles.core.timeline.BaseTimelineViewModel
-import org.futo.circles.core.timeline.data_source.SingleTimelineDataSource
-import javax.inject.Inject
-
-@HiltViewModel
-class SystemNoticesTimelineViewModel @Inject constructor(
-    timelineDataSource: SingleTimelineDataSource
-) : BaseTimelineViewModel(timelineDataSource) {
-
-    val systemNoticesTimelineEventsLiveData =
-        timelineDataSource.timelineEventsLiveData.map { list ->
-            list.mapNotNull {
-                if (it.content.type == PostContentType.TEXT_CONTENT)
-                    SystemNoticeListItem(
-                        it.id,
-                        (it.content as? TextContent)?.message ?: "",
-                        it.postInfo.timestamp
-                    )
-                else null
-            }
-        }
-
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesTimelineAdapter.kt b/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesTimelineAdapter.kt
deleted file mode 100644
index 3dee08158d45ecba70324aa96c3109bfea83fac0..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesTimelineAdapter.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.futo.circles.core.notices.list
-
-
-import android.view.ViewGroup
-import org.futo.circles.core.list.BaseRvAdapter
-import org.futo.circles.core.model.SystemNoticeListItem
-
-class SystemNoticesTimelineAdapter(
-    private val onLoadMore: () -> Unit
-) : BaseRvAdapter<SystemNoticeListItem, SystemNoticesViewHolder>(DefaultIdEntityCallback()) {
-
-
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SystemNoticesViewHolder {
-        return SystemNoticesViewHolder(parent)
-    }
-
-    override fun onBindViewHolder(holder: SystemNoticesViewHolder, position: Int) {
-        holder.bind(getItem(position))
-        if (position >= itemCount - LOAD_MORE_THRESHOLD) onLoadMore()
-    }
-
-
-    companion object {
-        private const val LOAD_MORE_THRESHOLD = 10
-    }
-
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesViewHolder.kt b/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesViewHolder.kt
deleted file mode 100644
index fba7f8b77666e085b8b4a83a847e288d4edccd1b..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesViewHolder.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.futo.circles.core.notices.list
-
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import org.futo.circles.core.databinding.ListItemSystemNoticesBinding
-import org.futo.circles.core.list.ViewBindingHolder
-import org.futo.circles.core.model.SystemNoticeListItem
-import java.text.DateFormat
-import java.util.Date
-
-class SystemNoticesViewHolder(
-    parent: ViewGroup
-) : RecyclerView.ViewHolder(inflate(parent, ListItemSystemNoticesBinding::inflate)) {
-
-    private companion object : ViewBindingHolder
-
-    private val binding = baseBinding as ListItemSystemNoticesBinding
-
-    fun bind(data: SystemNoticeListItem) {
-        with(binding) {
-            tvMessage.text = data.message
-            tvTime.text = DateFormat.getDateTimeInstance().format(Date(data.time))
-        }
-    }
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/room/CoreSpacesTreeBuilder.kt b/core/src/main/java/org/futo/circles/core/room/CoreSpacesTreeBuilder.kt
deleted file mode 100644
index 6e81911abed55396681c82ac6eda75d63e4ffce0..0000000000000000000000000000000000000000
--- a/core/src/main/java/org/futo/circles/core/room/CoreSpacesTreeBuilder.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.futo.circles.core.room
-
-import android.content.Context
-import androidx.lifecycle.MutableLiveData
-import dagger.hilt.android.qualifiers.ApplicationContext
-import kotlinx.coroutines.delay
-import org.futo.circles.core.CREATE_ROOM_DELAY
-import org.futo.circles.core.R
-import org.futo.circles.core.model.CirclesSpace
-import org.futo.circles.core.model.Gallery
-import org.futo.circles.core.model.GroupsSpace
-import org.futo.circles.core.model.LoadingData
-import org.futo.circles.core.model.PhotosSpace
-import org.futo.circles.core.model.ROOT_SPACE_TAG
-import org.futo.circles.core.model.RootSpace
-import org.futo.circles.core.model.SharedCirclesSpace
-import org.futo.circles.core.provider.MatrixSessionProvider
-import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
-import javax.inject.Inject
-
-class CoreSpacesTreeBuilder @Inject constructor(
-    @ApplicationContext private val context: Context,
-    private val createRoomDataSource: CreateRoomDataSource
-) {
-
-    val loadingLiveData = MutableLiveData<LoadingData>()
-
-    private val coreSpaces = listOf(
-        RootSpace(), CirclesSpace(), GroupsSpace(), PhotosSpace()
-    )
-
-    suspend fun createCoreSpacesTree() {
-        loadingLiveData.postValue(
-            LoadingData(
-                total = 0,
-                messageId = R.string.configuring_workspace,
-                isLoading = true
-            )
-        )
-        coreSpaces.forEach {
-            createRoomDataSource.createRoom(it)
-            delay(CREATE_ROOM_DELAY)
-        }
-        createRoomDataSource.createRoom(SharedCirclesSpace())
-        delay(CREATE_ROOM_DELAY)
-        createRoomDataSource.createRoom(Gallery(), context.getString(R.string.photos))
-        loadingLiveData.postValue(LoadingData(isLoading = false))
-    }
-
-    fun isCirclesHierarchyCreated(): Boolean = MatrixSessionProvider.currentSession?.roomService()
-        ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null })
-        ?.firstOrNull { summary -> summary.hasTag(ROOT_SPACE_TAG) } != null
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt b/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt
index 3a493229e1d813948affc80265937dd8388444af..59d0d28adf9c0350517e01f3066d0ff1742331b1 100644
--- a/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt
@@ -7,7 +7,8 @@ import org.futo.circles.core.model.Circle
 import org.futo.circles.core.model.CirclesRoom
 import org.futo.circles.core.model.Timeline
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.utils.getSharedCirclesSpaceId
+import org.futo.circles.core.workspace.SharedCircleDataSource
+import org.futo.circles.core.workspace.SpacesTreeAccountDataSource
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toContent
 import org.matrix.android.sdk.api.session.getRoom
@@ -25,21 +26,33 @@ import javax.inject.Inject
 
 class CreateRoomDataSource @Inject constructor(
     @ApplicationContext private val context: Context,
-    private val roomRelationsBuilder: RoomRelationsBuilder
+    private val roomRelationsBuilder: RoomRelationsBuilder,
+    private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource,
+    private val sharedCircleDataSource: SharedCircleDataSource
 ) {
 
-    private val session by lazy { MatrixSessionProvider.currentSession }
+    private val session by lazy { MatrixSessionProvider.getSessionOrThrow() }
 
-    suspend fun createCircleWithTimeline(
+    suspend fun createRoom(
+        circlesRoom: CirclesRoom,
         name: String? = null,
+        topic: String? = null,
         iconUri: Uri? = null,
         inviteIds: List<String>? = null,
-        isPublicCircle: Boolean
+        isPublicCircle: Boolean = false
     ): String {
-        val circleId = createRoom(Circle(), name, null, iconUri)
-        val timelineId = createCircleTimeline(circleId, name, iconUri, inviteIds)
-        if (isPublicCircle) addToSharedCircles(timelineId)
-        return circleId
+        val id = session.roomService().createRoom(
+            getParams(circlesRoom, name, topic, iconUri, inviteIds)
+        )
+        circlesRoom.parentAccountDataKey?.let { key ->
+            val parentId = spacesTreeAccountDataSource.getRoomIdByKey(key)
+            parentId?.let { roomRelationsBuilder.setRelations(id, it) }
+        }
+        if (circlesRoom is Circle) {
+            val timelineId = createCircleTimeline(id, name, iconUri, inviteIds)
+            if (isPublicCircle) sharedCircleDataSource.addToSharedCircles(timelineId)
+        }
+        return id
     }
 
     suspend fun createCircleTimeline(
@@ -48,29 +61,10 @@ class CreateRoomDataSource @Inject constructor(
         inviteIds: List<String>? = null
     ): String {
         val timelineId = createRoom(Timeline(), name, null, iconUri, inviteIds)
-        session?.getRoom(circleId)
-            ?.let { circle -> roomRelationsBuilder.setRelations(timelineId, circle) }
+        roomRelationsBuilder.setRelations(timelineId, circleId)
         return timelineId
     }
 
-    suspend fun createRoom(
-        circlesRoom: CirclesRoom,
-        name: String? = null,
-        topic: String? = null,
-        iconUri: Uri? = null,
-        inviteIds: List<String>? = null
-    ): String {
-        val id = session?.roomService()?.createRoom(
-            getParams(circlesRoom, name, topic, iconUri, inviteIds)
-        ) ?: throw Exception("Can not create room")
-        circlesRoom.tag?.let { session?.getRoom(id)?.tagsService()?.addTag(it, null) }
-        circlesRoom.parentTag?.let { tag ->
-            roomRelationsBuilder.findRoomByTag(tag)
-                ?.let { room -> roomRelationsBuilder.setRelations(id, room) }
-        }
-        return id
-    }
-
     private fun getParams(
         circlesRoom: CirclesRoom,
         name: String? = null,
@@ -112,18 +106,4 @@ class CreateRoomDataSource @Inject constructor(
             )
         )
     }
-
-    suspend fun addToSharedCircles(timelineId: String) {
-        session?.getRoom(getSharedCirclesSpaceId() ?: "")
-            ?.let { sharedCirclesSpace ->
-                roomRelationsBuilder.setRelations(timelineId, sharedCirclesSpace)
-            }
-    }
-
-    suspend fun removeFromSharedCircles(timelineId: String) {
-        session?.getRoom(getSharedCirclesSpaceId() ?: "")
-            ?.let { sharedCirclesSpace ->
-                roomRelationsBuilder.removeRelations(timelineId, sharedCirclesSpace.roomId)
-            }
-    }
 }
diff --git a/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt b/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt
index 67d31d3c28b8c1cfe348de50c84abda439df7349..4866369a1065b684ea4457836623a6c79475bf4e 100644
--- a/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt
+++ b/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt
@@ -2,24 +2,25 @@ package org.futo.circles.core.room
 
 import org.futo.circles.core.extensions.getRoomOwners
 import org.futo.circles.core.model.CirclesRoom
-import org.futo.circles.core.model.Gallery
-import org.futo.circles.core.model.Group
 import org.futo.circles.core.provider.MatrixSessionProvider
+import org.futo.circles.core.utils.getJoinedRoomById
+import org.futo.circles.core.workspace.SpacesTreeAccountDataSource
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.getRoom
-import org.matrix.android.sdk.api.session.room.Room
-import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import javax.inject.Inject
 
-class RoomRelationsBuilder @Inject constructor() {
+class RoomRelationsBuilder @Inject constructor(
+    private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource
+) {
 
     private val session by lazy { MatrixSessionProvider.currentSession }
 
-    suspend fun setRelations(childId: String, parentRoom: Room, isRoomCreatedByMe: Boolean = true) {
+    suspend fun setRelations(childId: String, parentRoomId: String) {
         val via = listOf(getHomeServerDomain())
-        if (isRoomCreatedByMe) {
-            session?.spaceService()?.setSpaceParent(childId, parentRoom.roomId, true, via)
+        tryOrNull {
+            session?.spaceService()?.setSpaceParent(childId, parentRoomId, false, via)
         }
-        parentRoom.asSpace()?.addChildren(childId, via, null)
+        getJoinedRoomById(parentRoomId)?.asSpace()?.addChildren(childId, via, null)
     }
 
     suspend fun removeRelations(childId: String, parentId: String) {
@@ -35,32 +36,14 @@ class RoomRelationsBuilder @Inject constructor() {
         }
     }
 
-    suspend fun setInvitedGroupRelations(roomId: String) =
-        setInvitedRoomRelations(roomId, Group())
-
-    suspend fun setInvitedGalleryRelations(roomId: String) =
-        setInvitedRoomRelations(roomId, Gallery())
-
-    private suspend fun setInvitedRoomRelations(roomId: String, circlesRoom: CirclesRoom) {
-        circlesRoom.tag?.let { session?.getRoom(roomId)?.tagsService()?.addTag(it, null) }
-        circlesRoom.parentTag?.let { tag ->
-            findRoomByTag(tag)
-                ?.let { room -> setRelations(roomId, room, false) }
-        }
-    }
-
-    suspend fun setInvitedCircleRelations(roomId: String, parentCircleId: String) {
-        session?.getRoom(parentCircleId)?.let { parentCircle ->
-            setRelations(roomId, parentCircle, false)
-        }
+    suspend fun setInvitedRoomRelations(roomId: String, circlesRoom: CirclesRoom) {
+        val key = circlesRoom.parentAccountDataKey ?: return
+        val parentId = spacesTreeAccountDataSource.getRoomIdByKey(key) ?: return
+        setRelations(roomId, parentId)
     }
 
-    fun findRoomByTag(tag: String): Room? {
-        val roomWithTagId =
-            session?.roomService()?.getRoomSummaries(roomSummaryQueryParams { excludeType = null })
-                ?.firstOrNull { summary -> summary.tags.firstOrNull { it.name == tag } != null }
-                ?.roomId
-        return roomWithTagId?.let { session?.getRoom(it) }
+    suspend fun setInvitedRoomRelations(roomId: String, parentCircleId: String) {
+        setRelations(roomId, parentCircleId)
     }
 
     private fun getHomeServerDomain() = session?.sessionParams?.homeServerHost ?: ""
diff --git a/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt b/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt
index 3f09ea9b8c188b302467b05975997d7a944c5883..d0c2b6d830ccc34fca7d87b5ebb83d8fc30de543 100644
--- a/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt
@@ -5,13 +5,11 @@ import androidx.lifecycle.map
 import dagger.hilt.android.scopes.ViewModelScoped
 import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.extensions.getOrThrow
-import org.futo.circles.core.model.CIRCLE_TAG
 import org.futo.circles.core.model.toFollowingListItem
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.room.RoomRelationsBuilder
+import org.futo.circles.core.utils.getJoinedRoomById
 import org.matrix.android.sdk.api.session.getRoom
-import org.matrix.android.sdk.api.session.room.model.Membership
-import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import javax.inject.Inject
 
 @ViewModelScoped
@@ -42,16 +40,7 @@ class FollowingDataSource @Inject constructor(
         session.roomService().leaveRoom(childRoomId)
     }
 
-    private fun getFollowingInCircleCount(roomId: String): Int {
-        var followingCount = 0
-        session.roomService().getRoomSummaries(roomSummaryQueryParams { excludeType = null })
-            .filter { summary ->
-                summary.hasTag(CIRCLE_TAG) && summary.membership == Membership.JOIN
-            }.forEach { circle ->
-                circle.spaceChildren?.firstOrNull { it.childRoomId == roomId }?.let {
-                    followingCount++
-                }
-            }
-        return followingCount
-    }
+    private fun getFollowingInCircleCount(roomId: String): Int =
+        getJoinedRoomById(roomId)?.roomSummary()?.spaceParents?.size ?: 0
+
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt b/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt
index e0bba3d1d330b29704728987c25b9d1711e31f29..27e8457a5650128bc48d3c9affd64f722a950356 100644
--- a/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt
+++ b/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt
@@ -8,6 +8,7 @@ import org.futo.circles.core.SingleEventLiveData
 import org.futo.circles.core.extensions.Response
 import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.extensions.launchBg
+import org.futo.circles.core.model.Circle
 import org.futo.circles.core.model.CircleRoomTypeArg
 import org.futo.circles.core.model.Gallery
 import org.futo.circles.core.model.Group
@@ -58,13 +59,13 @@ class CreateRoomViewModel @Inject constructor(
         name: String,
         inviteIds: List<String>?,
         isPublicCircle: Boolean
-    ) =
-        dataSource.createCircleWithTimeline(
-            name = name,
-            iconUri = selectedImageLiveData.value,
-            inviteIds = inviteIds,
-            isPublicCircle
-        )
+    ) = dataSource.createRoom(
+        circlesRoom = Circle(),
+        name = name,
+        iconUri = selectedImageLiveData.value,
+        inviteIds = inviteIds,
+        isPublicCircle = isPublicCircle
+    )
 
     private suspend fun createGallery(name: String) = dataSource.createRoom(
         circlesRoom = Gallery(),
diff --git a/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt b/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt
index decf97715279a737f3b9d1386afdaada34a85b3b..9baceb0d23e7e689f4fe13e537d48051fe372134 100644
--- a/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt
@@ -6,6 +6,8 @@ import kotlinx.coroutines.async
 import kotlinx.coroutines.awaitAll
 import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.model.CircleRoomTypeArg
+import org.futo.circles.core.model.Gallery
+import org.futo.circles.core.model.Group
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.room.RoomRelationsBuilder
 import org.matrix.android.sdk.api.session.getRoom
@@ -27,11 +29,10 @@ class InviteRequestsDataSource @Inject constructor(
     suspend fun acceptInvite(roomId: String, roomType: CircleRoomTypeArg) = createResult {
         MatrixSessionProvider.currentSession?.roomService()?.joinRoom(roomId)
         when (roomType) {
-            CircleRoomTypeArg.Group -> roomRelationsBuilder.setInvitedGroupRelations(roomId)
-            CircleRoomTypeArg.Photo -> roomRelationsBuilder.setInvitedGroupRelations(roomId)
+            CircleRoomTypeArg.Group -> roomRelationsBuilder.setInvitedRoomRelations(roomId, Group())
+            CircleRoomTypeArg.Photo -> roomRelationsBuilder.setInvitedRoomRelations(roomId, Gallery())
             CircleRoomTypeArg.Circle -> throw IllegalArgumentException("Circle has different relations")
         }
-
     }
 
     suspend fun rejectInvite(roomId: String) = createResult {
diff --git a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt
index 898a25fa6e0d749523504c0860a0487ca8e71208..1df0a20589f0705fbe99e52e530c0f461acc99b1 100644
--- a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt
@@ -9,9 +9,8 @@ import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.extensions.getFilename
 import org.futo.circles.core.extensions.getOrThrow
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.room.CreateRoomDataSource
 import org.futo.circles.core.utils.getTimelineRoomFor
-import org.futo.circles.core.utils.isCircleShared
+import org.futo.circles.core.workspace.SharedCircleDataSource
 import org.matrix.android.sdk.api.session.getRoom
 import java.util.UUID
 import javax.inject.Inject
@@ -20,7 +19,7 @@ import javax.inject.Inject
 class UpdateRoomDataSource @Inject constructor(
     savedStateHandle: SavedStateHandle,
     @ApplicationContext private val context: Context,
-    private val createRoomDataSource: CreateRoomDataSource
+    private val sharedCircleDataSource: SharedCircleDataSource
 ) {
 
     private val roomId: String = savedStateHandle.getOrThrow("roomId")
@@ -42,8 +41,8 @@ class UpdateRoomDataSource @Inject constructor(
 
     private suspend fun handelPrivateSharedVisibilityUpdate(isPublic: Boolean) {
         val timelineId = room?.roomId?.let { getTimelineRoomFor(it)?.roomId } ?: return
-        if (isPublic) createRoomDataSource.addToSharedCircles(timelineId)
-        else createRoomDataSource.removeFromSharedCircles(timelineId)
+        if (isPublic) sharedCircleDataSource.addToSharedCircles(timelineId)
+        else sharedCircleDataSource.removeFromSharedCircles(timelineId)
     }
 
     fun isNameChanged(newName: String) = room?.roomSummary()?.displayName != newName
@@ -51,7 +50,9 @@ class UpdateRoomDataSource @Inject constructor(
     fun isTopicChanged(newTopic: String) = room?.roomSummary()?.topic != newTopic
 
     fun isPrivateSharedChanged(isPublic: Boolean) = room?.roomId?.let {
-        isCircleShared(it) != isPublic
+        sharedCircleDataSource.isCircleShared(it) != isPublic
     } ?: false
 
+    fun isCircleShared(circleId: String) = sharedCircleDataSource.isCircleShared(circleId)
+
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt
index bb30e7cd7b4ef88ad5bf7408e326bab1c504c367..3bbaeb8d621640c999fe35cd77aae8384bbbda7d 100644
--- a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt
+++ b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt
@@ -21,12 +21,12 @@ abstract class UpdateRoomDialogFragment(inflate: (LayoutInflater, ViewGroup?, Bo
 
     abstract val roomId: String
 
-    private val viewModel by viewModels<UpdateRoomViewModel>()
+    protected val viewModel by viewModels<UpdateRoomViewModel>()
 
     abstract val mediaPickerHelper: MediaPickerHelper
     abstract val successMessageResId: Int
     abstract fun onCoverImageSelected(uri: Uri)
-    abstract fun setInitialGroupData(room: RoomSummary)
+    abstract fun setInitialRoomData(room: RoomSummary)
     abstract fun setUpdateButtonEnabled(isEnabled: Boolean)
 
     protected fun changeCoverImage() {
@@ -67,7 +67,7 @@ abstract class UpdateRoomDialogFragment(inflate: (LayoutInflater, ViewGroup?, Bo
             }
         )
         viewModel.groupSummaryLiveData.observeData(this) {
-            it?.let { setInitialGroupData(it) }
+            it?.let { setInitialRoomData(it) }
         }
         viewModel.isRoomDataChangedLiveData.observeData(this) {
             setUpdateButtonEnabled(it)
diff --git a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt
index bf320d7de71d57ad20ca2803ecb41ff2205f8057..2ff350d77a8645bb21cd7d0ec83d9d1b5848e0f3 100644
--- a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt
+++ b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt
@@ -39,4 +39,5 @@ class UpdateRoomViewModel @Inject constructor(
         isRoomDataChangedLiveData.postValue(isDataUpdated)
     }
 
+    fun isCircleShared(circleId: String) = dataSource.isCircleShared(circleId)
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt
index f08ba933573ac9e0bd0486af4970d91248ab3483..8f6756fd1c048ea3e857eee8f303bb849dfe2dba 100644
--- a/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt
+++ b/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt
@@ -13,7 +13,6 @@ import org.futo.circles.core.extensions.getText
 import org.futo.circles.core.extensions.loadProfileIcon
 import org.futo.circles.core.picker.helper.MediaPickerHelper
 import org.futo.circles.core.room.update.UpdateRoomDialogFragment
-import org.futo.circles.core.utils.isCircleShared
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 
 @AndroidEntryPoint
@@ -40,10 +39,10 @@ class UpdateCircleDialogFragment :
         onInputDataChanged()
     }
 
-    override fun setInitialGroupData(room: RoomSummary) {
+    override fun setInitialRoomData(room: RoomSummary) {
         binding.ivCover.loadProfileIcon(room.avatarUrl, room.displayName)
         binding.tilName.editText?.setText(room.displayName)
-        val isCircleShared = isCircleShared(roomId)
+        val isCircleShared = viewModel.isCircleShared(roomId)
         binding.btnPrivate.isChecked = !isCircleShared
         binding.btnPublic.isChecked = isCircleShared
     }
diff --git a/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt
index 74f58ceabcdc6588fdee323969ea8ae2248978f0..c90e191be48dbab0949b822f68926c7f284923e2 100644
--- a/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt
+++ b/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt
@@ -40,7 +40,7 @@ class UpdateGalleryDialogFragment :
         onInputDataChanged()
     }
 
-    override fun setInitialGroupData(room: RoomSummary) {
+    override fun setInitialRoomData(room: RoomSummary) {
         binding.ivCover.loadProfileIcon(room.avatarUrl, room.displayName)
         binding.tilName.editText?.setText(room.displayName)
     }
diff --git a/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt
index f4d8a04cf4f33f6adde14c180796951bcf1df244..380cb01d0c4275d6f3bf0be120ec11c6ef2730b3 100644
--- a/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt
+++ b/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt
@@ -39,7 +39,7 @@ class UpdateGroupDialogFragment :
         onInputDataChanged()
     }
 
-    override fun setInitialGroupData(room: RoomSummary) {
+    override fun setInitialRoomData(room: RoomSummary) {
         binding.ivCover.loadProfileIcon(room.avatarUrl, room.displayName)
         binding.tilName.editText?.setText(room.displayName)
         binding.tilTopic.editText?.setText(room.topic)
diff --git a/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt b/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt
index 07c77fb7ab2c1192260f1a2865465285a026ed89..ccb777f32fef15e38a62ba3d1ee9c90416d50491 100644
--- a/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt
@@ -1,15 +1,19 @@
 package org.futo.circles.core.select_users
 
+import androidx.lifecycle.asFlow
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
 import org.futo.circles.core.extensions.Response
 import org.futo.circles.core.extensions.createResult
-import org.futo.circles.core.extensions.getKnownUsersFlow
+import org.futo.circles.core.extensions.getOrFetchUser
 import org.futo.circles.core.extensions.getServerDomain
+import org.futo.circles.core.extensions.getUserIdsToExclude
 import org.futo.circles.core.provider.MatrixSessionProvider
+import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import org.matrix.android.sdk.api.session.user.model.User
@@ -36,6 +40,16 @@ class SearchUserDataSource @Inject constructor() {
                 }
             } ?: flowOf()
 
+    private fun Session.getKnownUsersFlow() =
+        roomService().getRoomSummariesLive(roomSummaryQueryParams { excludeType = null }).asFlow()
+            .mapLatest { roomSummaries ->
+                val knowUsers = mutableSetOf<User>()
+                roomSummaries.forEach { summary ->
+                    summary.otherMemberIds.forEach { knowUsers.add(getOrFetchUser(it)) }
+                }
+                knowUsers.toList().filterNot { getUserIdsToExclude().contains(it.userId) }
+            }
+
     suspend fun searchSuggestions(
         query: String,
         userIdsToExclude: Set<String> = emptySet()
diff --git a/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt b/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt
index 7b604713af9e614c177a4945dfe0a13f9f535beb..0b2eea4690fc54f5202d1bd280fd17ca29cfa68f 100644
--- a/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt
@@ -1,12 +1,15 @@
 package org.futo.circles.core.select_users
 
 import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.asFlow
 import dagger.hilt.android.scopes.ViewModelScoped
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.mapLatest
+import org.futo.circles.core.extensions.getOrFetchUser
 import org.futo.circles.core.extensions.getUserIdsToExclude
 import org.futo.circles.core.mapping.toUserListItem
 import org.futo.circles.core.model.CirclesUserSummary
@@ -17,9 +20,11 @@ import org.futo.circles.core.model.UserListItem
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.utils.UserUtils
 import org.matrix.android.sdk.api.MatrixPatterns
+import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
 import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import org.matrix.android.sdk.api.session.user.model.User
 import javax.inject.Inject
 
diff --git a/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt b/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt
index 6d61643c419f295c3dd52be6a775042cbcef0afd..ca975587a66db13ae8dd52a567b3824c656df24c 100644
--- a/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt
+++ b/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt
@@ -1,17 +1,19 @@
 package org.futo.circles.core.utils
 
-import org.futo.circles.core.SYSTEM_NOTICES_TAG
-import org.futo.circles.core.extensions.getRoomOwners
-import org.futo.circles.core.extensions.getTimelineRoom
-import org.futo.circles.core.model.PHOTOS_SPACE_TAG
-import org.futo.circles.core.model.SHARED_CIRCLES_SPACE_TAG
+import org.futo.circles.core.model.TIMELINE_TYPE
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.matrix.android.sdk.api.session.getRoom
-import org.matrix.android.sdk.api.session.getRoomSummary
 import org.matrix.android.sdk.api.session.room.Room
 import org.matrix.android.sdk.api.session.room.model.Membership
-import org.matrix.android.sdk.api.session.room.model.RoomType
-import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
+
+fun Room.getTimelineRoom(): Room? {
+    val session = MatrixSessionProvider.currentSession ?: return null
+    val childId = roomSummary()?.spaceChildren?.firstOrNull {
+        val room = session.getRoom(it.childRoomId)?.roomSummary()
+        room?.inviterId == null && room?.roomType == TIMELINE_TYPE
+    }?.childRoomId
+    return childId?.let { session.getRoom(it) }
+}
 
 fun getTimelineRoomFor(circleId: String): Room? {
     val session = MatrixSessionProvider.currentSession ?: return null
@@ -21,33 +23,9 @@ fun getTimelineRoomFor(circleId: String): Room? {
 fun getTimelineRoomIdOrThrow(circleId: String) = getTimelineRoomFor(circleId)?.roomId
     ?: throw IllegalArgumentException("Timeline not found")
 
-fun getSystemNoticesRoomId(): String? = getJoinedRoomIdByTag(SYSTEM_NOTICES_TAG)
-
-fun getJoinedRoomIdByTag(tag: String): String? {
-    val session = MatrixSessionProvider.currentSession ?: return null
-    return session.roomService().getRoomSummaries(roomSummaryQueryParams())
-        .firstOrNull { it.membership == Membership.JOIN && it.hasTag(tag) }?.roomId
-}
-
-fun getPhotosSpaceId(): String? = getSpaceIdByTag(PHOTOS_SPACE_TAG)
-fun getSharedCirclesSpaceId(): String? = getSpaceIdByTag(SHARED_CIRCLES_SPACE_TAG)
-
-fun getSharedCircleFor(userId: String) = MatrixSessionProvider.currentSession?.roomService()
-    ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null })?.firstOrNull { summary ->
-        summary.roomType == RoomType.SPACE && summary.membership == Membership.JOIN &&
-                getRoomOwners(summary.roomId).map { it.userId }.contains(userId)
-    }
 
-fun getSpaceIdByTag(tag: String): String? {
+fun getJoinedRoomById(roomId: String): Room? {
     val session = MatrixSessionProvider.currentSession ?: return null
-    return session.roomService().getRoomSummaries(roomSummaryQueryParams { excludeType = null })
-        .firstOrNull { it.hasTag(tag) && it.roomType == RoomType.SPACE }?.roomId
-}
-
-fun isCircleShared(circleId: String): Boolean {
-    val timelineId = getTimelineRoomFor(circleId)?.roomId
-    val sharedCirclesTimelinesIds = getSharedCirclesSpaceId()?.let {
-        MatrixSessionProvider.currentSession?.getRoomSummary(it)?.spaceChildren?.map { it.childRoomId }
-    } ?: emptyList()
-    return sharedCirclesTimelinesIds.contains(timelineId)
+    return session.roomService().getRoom(roomId)
+        ?.takeIf { it.roomSummary()?.membership == Membership.JOIN }
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt b/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt
index e8a24bfe12ab9885d59258990fd82e9543d416ee..e4e5b6d81eaf85544f5a35a0124290829c25f691 100644
--- a/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt
+++ b/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt
@@ -25,7 +25,6 @@ class LoadingDialog(context: Context) : AppCompatDialog(context) {
 
     fun handleLoading(data: LoadingData) {
         if (data.isLoading) {
-            binding.vLoading.setMessage(data.messageId)
             binding.vLoading.setProgress(data)
             if (isShowing.not()) show()
         } else {
diff --git a/core/src/main/java/org/futo/circles/core/view/LoadingView.kt b/core/src/main/java/org/futo/circles/core/view/LoadingView.kt
index d1a3a48589669ce47217b518a62aa9e880cf0209..e64388d70da928a3414d552c483ceef629b41188 100644
--- a/core/src/main/java/org/futo/circles/core/view/LoadingView.kt
+++ b/core/src/main/java/org/futo/circles/core/view/LoadingView.kt
@@ -3,7 +3,6 @@ package org.futo.circles.core.view
 import android.content.Context
 import android.util.AttributeSet
 import android.view.LayoutInflater
-import androidx.annotation.StringRes
 import androidx.constraintlayout.widget.ConstraintLayout
 import org.futo.circles.core.databinding.ViewLoadingBinding
 import org.futo.circles.core.extensions.setIsVisible
@@ -18,16 +17,14 @@ class LoadingView(
         ViewLoadingBinding.inflate(LayoutInflater.from(context), this)
 
 
-    fun setMessage(@StringRes messageId: Int) {
-        binding.tvLoadingMessage.setText(messageId)
-    }
-
     fun setProgress(data: LoadingData) {
         with(binding) {
-            setMessage(data.messageId)
-            horizontalProgress.max = data.total
-            horizontalProgress.progress = data.progress
-            horizontalProgress.setIsVisible(data.total != data.progress)
+            tvLoadingMessage.setText(data.messageId)
+            horizontalProgress.apply {
+                setIsVisible(data.total != data.progress)
+                max = data.total
+                progress = data.progress
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/workspace/SharedCircleDataSource.kt b/core/src/main/java/org/futo/circles/core/workspace/SharedCircleDataSource.kt
new file mode 100644
index 0000000000000000000000000000000000000000..abf48e67954807499b1b3a585822eef1c9b06c54
--- /dev/null
+++ b/core/src/main/java/org/futo/circles/core/workspace/SharedCircleDataSource.kt
@@ -0,0 +1,43 @@
+package org.futo.circles.core.workspace
+
+import org.futo.circles.core.extensions.getRoomOwners
+import org.futo.circles.core.model.PROFILE_SPACE_ACCOUNT_DATA_KEY
+import org.futo.circles.core.provider.MatrixSessionProvider
+import org.futo.circles.core.room.RoomRelationsBuilder
+import org.futo.circles.core.utils.getTimelineRoomFor
+import org.matrix.android.sdk.api.session.getRoomSummary
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomType
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
+import javax.inject.Inject
+
+class SharedCircleDataSource @Inject constructor(
+    private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource,
+    private val roomRelationsBuilder: RoomRelationsBuilder
+) {
+
+    fun getSharedCirclesSpaceId() =
+        spacesTreeAccountDataSource.getRoomIdByKey(PROFILE_SPACE_ACCOUNT_DATA_KEY)
+
+    suspend fun addToSharedCircles(timelineId: String) {
+        getSharedCirclesSpaceId()?.let { roomRelationsBuilder.setRelations(timelineId, it) }
+    }
+
+    suspend fun removeFromSharedCircles(timelineId: String) {
+        getSharedCirclesSpaceId()?.let { roomRelationsBuilder.removeRelations(timelineId, it) }
+    }
+
+    fun getSharedCircleFor(userId: String) = MatrixSessionProvider.currentSession?.roomService()
+        ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null })?.firstOrNull { summary ->
+            summary.roomType == RoomType.SPACE && summary.membership == Membership.JOIN &&
+                    getRoomOwners(summary.roomId).map { it.userId }.contains(userId)
+        }
+
+    fun isCircleShared(circleId: String): Boolean {
+        val timelineId = getTimelineRoomFor(circleId)?.roomId
+        val sharedCirclesTimelinesIds = getSharedCirclesSpaceId()?.let {
+            MatrixSessionProvider.currentSession?.getRoomSummary(it)?.spaceChildren?.map { it.childRoomId }
+        } ?: emptyList()
+        return sharedCirclesTimelinesIds.contains(timelineId)
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/workspace/SpacesTreeAccountDataSource.kt b/core/src/main/java/org/futo/circles/core/workspace/SpacesTreeAccountDataSource.kt
new file mode 100644
index 0000000000000000000000000000000000000000..86e2172185aa859cbf3e4a519c03b67627960298
--- /dev/null
+++ b/core/src/main/java/org/futo/circles/core/workspace/SpacesTreeAccountDataSource.kt
@@ -0,0 +1,28 @@
+package org.futo.circles.core.workspace
+
+import org.futo.circles.core.provider.MatrixSessionProvider
+import javax.inject.Inject
+
+class SpacesTreeAccountDataSource @Inject constructor() {
+
+    private fun getSpacesTreeConfig() =
+        MatrixSessionProvider.currentSession?.accountDataService()
+            ?.getUserAccountDataEvent(SPACES_CONFIG_KEY)?.content ?: emptyMap()
+
+    suspend fun updateSpacesConfigAccountData(key: String, roomId: String) {
+        val currentConfig = getSpacesTreeConfig().toMutableMap()
+        currentConfig[key] = roomId
+        saveSpacesTreeConfig(currentConfig)
+    }
+
+    fun getRoomIdByKey(key: String) = getSpacesTreeConfig()[key]?.toString()
+
+    private suspend fun saveSpacesTreeConfig(configMap: Map<String, Any>) {
+        MatrixSessionProvider.getSessionOrThrow().accountDataService()
+            .updateUserAccountData(SPACES_CONFIG_KEY, configMap)
+    }
+
+    companion object {
+        private const val SPACES_CONFIG_KEY = "org.futo.circles.config"
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/res/layout/dialog_fragment_system_notices.xml b/core/src/main/res/layout/dialog_fragment_system_notices.xml
deleted file mode 100644
index 962a1815ad46e02c95373e5069734a72db7fc462..0000000000000000000000000000000000000000
--- a/core/src/main/res/layout/dialog_fragment_system_notices.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <com.google.android.material.appbar.MaterialToolbar
-        android:id="@+id/toolbar"
-        android:layout_width="0dp"
-        android:layout_height="?attr/actionBarSize"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:navigationIcon="?attr/homeAsUpIndicator"
-        app:title="@string/system_notices"
-        app:titleCentered="true" />
-
-    <View
-        android:id="@+id/toolbarDivider"
-        android:layout_width="0dp"
-        android:layout_height="@dimen/divider_height"
-        android:background="@color/divider_color"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/toolbar" />
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/rvTimeline"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/toolbarDivider" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/layout/list_item_system_notices.xml b/core/src/main/res/layout/list_item_system_notices.xml
deleted file mode 100644
index 1bacb774fe10628bffc4d44b35c96d560f0d6031..0000000000000000000000000000000000000000
--- a/core/src/main/res/layout/list_item_system_notices.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_marginStart="8dp"
-    android:layout_marginTop="8dp"
-    android:layout_marginEnd="36dp">
-
-    <com.google.android.material.imageview.ShapeableImageView
-        android:id="@+id/ivBackground"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:background="@color/chip_selected_color"
-        app:layout_constraintBottom_toBottomOf="@id/tvTime"
-        app:layout_constraintEnd_toEndOf="@id/tvMessage"
-        app:layout_constraintStart_toStartOf="@id/tvMessage"
-        app:layout_constraintTop_toTopOf="@id/tvMessage"
-        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Message" />
-
-    <TextView
-        android:id="@+id/tvMessage"
-        style="@style/body"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:autoLink="web"
-        android:padding="8dp"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:text="sadasdasdasdasdasdasdasdasdasd" />
-
-    <TextView
-        android:id="@+id/tvTime"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="8dp"
-        android:paddingBottom="4dp"
-        android:textSize="12sp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/tvMessage"
-        tools:text="sadasdasdasdasdasdasdasdasdasd" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/navigation/timeline_options_nav_graph.xml b/core/src/main/res/navigation/timeline_options_nav_graph.xml
index 8a250f7a649b591bd2f49585beab3cbdbc1dda2f..be057a07db03101d59b976926e40fe97abb7db6e 100644
--- a/core/src/main/res/navigation/timeline_options_nav_graph.xml
+++ b/core/src/main/res/navigation/timeline_options_nav_graph.xml
@@ -192,7 +192,7 @@
     </dialog>
     <dialog
         android:id="@+id/followingDialogFragment"
-        android:name="org.futo.circles.feature.circles.following.FollowingDialogFragment"
+        android:name="org.futo.circles.core.room.circles.following.FollowingDialogFragment"
         android:label="FollowingDialogFragment"
         tools:layout="@layout/dialog_fragment_following">
 
diff --git a/core/src/main/res/values/color.xml b/core/src/main/res/values/color.xml
index 26ce318f8d0e7d1b4b2d0132b54b995b7dcc6ffb..7f2f935afb90f1b07f2efa16fab896646a04aef0 100644
--- a/core/src/main/res/values/color.xml
+++ b/core/src/main/res/values/color.xml
@@ -7,6 +7,7 @@
     <color name="purple_700">#FF3700B3</color>
     <color name="teal_700">#FF018786</color>
     <color name="black">#FF000000</color>
+    <color name="yellow">#FFCC00</color>
     <color name="white">#FFFFFFFF</color>
     <color name="red">#FF3B30</color>
     <color name="divider_color">#ddd</color>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 5c4f97558b5cc934df2cb5afd1d3853c1a1daf1a..9d39d6f217cc0cfb5076c7ecb97080cee3eb19f2 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -22,7 +22,6 @@
     <string name="moderator">Moderator</string>
     <string name="user">User</string>
     <string name="read_only">Read-only</string>
-    <string name="configuring_workspace">Configuring workspace</string>
     <string name="photos">Photos</string>
     <string name="loading">Loading</string>
     <string name="root_space_name">Circles</string>
@@ -30,6 +29,7 @@
     <string name="shared_circles">Shared Circles</string>
     <string name="photos_space_name">My Photo Galleries</string>
     <string name="groups_space_name">My Groups</string>
+    <string name="peopel_space_name">People</string>
     <string name="known_users">Known users</string>
     <string name="suggestions">Suggestions</string>
     <string name="no_results">No results</string>
@@ -56,8 +56,6 @@
     <string name="choose_gallery">Choose gallery</string>
     <string name="pick_media">Pick media</string>
     <string name="change_icon">Change icon</string>
-    <string name="system_notices">System notices</string>
-    <string name="system_notices_room_not_found">System notices room not found.</string>
     <string name="account">Account</string>
     <string name="clear_cache_and_reload">Clear cache and reload</string>
     <string name="deactivate_my_account">Deactivate my account</string>
@@ -129,5 +127,18 @@
     <string name="decline">Decline</string>
     <string name="requested_to_join_format">%s requested to join</string>
     <string name="invited_by_format">Invited by %s</string>
-
+    <string name="circle_encryption_warning">NOTE: Circle name and cover image are not encrypted</string>
+    <string name="circle_name">Circle name</string>
+    <string name="circle_type">Circle type</string>
+    <string name="public_type">Public</string>
+    <string name="public_circle_explanation">Other users can ask to join</string>
+    <string name="private_type">Private</string>
+    <string name="private_circle_explanation">Accessible only by your invitation</string>
+    <string name="gallery_name">Gallery name</string>
+    <string name="gallery_encryption_warning">NOTE: Gallery name and cover image are not encrypted</string>
+    <string name="group_name">Group name</string>
+    <string name="group_encryption_warning">NOTE: Group name, topic and cover image are not encrypted</string>
+    <string name="group_topic">Group topic</string>
+    <string name="remove_from_this_circle_but_do_not_unfollow">Remove from this circle, but do not unfollow</string>
+    <string name="unfollow_completely_remove_from_all_circles">Unfollow completely (remove from all circles)</string>
 </resources>
\ No newline at end of file
diff --git a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt
index ea1352e1b8723fc636b644915e0d58f704995bda..53f3d22274b95e5a62f178e47a8fe89565ae97eb 100644
--- a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt
+++ b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt
@@ -6,12 +6,15 @@ import android.provider.MediaStore
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.core.model.Gallery
 import org.futo.circles.core.model.MediaType
+import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.room.CreateRoomDataSource
 import org.futo.circles.core.timeline.post.SendMessageDataSource
-import org.futo.circles.core.utils.getJoinedRoomIdByTag
 import org.futo.circles.gallery.model.MediaFolderListItem
 import org.futo.circles.gallery.model.MediaToBackupItem
 import org.futo.circles.gallery.model.toMediaToBackupItem
+import org.matrix.android.sdk.api.session.getRoom
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import java.io.File
 import javax.inject.Inject
 
@@ -79,13 +82,22 @@ class MediaBackupDataSource @Inject constructor(
         var roomId = getJoinedRoomIdByTag(bucketId)
         if (roomId == null) {
             roomId = createRoomDataSource.createRoom(
-                circlesRoom = Gallery(tag = bucketId),
+                circlesRoom = Gallery(),
                 name = getFolderNameBy(bucketId)
             )
+            MatrixSessionProvider.currentSession?.getRoom(roomId)?.tagsService()
+                ?.addTag(bucketId, null)
         }
         return roomId
     }
 
+    private fun getJoinedRoomIdByTag(tag: String): String? {
+        val session = MatrixSessionProvider.currentSession ?: return null
+        return session.roomService().getRoomSummaries(roomSummaryQueryParams {
+            memberships = listOf(Membership.JOIN)
+        }).firstOrNull { it.hasTag(tag) }?.roomId
+    }
+
     private fun getMediaCursor(
         selection: String? = null
     ): Cursor? {
diff --git a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt
index c12c04964d126c6e9042eadf1a5bb8f54d846ab8..84a00d972f83f5d5a67022b3d8bb445f4188af89 100644
--- a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt
+++ b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt
@@ -3,8 +3,9 @@ package org.futo.circles.gallery.feature.backup
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.map
 import org.futo.circles.core.extensions.createResult
+import org.futo.circles.core.model.PHOTOS_SPACE_ACCOUNT_DATA_KEY
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.core.utils.getPhotosSpaceId
+import org.futo.circles.core.workspace.SpacesTreeAccountDataSource
 import org.futo.circles.gallery.model.MediaBackupSettingsData
 import org.futo.circles.gallery.model.toMediaBackupSettingsData
 import org.matrix.android.sdk.api.session.getRoom
@@ -12,19 +13,25 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
 import org.matrix.android.sdk.api.util.Optional
 import javax.inject.Inject
 
-class RoomAccountDataSource @Inject constructor() {
+class RoomAccountDataSource @Inject constructor(
+    private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource
+) {
+
+    private fun getPhotosSpaceId() = spacesTreeAccountDataSource.getRoomIdByKey(
+        PHOTOS_SPACE_ACCOUNT_DATA_KEY
+    ) ?: ""
 
     fun getMediaBackupSettingsLive() =
-        getAccountDataEventLive(getPhotosSpaceId() ?: "", ROOM_BACKUP_EVENT_TYPE)?.map {
+        getAccountDataEventLive(getPhotosSpaceId(), ROOM_BACKUP_EVENT_TYPE)?.map {
             it.getOrNull()?.content.toMediaBackupSettingsData()
         }
 
     fun getMediaBackupSettings() =
-        getAccountDataEvent(getPhotosSpaceId() ?: "", ROOM_BACKUP_EVENT_TYPE)?.content
+        getAccountDataEvent(getPhotosSpaceId(), ROOM_BACKUP_EVENT_TYPE)?.content
             .toMediaBackupSettingsData()
 
     suspend fun saveMediaBackupSettings(data: MediaBackupSettingsData) = updateRoomAccountData(
-        getPhotosSpaceId() ?: "", ROOM_BACKUP_EVENT_TYPE, data.toMap()
+        getPhotosSpaceId(), ROOM_BACKUP_EVENT_TYPE, data.toMap()
     )
 
     fun getMediaBackupDateModified(roomId: String) =
diff --git a/gallery/src/main/res/values/strings.xml b/gallery/src/main/res/values/strings.xml
index 878656c6afa528bb23c360911e1bbf3636367889..6b0021488da69412bc5de1c450ee92cadbda0acd 100644
--- a/gallery/src/main/res/values/strings.xml
+++ b/gallery/src/main/res/values/strings.xml
@@ -14,10 +14,7 @@
     <string name="compress_before_sending">Compress before sending</string>
     <string name="backup_device_folders">Backup device folders</string>
     <string name="backup_folders_hint">Choose folders to backup and view in your Gallery:</string>
-    <string name="gallery_name">Gallery name</string>
-    <string name="gallery_encryption_warning">NOTE: Gallery name and cover image are not encrypted</string>
     <string name="create_new_gallery">Create new gallery</string>
-    <string name="create">Create</string>
     <string name="photos_empty_message">Create your first Gallery</string>
 
 </resources>
\ No newline at end of file