diff --git a/3rdparty/qtquickdesigner-components b/3rdparty/qtquickdesigner-components
index 80b9e31a8863c9bf2a57c3d569b761d9df71cdb3..20397e26370ff073125fd19f77c7ad013276b5bd 160000
--- a/3rdparty/qtquickdesigner-components
+++ b/3rdparty/qtquickdesigner-components
@@ -1 +1 @@
-Subproject commit 80b9e31a8863c9bf2a57c3d569b761d9df71cdb3
+Subproject commit 20397e26370ff073125fd19f77c7ad013276b5bd
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 976d49cd6c0b854ea6f3a5d38df37e87b2bb7eb7..2d1ca30efe49cc5117362d4ed93a4e83b3f164fd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,10 +4,6 @@ project(qtuiviewer LANGUAGES CXX)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
-#set(CMAKE_AUTOUIC ON)
-#set(CMAKE_AUTOMOC ON)
-#set(CMAKE_AUTORCC ON)
-
 set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
@@ -25,7 +21,7 @@ find_package(
 find_package(Qt6 REQUIRED COMPONENTS Core)
 qt_policy(SET QTP0002 NEW)
 
-set(QT_MINIMUM_VERSION 6.7.0)
+set(QT_MINIMUM_VERSION 6.7.3)
 if(QT_VERSION VERSION_LESS QT_MINIMUM_VERSION)
     message(FATAL_ERROR "Minimum supported Qt version: ${QT_MINIMUM_VERSION}")
 endif()
diff --git a/cicd/gitlab-ci.yml b/cicd/gitlab-ci.yml
index 9a73acdd5fc5fa711d7f6efbdb00cde9af1a52f1..293b3893b79b25ee9b707bf1d0927e27b44130c9 100644
--- a/cicd/gitlab-ci.yml
+++ b/cicd/gitlab-ci.yml
@@ -1,5 +1,5 @@
 variables:
-  QDS_CI_QT_VERSION: "6.7.0"
+  QDS_CI_QT_VERSION: "6.7.3"
   QDS_CI_ARTIFACTS_PATH: "${CI_PROJECT_DIR}/artifacts"
   DEBIAN_FRONTEND: non-interactive
   GIT_SUBMODULE_STRATEGY: recursive
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e1c917ddeaa4e4caf75cf2bd428f328118f60252..e0714325934988658dc9b23b1d0b021e94fa4cde 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -11,7 +11,6 @@ qt_add_executable(${PROJECT_NAME}
     backend/main.cpp
     backend/logger.h
     backend/backend.cpp backend/backend.h
-    backend/serviceconnector.cpp backend/serviceconnector.h
     backend/projectmanager.cpp backend/projectmanager.h
     backend/settings.cpp backend/settings.h
     backend/dsconnector/ds.cpp backend/dsconnector/ds.h
@@ -60,7 +59,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
 qt_add_library(qtuiviewerlib OBJECT
     EXCLUDE_FROM_ALL
     backend/projectmanager.cpp backend/projectmanager.h
-    backend/serviceconnector.cpp backend/serviceconnector.h
     backend/settings.cpp backend/settings.h
     backend/dsconnector/ds.cpp backend/dsconnector/ds.h
     backend/dsconnector/dsdiscovery.cpp backend/dsconnector/dsdiscovery.h
diff --git a/src/HomePage.qml b/src/HomePage.qml
index 2f2177144325f3c428185866c80ebb2572c0fb97..d6e328bada16a91eab0503dba1492f0e68873237 100644
--- a/src/HomePage.qml
+++ b/src/HomePage.qml
@@ -225,10 +225,18 @@ Flickable {
                             Layout.alignment: Qt.AlignHCenter
 
                             placeholderText: qsTr("IP Address")
-                            text: "10.0.2.2"
+                            text: backend.lastDesignStudioIp()
                             validator: RegularExpressionValidator {
                                 regularExpression: /^(\d{1,3}\.){3}\d{1,3}$/
                             }
+
+                            Connections {
+                                target: backend
+
+                                function onConnectedChanged(isConnected, ip) {
+                                    ipAddress.text = ip
+                                }
+                            }
                         }
 
                         Button {
diff --git a/src/SettingsPage.qml b/src/SettingsPage.qml
index c05c13172d017cbc317073327b6d3a918bffd4b7..ef978603540333d68bfd65cafa218a1afb167ff8 100644
--- a/src/SettingsPage.qml
+++ b/src/SettingsPage.qml
@@ -31,6 +31,7 @@ Flickable {
             text: qsTr("Auto-scale")
             subText: qsTr("Scales the project to fit to current display and orientation")
             checked: backend.autoScaleProject() ? Qt.Checked : Qt.Unchecked
+            onToggled: backend.setAutoScaleProject(checked)
         }
 
         SettingsItem {
diff --git a/src/backend/backend.cpp b/src/backend/backend.cpp
index 7d0c60267de5594c7f3071a5f9c4e3cbe163ef5d..2b87e240d4aa9a222f6758a063659824c0ad1f50 100644
--- a/src/backend/backend.cpp
+++ b/src/backend/backend.cpp
@@ -26,15 +26,6 @@
 #include "backend.h"
 
 #include <QDesktopServices>
-#include <QEventLoop>
-#include <QFileInfo>
-#include <QGuiApplication>
-#include <QJniObject>
-#include <QJsonArray>
-#include <QJsonObject>
-#include <QSettings>
-#include <QSysInfo>
-#include <QTimer>
 
 #include "logger.h"
 
@@ -50,32 +41,15 @@ Backend::Backend(QObject *parent)
     QDesktopServices::setUrlHandler("qtdesignstudio", this, "parseDesignViewerUrl");
     QDesktopServices::setUrlHandler("https", this, "parseDesignViewerUrl");
 
-    // Initialize background update
-    connect(&m_projectListUpdateTimer, &QTimer::timeout, this, &Backend::updateUserProjectList);
-    m_projectListUpdateTimer.setInterval(1000 * 10);
-    m_projectListUpdateTimer.start();
-    updateUserProjectList();
-    initDesignStudioManager();
-
-    connect(qApp,
-            &QGuiApplication::applicationStateChanged,
-            this,
-            [this](Qt::ApplicationState state) {
-                qDebug() << "Application state changed to:" << state;
-                if (state == Qt::ApplicationState::ApplicationActive) {
-                    m_dsConnectorThread.start();
-                    m_projectListUpdateTimer.start();
-                } else if (state == Qt::ApplicationState::ApplicationSuspended) {
-                    m_dsConnectorThread.quit();
-                    m_projectListUpdateTimer.stop();
-                }
-            });
+    m_dsManagerThread.setParent(this);
+    connect(&m_dsManagerThread, &QThread::started, this, &Backend::initDsManager);
+    m_dsManagerThread.start();
 
     connect(&Logger::instance(), &Logger::logMessage, this, [this](QtMsgType type, QString &msg) {
         // if we have any active project running, then reroute
         // all the logs to the dsmanager with the last project sender id
         if (m_projectManager) {
-            QMetaObject::invokeMethod(m_designStudioManager.get(),
+            QMetaObject::invokeMethod(m_dsManager.get(),
                                       "sendProjectLogs",
                                       Qt::QueuedConnection,
                                       Q_ARG(QString, m_lastProjectSenderId),
@@ -104,8 +78,12 @@ Backend::Backend(QObject *parent)
     qDebug() << "-- Build CPU architecture: " << QSysInfo::buildCpuArchitecture();
     qDebug() << "-- Device serial: " << getDeviceSerial();
     qDebug() << "-- Device unique ID: " << getDeviceUuid();
+}
 
-    qDebug() << "Thread id backend:" << QThread::currentThreadId();
+Backend::~Backend()
+{
+    m_dsManagerThread.quit();
+    m_dsManagerThread.wait();
 }
 
 // this function returns the device serial number (which is really unique)
@@ -161,7 +139,7 @@ void Backend::initializeProjectManager()
         [&] {
             emit popupClose();
             m_projectManager.reset();
-            QMetaObject::invokeMethod(m_designStudioManager.get(),
+            QMetaObject::invokeMethod(m_dsManager.get(),
                                       "sendProjectStopped",
                                       Qt::QueuedConnection,
                                       Q_ARG(QString, m_lastProjectSenderId));
@@ -169,82 +147,57 @@ void Backend::initializeProjectManager()
         Qt::QueuedConnection);
 }
 
-void Backend::initDesignStudioManager()
+void Backend::initDsManager()
 {
-    connect(&m_dsConnectorThread, &QThread::started, [this] {
-        qDebug() << "Design Studio Manager thread started";
-        m_designStudioManager.reset(new DesignStudioManager(nullptr, false, getDeviceUuid()));
-
-        // signals goes from DS Manager to UI
-        connect(m_designStudioManager.get(),
-                &DesignStudioManager::pairingPinRequested,
-                this,
-                &Backend::pinRequested);
-
-        connect(m_designStudioManager.get(),
-                &DesignStudioManager::projectReceived,
-                this,
-                &Backend::runDsProject);
-
-        connect(m_designStudioManager.get(),
-                &DesignStudioManager::designStudioConnected,
-                this,
-                [this](const QString &id, const QString &ipAddr) {
-                    emit connectedChanged(true, ipAddr);
-                });
-        connect(m_designStudioManager.get(),
-                &DesignStudioManager::designStudioDisconnected,
-                this,
-                [this](const QString &id, const QString &ipAddr) {
-                    if (id == m_lastProjectSenderId && m_projectManager) {
-                        m_projectManager->stopProject();
-                    }
-                    emit connectedChanged(false, ipAddr);
-                });
-
-        connect(m_designStudioManager.get(),
-                &DesignStudioManager::projectStopRequested,
-                this,
-                [this](const QString &id) {
-                    if (m_projectManager) {
-                        m_projectManager->stopProject();
-                    }
-                });
-
-        // signals goes from UI to DS Manager
-        connect(this,
-                &Backend::enterPin,
-                m_designStudioManager.get(),
-                &DesignStudioManager::enterPin);
-    });
+    qDebug() << "Design Studio Manager thread started. Initializing Design Studio Manager";
+    m_dsManager.reset(new DesignStudioManager(nullptr, false, getDeviceUuid()));
 
-    connect(&m_dsConnectorThread, &QThread::finished, this, [this] {
-        qDebug() << "Design Studio Manager thread finished";
-        m_designStudioManager.reset();
-    });
+    connect(m_dsManager.get(), &DesignStudioManager::projectReceived, this, &Backend::runProject);
 
-    connect(&m_serviceConnector,
-            &ServiceConnector::downloadProgress,
+    connect(m_dsManager.get(),
+            &DesignStudioManager::designStudioConnected,
             this,
-            &Backend::downloadProgress);
+            [this](const QString &id, const QString &ipAddr) {
+                emit connectedChanged(true, ipAddr);
+            });
+    connect(m_dsManager.get(),
+            &DesignStudioManager::designStudioDisconnected,
+            this,
+            [this](const QString &id, const QString &ipAddr) {
+                if (id == m_lastProjectSenderId && m_projectManager) {
+                    m_projectManager->stopProject();
+                }
+                emit connectedChanged(false, ipAddr);
+            });
+
+    connect(m_dsManager.get(),
+            &DesignStudioManager::projectStopRequested,
+            this,
+            [this](const QString &id) {
+                if (m_projectManager) {
+                    m_projectManager->stopProject();
+                }
+            });
+
+    m_dsManager->initialize();
+    qDebug() << "Design Studio Manager initialized";
 }
 
 void Backend::connectDesignStudio(const QString &ipAddr)
 {
-    QMetaObject::invokeMethod(m_designStudioManager.get(),
-                              "designStudioFound",
+    QMetaObject::invokeMethod(m_dsManager.get(),
+                              "initDesignStudio",
                               Qt::QueuedConnection,
                               Q_ARG(QString, ipAddr),
-                              Q_ARG(QString, ""),
-                              Q_ARG(bool, true));
+                              Q_ARG(QString, ""));
     emit popupOpen("Connecting in the background...", 1500);
 }
 
-void Backend::runDsProject(const QString &id, const QByteArray &projectData)
+void Backend::runProject(const QString &id, const QByteArray &projectData)
 {
     // we'll use this to notify the correct DS when the project started/stopped
     m_lastProjectSenderId = id;
-    QMetaObject::invokeMethod(m_designStudioManager.get(),
+    QMetaObject::invokeMethod(m_dsManager.get(),
                               "sendProjectRunning",
                               Qt::QueuedConnection,
                               Q_ARG(QString, id));
@@ -257,7 +210,7 @@ void Backend::runDsProject(const QString &id, const QByteArray &projectData)
 
     if (!m_projectManager->runProject(projectPath)) {
         qCritical() << "Could not run project. Please check the logs for more information.";
-        QMetaObject::invokeMethod(m_designStudioManager.get(),
+        QMetaObject::invokeMethod(m_dsManager.get(),
                                   "sendProjectStopped",
                                   Qt::QueuedConnection,
                                   Q_ARG(QString, id));
@@ -268,206 +221,6 @@ void Backend::runDsProject(const QString &id, const QByteArray &projectData)
     emit popupClose();
 }
 
-void Backend::runDemoProject(const QString &projectName)
-{
-    initializeProjectManager();
-    qDebug() << "Checking if demo project is cached for " << projectName;
-    emit popupOpen();
-
-    // sample project info
-    // [{"lastUpdate":1701947766739.9812,"name":"ClusterTutorial.qmlrc"}]
-    const std::optional<QJsonArray> projectList = m_serviceConnector.fetchDemoList();
-
-    if (projectList == std::nullopt) {
-        qCritical()
-            << "Could not fetch demo project list. Please check your internet connection and "
-               "try again.";
-        emit popupClose();
-        return;
-    }
-
-    QJsonObject projectInfo;
-    for (auto project : projectList.value()) {
-        if (projectName == project.toObject().value("name").toString().remove(".qmlrc")) {
-            projectInfo = project.toObject();
-            break;
-        }
-    }
-
-    const bool cached = m_projectManager->isDemoProjectCached(projectInfo);
-
-    if (!cached) {
-        updatePopup("Downloading demo project...", false);
-
-        const std::optional<QByteArray> project = m_serviceConnector.fetchDemo(projectName);
-
-        if (project == std::nullopt) {
-            qCritical() << "Could not download demo project. Please check the logs for more "
-                           "information.";
-            emit popupClose();
-            return;
-        }
-
-        updatePopup("Caching demo project...");
-        if (!m_projectManager->cacheDemoProject(project.value(), projectInfo)) {
-            qCritical()
-                << "Could not cache demo project. Please check the logs for more information.";
-            emit popupClose();
-            return;
-        }
-    } else {
-        qDebug() << "Demo project is cached. Running cached project...";
-    }
-
-    updatePopup("Running demo project...");
-    if (!m_projectManager->runDemoProject(projectName))
-        qCritical() << "Could not run demo project. Please check the logs for more information.";
-    else {
-        updatePopup("Showing the app window...");
-        m_projectManager->showAppWindow();
-    }
-
-    emit popupClose();
-}
-
-void Backend::clearDemoCaches()
-{
-    emit popupOpen();
-    updatePopup("Clearing demo caches...");
-    ProjectManager().clearDemoCaches();
-    emit popupClose();
-}
-
-void Backend::runUserProject(const QString &projectName, const QString &password)
-{
-    initializeProjectManager();
-    updatePopup("Running user project");
-    emit popupOpen();
-
-    qDebug() << "Running user project:" << projectName;
-
-    // fetch the project list to check if the project is cached
-    const std::optional<QJsonArray> projectList = m_serviceConnector.fetchUserProjectList(
-        m_settings.userHash());
-
-    if (projectList == std::nullopt) {
-        qCritical()
-            << "Could not fetch user project list. Please check your internet connection and "
-               "try again.";
-        emit popupClose();
-        return;
-    }
-
-    QJsonObject projectInfo;
-    for (const auto &project : projectList.value()) {
-        if (projectName == project.toObject().value("appName").toString()) {
-            projectInfo = project.toObject();
-            break;
-        }
-    }
-
-    const bool projectCached = m_projectManager->isProjectCached(projectInfo);
-
-    if (!projectCached) {
-        qDebug("Project is not cached. Downloading...");
-        updatePopup("Project is not cached. Downloading...", false);
-        const std::optional<QByteArray> projectData
-            = m_serviceConnector.fetchUserProject(m_settings.userHash(), projectName, password);
-
-        if (projectData == std::nullopt) {
-            qCritical()
-                << "Could not download project. Please check the logs for more information.";
-            emit popupClose();
-            return;
-        }
-
-        updatePopup("Caching user project...");
-        if (!m_projectManager->cacheProject(projectData.value(), projectInfo)) {
-            qCritical() << "Could not cache project. Please check the logs for more information.";
-            emit popupClose();
-            return;
-        }
-    }
-
-    qDebug("Project is cached. Running cached project...");
-    updatePopup("Running cached project...");
-    if (!m_projectManager->runCachedProject(projectInfo))
-        qCritical() << "Could not run project. Please check the logs for more information.";
-    else {
-        updatePopup("Showing the app window...");
-        m_projectManager->showAppWindow();
-    }
-
-    emit popupClose();
-}
-
-void Backend::runOnlineProject(const QString &url)
-{
-    initializeProjectManager();
-    emit popupOpen();
-    updatePopup("Downloading...", false);
-    const std::optional<QByteArray> projectData = m_serviceConnector.fetchProject(url);
-
-    if (projectData == std::nullopt) {
-        qCritical() << "Could not download project. Please check the logs for more information.";
-        emit popupClose();
-        return;
-    }
-
-    updatePopup("Unpacking project...");
-    QString projectPath = m_projectManager->unpackProject(projectData.value());
-    updatePopup("Running project...");
-
-    if (!m_projectManager->runProject(projectPath))
-        qCritical() << "Could not run project. Please check the logs for more information.";
-    else {
-        m_projectManager->showAppWindow();
-    }
-
-    emit popupClose();
-}
-
-void Backend::updateUserProjectList()
-{
-    const QString userHash = m_settings.userHash();
-
-    if (userHash.isEmpty()) {
-        return;
-    }
-
-    qDebug() << "Fetching available project list for user:" << userHash;
-    const std::optional<QJsonArray> projectList = m_serviceConnector.fetchUserProjectList(userHash);
-
-    if (projectList == std::nullopt) {
-        qWarning(
-            "Could not fetch project list. Please check your internet connection and try again.");
-    } else if (projectList.value() == m_projectList) {
-        qDebug("No new projects are available");
-    } else {
-        qDebug("List of available projects fetched:");
-        for (const auto &project : projectList.value()) {
-            const QString projectName{project.toObject().value("appName").toString()};
-            qDebug() << "--" << projectName;
-        }
-
-        // check if any project is removed on the cloud
-        for (const auto &project : m_projectList) {
-            const QString projectName{project.toObject().value("appName").toString()};
-            if (!projectList.value().contains(project)) {
-                qDebug() << "Project removed:" << projectName << ". Removing from cache...";
-                // remove the project from the cache
-                ProjectManager().clearCachedProject(project.toObject());
-            }
-        }
-    }
-
-    // we need to set m_projectList even if it is empty
-    // because this triggers the onModelChanged function in the QML
-    // in order to update the UI
-    m_projectList = projectList.value();
-    emit projectListChanged();
-}
-
 void Backend::scanQrCode()
 {
     m_qrScanner.reset(new QrScanner);
@@ -481,18 +234,7 @@ void Backend::scanQrCode()
 
 void Backend::parseDesignViewerUrl(const QUrl &url)
 {
-    // url format could be one of the following:
-    // - https://<url>/<project_name>.qmlrc
-    // - qtdesignviewer://<user_hash>
-    // - qtdesignstudio://<ipv4_address>?<design_studio_id>
-
-    if (url.scheme() == "https") {
-        emit urlUpdated(url.toString());
-    } else if (url.scheme() == "qtdesignviewer") {
-        qDebug() << "Registering user from QR code";
-        m_settings.setUserHash(url.host());
-        updateUserProjectList();
-    } else if (url.scheme() == "qtdesignstudio") {
+    if (url.scheme() == "qtdesignstudio") {
         qDebug() << "Connecting to Design Studio from QR code";
 
         if (url.host().isEmpty()) {
@@ -506,7 +248,7 @@ void Backend::parseDesignViewerUrl(const QUrl &url)
         const QString ipv4Addr = url.host();
         const QString designStudioId = url.query();
 
-        QMetaObject::invokeMethod(m_designStudioManager.get(),
+        QMetaObject::invokeMethod(m_dsManager.get(),
                                   "designStudioFound",
                                   Qt::QueuedConnection,
                                   Q_ARG(QString, ipv4Addr),
@@ -520,5 +262,19 @@ void Backend::parseDesignViewerUrl(const QUrl &url)
 void Backend::popupInterrupted()
 {
     qDebug() << "Popup closed prematurely. Interrupting active downloads (if any)";
-    QMetaObject::invokeMethod(&m_serviceConnector, "interrupted", Qt::QueuedConnection);
+}
+
+bool Backend::autoScaleProject() const
+{
+    return m_settings.autoScaleProject();
+}
+
+void Backend::setAutoScaleProject(bool autoScaleProject)
+{
+    m_settings.setAutoScaleProject(autoScaleProject);
+}
+
+QString Backend::lastDesignStudioIp() const
+{
+    return m_dsManager ? m_dsManager->getDesignStudioIp({}) : QString();
 }
diff --git a/src/backend/backend.h b/src/backend/backend.h
index 1351df8f5dbf22987259fef7797957275c9f7d41..4a24e3f3cc8d9eb90f660cd463c4b061fff7e45b 100644
--- a/src/backend/backend.h
+++ b/src/backend/backend.h
@@ -27,42 +27,30 @@
 #define DV_ANDROID_H
 
 #include <QThread>
-#include <QTimer>
-
-#include <memory>
 
 #include "dsconnector/dsmanager.h"
 #include "projectmanager.h"
 #include "qrscanner.h"
-#include "serviceconnector.h"
 #include "settings.h"
 
 class Backend : public QObject
 {
     Q_OBJECT
-    Q_PROPERTY(QJsonArray projectList READ projectList NOTIFY projectListChanged)
-
 public:
     explicit Backend(QObject *parent = nullptr);
-
-    QJsonArray projectList() const { return m_projectList; }
+    ~Backend();
 
 private:
-    // UI data
-    QJsonArray m_projectList;
-
     // Other members
-    ServiceConnector m_serviceConnector;
     std::unique_ptr<ProjectManager> m_projectManager;
     std::unique_ptr<QrScanner> m_qrScanner;
 
     // DS Connector
-    QThread m_dsConnectorThread;
-    std::unique_ptr<DesignStudioManager> m_designStudioManager;
+    QScopedPointer<DesignStudioManager> m_dsManager;
+    QThread m_dsManagerThread;
     QString m_lastProjectSenderId;
 
     // Settings
-    QTimer m_projectListUpdateTimer;
     Settings m_settings;
 
     // member functions
@@ -70,48 +58,35 @@ private:
     QByteArray getDeviceSerial();
     QString getDeviceUuid();
 
-signals:
-    // UI signals - Home page
-    void projectListChanged();
-    void urlUpdated(QString);
-    void userHashChanged();
+    void initDsManager();
+    void initializeProjectManager();
+
+    void runProject(const QString &id, const QByteArray &projectData);
 
+signals:
     // UI signals - Popup
-    void downloadProgress(float);
     void popupProgressIndeterminateChanged(bool indeterminate);
     void popupTextChanged(QString text);
     void popupOpen(const QString &text = {}, int timeout = 0);
     void popupClose();
 
     // UI signals - from DS Manager page
-    void pinRequested(const QString &id);
-    void pinPopupOpen();
     void connectedChanged(bool connected, const QString &ipAddr);
 
     // UI signals - from UI
-    void enterPin(const QString &deviceId, const QString &pin);
     void connectToDesignStudio(const QString &url);
 
 public slots:
     QString buildInfo() const;
     void scanQrCode();
-
-    void runOnlineProject(const QString &url);
-    void runUserProject(const QString &projectName, const QString &password);
-    void runDemoProject(const QString &projectName);
-    void runDsProject(const QString &id, const QByteArray &projectData);
-    void clearDemoCaches();
-
-    void initDesignStudioManager();
     void connectDesignStudio(const QString &ipAddr);
-
     void parseDesignViewerUrl(const QUrl &url);
-
     void popupInterrupted();
 
-private slots:
-    void initializeProjectManager();
-    void updateUserProjectList();
+    bool autoScaleProject() const;
+    void setAutoScaleProject(bool autoScaleProject);
+
+    QString lastDesignStudioIp() const;
 };
 
 #endif // DV_ANDROID_H
diff --git a/src/backend/constants.h b/src/backend/constants.h
deleted file mode 100644
index dfbf2615b24afc89ebe01404612c4b8eb3b03985..0000000000000000000000000000000000000000
--- a/src/backend/constants.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2024 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QStandardPaths>
-#include <QString>
-
-namespace Constants {
-
-// Path Constants
-namespace Paths {
-const static QString WritableLocation = QStandardPaths::writableLocation(
-    QStandardPaths::AppDataLocation);
-const static QString ProjectCachePath = WritableLocation + "/projectCache";
-const static QString DemoProjectsPath = WritableLocation + "/demoProjects";
-const static QString ConfigPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
-const static QString ConfigPathDsManager = ConfigPath + "/dsmanager.json";
-const static QString ConfigPathSettings = ConfigPath + "/settings.json";
-} // namespace Paths
-
-} // namespace Constants
diff --git a/src/backend/dsconnector/ds.cpp b/src/backend/dsconnector/ds.cpp
index 5379af82881f6be0f603f5c7cda6552d916790f0..f3282b41194e8f07b60bad0728490a5b2423a442 100644
--- a/src/backend/dsconnector/ds.cpp
+++ b/src/backend/dsconnector/ds.cpp
@@ -25,20 +25,14 @@
 
 #include "ds.h"
 
-#include <QDebug>
-#include <QGuiApplication>
 #include <QJsonDocument>
 #include <QJsonObject>
-#include <QRect>
 #include <QScreen>
-#include <QSysInfo>
-#include <QTimer>
 
 DesignStudio::DesignStudio(const QString &ipv4Addr,
                            const quint16 port,
                            const QString &designStudioId,
                            const QString &deviceId,
-                           const bool skipPairing,
                            QObject *parent)
     : QObject(parent)
     , m_ipv4Addr(ipv4Addr)
@@ -46,11 +40,9 @@ DesignStudio::DesignStudio(const QString &ipv4Addr,
     , m_url("ws://" + m_ipv4Addr + ":" + QString::number(m_port))
     , m_id(designStudioId)
     , m_deviceUuid(deviceId)
-    , m_skipPairing(skipPairing)
 {
     initPingPong();
     initSocket();
-    qDebug() << "Design Studio" << m_id << "skip pairing" << m_skipPairing;
 }
 
 void DesignStudio::initPingPong()
@@ -88,6 +80,7 @@ void DesignStudio::initSocket()
             m_socketWasConnected = true;
             m_pingTimer.start(15000);
             m_pongTimer.stop();
+            emit connected(m_id);
         } else if (state == QAbstractSocket::UnconnectedState && m_socketWasConnected) {
             qDebug() << "Disconnected from Design Studio" << m_id;
             m_socketWasConnected = false;
@@ -96,18 +89,21 @@ void DesignStudio::initSocket()
             emit disconnected(m_id);
         }
     });
+}
 
+void DesignStudio::connectToDesignStudio()
+{
     m_socket.open(m_url);
 }
 
-QString DesignStudio::ipv4Addr() const
+void DesignStudio::disconnectFromDesignStudio()
 {
-    return m_ipv4Addr;
+    m_socket.close();
 }
 
-bool DesignStudio::skipPairing() const
+QString DesignStudio::ipv4Addr() const
 {
-    return m_skipPairing;
+    return m_ipv4Addr;
 }
 
 quint16 DesignStudio::port() const
@@ -125,12 +121,7 @@ QString DesignStudio::id() const
     return m_id;
 }
 
-bool DesignStudio::isPaired() const
-{
-    return m_skipPairing || m_paired;
-}
-
-bool DesignStudio::connected() const
+bool DesignStudio::isConnected() const
 {
     return m_socket.state() == QAbstractSocket::ConnectedState;
 }
@@ -143,11 +134,6 @@ void DesignStudio::setIpAddress(const QString &ipv4Addr)
     m_socket.open(m_url);
 }
 
-void DesignStudio::setSkipPairing(const bool skipPairing)
-{
-    m_skipPairing = skipPairing;
-}
-
 void DesignStudio::setDesignStudioId(const QString &designStudioId)
 {
     m_id = designStudioId;
@@ -165,19 +151,12 @@ void DesignStudio::sendDeviceInfo()
     deviceInfo["architecture"] = QSysInfo::currentCpuArchitecture();
     deviceInfo["deviceId"] = m_deviceUuid;
     deviceInfo["appVersion"] = QString(CMAKE_VAR_GIT_VERSION);
-    deviceInfo["skipPairing"] = m_skipPairing;
 
     qDebug() << "Sending device info to Design Studio" << deviceInfo;
 
     sendData(PackageToDesignStudio::deviceInfo, deviceInfo);
 }
 
-void DesignStudio::sendPairingPin(const QString &pin)
-{
-    qDebug() << "Sending pairing PIN to Design Studio with pin" << pin;
-    sendData(PackageToDesignStudio::pairingPin, pin);
-}
-
 void DesignStudio::sendData(const QLatin1String &dataType, const QJsonValue &data)
 {
     QJsonObject message;
@@ -210,26 +189,10 @@ void DesignStudio::processTextMessage(const QString &message)
         if (m_id != newDesignStudioId) {
             qDebug() << "Design Studio" << m_id << "changed ID to" << newDesignStudioId
                      << "with IP address" << m_ipv4Addr << "Notifying ds manager.";
-            emit idChanged(newDesignStudioId, m_ipv4Addr);
-        } else {
-            qDebug() << "Design Studio" << m_id << "is waiting for the info.";
-            sendDeviceInfo();
+            m_id = newDesignStudioId;
+            emit idReceived(newDesignStudioId, m_ipv4Addr);
         }
-    } else if (dataType == PackageFromDesignStudio::pinRequested) {
-        qDebug() << "Registration PIN requested by Design Studio";
-        emit pinRequested(m_id);
-    } else if (dataType == PackageFromDesignStudio::pinFailed) {
-        qDebug() << "Registration PIN verification failed";
-        emit pinFailed(m_id);
-    } else if (dataType == PackageFromDesignStudio::deviceIdDeclined) {
-        qDebug() << "Design Studio unpaired the device";
-        m_paired = false;
-        emit unpaired(m_id);
-    } else if (dataType == PackageFromDesignStudio::deviceIdAccepted) {
-        qDebug() << "Design Studio accepted the device ID. Connection alive.";
-        m_paired = true;
-        m_skipPairing = false;
-        emit paired(m_id);
+        sendDeviceInfo();
     } else if (dataType == PackageFromDesignStudio::projectData) {
         qDebug() << "Project is expected";
         emit projectIncoming();
diff --git a/src/backend/dsconnector/ds.h b/src/backend/dsconnector/ds.h
index bb461375465952fee1e10926be92c746aba2795f..a4cc12aa406e899044ee64196001032e0207a090 100644
--- a/src/backend/dsconnector/ds.h
+++ b/src/backend/dsconnector/ds.h
@@ -25,21 +25,13 @@
 
 #pragma once
 
-#include <QObject>
+#include <QJsonValue>
 #include <QTimer>
 #include <QWebSocket>
-#include <qjsonvalue.h>
-#include <qlatin1stringview.h>
-
-#include <QLatin1String>
 
 namespace PackageFromDesignStudio {
 using namespace Qt::Literals;
 constexpr auto designStudioReady = "designStudioReady"_L1;
-constexpr auto pinRequested = "pinRequested"_L1;
-constexpr auto pinFailed = "pinVerificationFailed"_L1;
-constexpr auto deviceIdDeclined = "deviceIdDeclined"_L1;
-constexpr auto deviceIdAccepted = "deviceIdAccepted"_L1;
 constexpr auto projectData = "projectData"_L1;
 constexpr auto stopRunningProject = "stopRunningProject"_L1;
 }; // namespace PackageFromDesignStudio
@@ -47,7 +39,6 @@ constexpr auto stopRunningProject = "stopRunningProject"_L1;
 namespace PackageToDesignStudio {
 using namespace Qt::Literals;
 constexpr auto deviceInfo = "deviceInfo"_L1;
-constexpr auto pairingPin = "registrationPinResponse"_L1;
 constexpr auto projectRunning = "projectRunning"_L1;
 constexpr auto projectStopped = "projectStopped"_L1;
 constexpr auto projectLogs = "projectLogs"_L1;
@@ -61,25 +52,24 @@ public:
                  const quint16 port,
                  const QString &id = QString(),
                  const QString &deviceUuid = QString(),
-                 const bool skipPairing = false,
                  QObject *parent = nullptr);
 
+    // Socket ops
+    void connectToDesignStudio();
+    void disconnectFromDesignStudio();
+
     // Getters
     QString ipv4Addr() const;
     quint16 port() const;
     QString id() const;
     QUrl url() const;
-    bool skipPairing() const;
-    bool isPaired() const;
-    bool connected() const;
+    bool isConnected() const;
 
     // Setters
     void setIpAddress(const QString &ipv4Addr);
     void setDesignStudioId(const QString &designStudioId);
-    void setSkipPairing(const bool skipPairing);
 
     // Send data
-    void sendPairingPin(const QString &pin);
     void sendDeviceInfo();
     void sendProjectRunning();
     void sendProjectStopped();
@@ -99,10 +89,6 @@ private:
     QString m_id;
     QString m_deviceUuid;
 
-    // Pairing
-    bool m_paired = false;
-    bool m_skipPairing = false;
-
     // Settings
     constexpr static int m_reconnectTimeout = 5000;
 
@@ -120,13 +106,10 @@ private slots:
 signals:
     // socket signals
     void disconnected(const QString &id);
+    void connected(const QString &id);
 
     // DS signals
-    void idChanged(const QString &id, const QString &ipv4Addr);
-    void pinRequested(const QString &id);
-    void pinFailed(const QString &id);
-    void paired(const QString &id);
-    void unpaired(const QString &id);
+    void idReceived(const QString &id, const QString &ipv4Addr);
 
     void projectIncoming();
     void projectReceived(const QString &id, const QByteArray &data);
diff --git a/src/backend/dsconnector/dsdiscovery.cpp b/src/backend/dsconnector/dsdiscovery.cpp
index 9c0fcc5e65c5db6b0cdf2c48aef6d0a8c43c01ab..09c7c6c03794ee4de619ccb4f72561e2320dc676 100644
--- a/src/backend/dsconnector/dsdiscovery.cpp
+++ b/src/backend/dsconnector/dsdiscovery.cpp
@@ -31,7 +31,6 @@
 #include <QJsonDocument>
 #include <QJsonObject>
 #include <QJsonParseError>
-#include <qjsondocument.h>
 
 DesignStudioDiscovery::DesignStudioDiscovery(QObject *parent)
     : QObject(parent)
diff --git a/src/backend/dsconnector/dsdiscovery.h b/src/backend/dsconnector/dsdiscovery.h
index 9ddedaca3e4f35be65351acb8365147f987e1992..f3756c6d8f1944a70554139a76fd11d4cea0accf 100644
--- a/src/backend/dsconnector/dsdiscovery.h
+++ b/src/backend/dsconnector/dsdiscovery.h
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include <QObject>
 #include <QUdpSocket>
 
 class DesignStudioDiscovery : public QObject
@@ -38,9 +37,7 @@ private slots:
     void onReadyRead();
 
 signals:
-    void designStudioFound(const QString &ipv4Addr,
-                           const QString &id,
-                           const bool skipPairing = false);
+    void designStudioFound(const QString &ipv4Addr, const QString &id);
 
 private:
     QUdpSocket m_udpSocket;
diff --git a/src/backend/dsconnector/dsmanager.cpp b/src/backend/dsconnector/dsmanager.cpp
index 9f753b230df7acdb3dd7acf35002c427bc796b9b..777b85c8282b7faa68e03710deb48ba08886f7e2 100644
--- a/src/backend/dsconnector/dsmanager.cpp
+++ b/src/backend/dsconnector/dsmanager.cpp
@@ -24,30 +24,36 @@
 ****************************************************************************/
 
 #include "dsmanager.h"
-#include "../constants.h"
 #include "backend/dsconnector/ds.h"
-#include <memory>
 
 #include <QFile>
 #include <QJsonArray>
 #include <QJsonDocument>
 #include <QJsonObject>
-#include <QLoggingCategory>
-#include <QThread>
-#include <qdebug.h>
-#include <qjsonobject.h>
-#include <qobject.h>
+#include <QStandardPaths>
 
 DesignStudioManager::DesignStudioManager(QObject *parent,
                                          const bool enableDiscovery,
                                          const QString &deviceUuid)
     : QObject(parent)
     , m_deviceUuid(deviceUuid)
+    , m_enableDiscovery(enableDiscovery)
+    , m_settingsPath(
+          QStandardPaths::writableLocation(QStandardPaths::ConfigLocation).append("/dsmanager.json"))
+{}
+
+void DesignStudioManager::initialize()
 {
-    qDebug() << ">>> THREAD ID _ dsmanger:" << QThread::currentThreadId();
-    initializePairedDesignStudios();
+    static bool initialized = false;
+    if (initialized) {
+        return;
+    }
+    initialized = true;
 
-    if (enableDiscovery) {
+    initLastKnownDs();
+
+    qDebug() << "Device UUID:" << m_deviceUuid;
+    if (m_enableDiscovery) {
         qDebug() << "Starting Design Studio discovery";
         m_discovery = std::make_unique<DesignStudioDiscovery>();
         connect(m_discovery.get(),
@@ -55,14 +61,11 @@ DesignStudioManager::DesignStudioManager(QObject *parent,
                 this,
                 &DesignStudioManager::designStudioFound);
     }
-
-    qDebug() << "Design Studio Manager initialized";
-    qDebug() << "Thread id dsmanger:" << QThread::currentThreadId();
 }
 
-void DesignStudioManager::initializePairedDesignStudios()
+void DesignStudioManager::initLastKnownDs()
 {
-    QFile file(Constants::Paths::ConfigPathDsManager);
+    QFile file(m_settingsPath);
 
     if (!file.exists()) {
         qDebug() << "Settings file not found.";
@@ -82,78 +85,67 @@ void DesignStudioManager::initializePairedDesignStudios()
     QJsonArray dsArray = obj["designStudios"].toArray();
     for (const auto &ds : dsArray) {
         QJsonObject dsObj = ds.toObject();
-        initDesignStudio(dsObj["ipv4Addr"].toString(),
-                         dsObj["designStudioId"].toString(),
-                         dsObj["skipPairing"].toBool());
+        initDesignStudio(dsObj["ipv4Addr"].toString(), dsObj["designStudioId"].toString());
     }
 }
 
-void DesignStudioManager::initDesignStudio(const QString &ipv4Addr,
-                                           const QString &designStudioId,
-                                           const bool skipPairing)
+void DesignStudioManager::initDesignStudio(const QString &ipv4Addr, const QString &designStudioId)
 {
-    qDebug() << "Initializing Design Studio" << designStudioId << "with IPv4 address" << ipv4Addr;
-    auto ds
-        = std::make_unique<DesignStudio>(ipv4Addr, 40000, designStudioId, m_deviceUuid, skipPairing);
+    if (m_designStudio) {
+        if (m_designStudio->ipv4Addr() == ipv4Addr && m_designStudio->isConnected()) {
+            qDebug() << "Design Studio" << ipv4Addr << "is already connected";
+            return;
+        }
+    }
 
-    connect(ds.get(), &DesignStudio::paired, this, &DesignStudioManager::designStudioPaired);
+    emit designStudioDisconnected(designStudioId, ipv4Addr);
 
-    connect(ds.get(), &DesignStudio::unpaired, this, &DesignStudioManager::designStudioUnpaired);
+    qDebug() << "Initializing Design Studio" << designStudioId << "with IPv4 address" << ipv4Addr;
+    m_designStudio.reset(new DesignStudio(ipv4Addr, 40000, designStudioId, m_deviceUuid));
 
-    connect(ds.get(), &DesignStudio::pinRequested, this, &DesignStudioManager::pairingPinRequested);
+    connect(m_designStudio.get(),
+            &DesignStudio::idReceived,
+            this,
+            [this](const QString &, const QString &) { updateConfigFile(); });
 
-    connect(ds.get(), &DesignStudio::idChanged, this, &DesignStudioManager::dsIdChanged);
+    connect(m_designStudio.get(),
+            &DesignStudio::projectReceived,
+            this,
+            &DesignStudioManager::projectReceived);
 
-    connect(ds.get(), &DesignStudio::projectReceived, this, &DesignStudioManager::projectReceived);
+    connect(m_designStudio.get(), &DesignStudio::connected, this, [this](const QString &id) {
+        emit designStudioConnected(id, m_designStudio->ipv4Addr());
+    });
 
-    connect(ds.get(), &DesignStudio::disconnected, this, &DesignStudioManager::dsDisconnected);
+    connect(m_designStudio.get(), &DesignStudio::disconnected, this, [this](const QString &id) {
+        emit designStudioDisconnected(id, m_designStudio->ipv4Addr());
+    });
 
-    connect(ds.get(),
+    connect(m_designStudio.get(),
             &DesignStudio::projectStopRequested,
             this,
             &DesignStudioManager::projectStopRequested);
 
-    m_designStudios.push_back(std::move(ds));
+    m_designStudio->connectToDesignStudio();
+    updateConfigFile();
 }
 
-void DesignStudioManager::designStudioFound(const QString &ipv4Addr,
-                                            const QString &id,
-                                            const bool skipPairing)
+void DesignStudioManager::designStudioFound(const QString &ipv4Addr, const QString &id)
 {
     qDebug() << "Design Studio found with IPv4 address" << ipv4Addr << "and ID" << id;
-    // check if the Design Studio is already in the list
 
-    for (const auto &ds : m_designStudios) {
-        if (ds->id() == id) {
-            if (ds->ipv4Addr() != ipv4Addr) {
-                qDebug() << "Design Studio" << id << "changed IP address from" << ds->ipv4Addr()
-                         << "to" << ipv4Addr;
-                ds->setIpAddress(ipv4Addr);
-                updateConfigFile();
-            } else {
-                qDebug() << "Design Studio" << id << "already in the list";
-            }
-            return;
-        }
-
-        if (ds->ipv4Addr() == ipv4Addr && ds->connected()) {
-            qDebug() << "Design Studio with IP address" << ipv4Addr << "already in the list with ID"
-                     << ds->id() << "and connected";
-            if (skipPairing) {
-                qDebug() << "Forcing pairing with Design Studio" << id;
-                ds->setSkipPairing(skipPairing);
-                ds->sendDeviceInfo();
-            }
-            return;
-        }
+    // check if the Design Studio is already in the list
+    if (m_designStudio->id() == id && m_designStudio->ipv4Addr() != ipv4Addr) {
+        qDebug() << "Design Studio" << id << "changed IP address from" << m_designStudio->ipv4Addr()
+                 << "to" << ipv4Addr;
+        m_designStudio->setIpAddress(ipv4Addr);
+        updateConfigFile();
     }
-
-    initDesignStudio(ipv4Addr, id, skipPairing);
 }
 
 void DesignStudioManager::updateConfigFile()
 {
-    QFile file(Constants::Paths::ConfigPathDsManager);
+    QFile file(m_settingsPath);
     if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
         qDebug() << "Failed to open settings file for writing";
         return;
@@ -161,155 +153,29 @@ void DesignStudioManager::updateConfigFile()
 
     QJsonObject rootObj;
     QJsonArray dsArray;
-
-    for (const auto &d : m_designStudios) {
-        if (!d->isPaired()) {
-            continue;
-        }
-
-        QJsonObject dsObj;
-        dsObj["ipv4Addr"] = d->ipv4Addr();
-        dsObj["id"] = d->id();
-        dsObj["skipPairing"] = d->skipPairing();
-        dsArray.append(dsObj);
-    }
+    dsArray.append(
+        QJsonObject{{"ipv4Addr", m_designStudio->ipv4Addr()}, {"id", m_designStudio->id()}});
 
     rootObj["designStudios"] = dsArray;
     file.write(QJsonDocument(rootObj).toJson());
 }
 
-void DesignStudioManager::dsIdChanged(const QString &id, const QString &ipv4Addr)
-{
-    /* that can happen because of the following reasons;
-        1. The IP address is pointing a different Design Studio (can happen because of DHCP or manual change)
-        2. The Design Studio changed its ID (can happen because of a reinstall)
-        3. Design Studio is initialized only with IP address and ID is received later
-    */
-
-    for (const auto &ds : m_designStudios) {
-        // case 1 and 3
-        if (ds->ipv4Addr() == ipv4Addr && ds->id() != id) {
-            qDebug() << "Design Studio" << id << "changed ID to" << id << "with IP address"
-                     << ipv4Addr;
-            ds->setDesignStudioId(id);
-            ds->sendDeviceInfo();
-            break;
-        }
-
-        // case 2
-        if (ds->id() == id) {
-            qDebug() << "Design Studio" << id << "changed IP address from" << ds->ipv4Addr() << "to"
-                     << ipv4Addr;
-
-            // if there's another DS with the same IP address, remove it
-            m_designStudios.erase(std::remove_if(m_designStudios.begin(),
-                                                 m_designStudios.end(),
-                                                 [&](const auto &d) {
-                                                     return d->ipv4Addr() == ipv4Addr;
-                                                 }),
-                                  m_designStudios.end());
-            ds->setIpAddress(ipv4Addr);
-            ds->sendDeviceInfo();
-            break;
-        }
-    }
-
-    updateConfigFile();
-}
-
-void DesignStudioManager::designStudioPaired(const QString &id)
-{
-    qDebug() << "Design Studio" << id << "paired. Updating settings.";
-    updateConfigFile();
-    auto ds = std::find_if(m_designStudios.begin(), m_designStudios.end(), [&](const auto &d) {
-        return d->id() == id;
-    });
-    if (ds == m_designStudios.end()) {
-        qCritical() << "Design Studio" << id << "not found in the list. Something went wrong.";
-        return;
-    }
-
-    if (!(*ds)->connected()) {
-        qWarning() << "Design Studio" << id
-                   << "is not connected. Not notifying UI about the connection update.";
-        return;
-    }
-
-    emit designStudioConnected(id, (*ds)->ipv4Addr());
-}
-
-void DesignStudioManager::designStudioUnpaired(const QString &id)
+void DesignStudioManager::sendProjectRunning(const QString &)
 {
-    qDebug() << "Design Studio" << id << "unpaired. Removing from settings.";
-    updateConfigFile();
-    auto ds = std::find_if(m_designStudios.begin(), m_designStudios.end(), [&](const auto &d) {
-        return d->id() == id;
-    });
-    if (ds == m_designStudios.end()) {
-        qCritical() << "Design Studio" << id << "not found in the list. Something went wrong.";
-        return;
-    }
-
-    emit designStudioDisconnected(id, (*ds)->ipv4Addr());
+    m_designStudio->sendProjectRunning();
 }
 
-void DesignStudioManager::enterPin(const QString &id, const QString &pin)
+void DesignStudioManager::sendProjectStopped(const QString &)
 {
-    DesignStudio *ds = nullptr;
-
-    for (const auto &d : m_designStudios) {
-        if (d->id() == id) {
-            ds = d.get();
-            break;
-        }
-    }
-
-    if (!ds) {
-        return;
-    }
-
-    ds->sendPairingPin(pin);
+    m_designStudio->sendProjectStopped();
 }
 
-void DesignStudioManager::dsDisconnected(const QString &id)
+void DesignStudioManager::sendProjectLogs(const QString &, const QString &logs)
 {
-    qDebug() << "Design Studio" << id << "disconnected";
-    auto ds = std::find_if(m_designStudios.begin(), m_designStudios.end(), [&](const auto &d) {
-        return d->id() == id;
-    });
-
-    if (!(*ds)->isPaired()) {
-        qDebug() << "Design Studio" << id
-                 << "is not paired. Not notifying UI about the disconnection.";
-        return;
-    }
-
-    emit designStudioDisconnected(id, (*ds)->ipv4Addr());
+    m_designStudio->sendProjectLogs(logs);
 }
 
-void DesignStudioManager::sendProjectRunning(const QString &id)
+QString DesignStudioManager::getDesignStudioIp(const QString &) const
 {
-    for (const auto &ds : m_designStudios) {
-        if (ds->id() == id) {
-            ds->sendProjectRunning();
-        }
-    }
-}
-
-void DesignStudioManager::sendProjectStopped(const QString &id)
-{
-    for (const auto &ds : m_designStudios) {
-        if (ds->id() == id) {
-            ds->sendProjectStopped();
-        }
-    }
-}
-
-void DesignStudioManager::sendProjectLogs(const QString &id, const QString &logs)
-{
-    for (const auto &ds : m_designStudios) {
-        if (ds->id() == id) {
-            ds->sendProjectLogs(logs);
-        }
-    }
+    return m_designStudio ? m_designStudio->ipv4Addr() : QString();
 }
diff --git a/src/backend/dsconnector/dsmanager.h b/src/backend/dsconnector/dsmanager.h
index 48bc17ca1a91a5c4c64337e9036777bf870842b4..913d3725e5613f3a0f33d77a3d3b90cffe366c8a 100644
--- a/src/backend/dsconnector/dsmanager.h
+++ b/src/backend/dsconnector/dsmanager.h
@@ -23,15 +23,12 @@
 **
 ****************************************************************************/
 
-#ifndef DSCONNECTOR_H
-#define DSCONNECTOR_H
+#pragma once
 
 #include <QObject>
-#include <qscopedpointer.h>
 
 #include "ds.h"
 #include "dsdiscovery.h"
-#include <memory>
 
 class DesignStudioManager : public QObject
 {
@@ -41,45 +38,35 @@ public:
                                  const bool enableDiscovery = false,
                                  const QString &deviceUuid = {});
 
+    void initialize();
+
 public slots:
     void sendProjectRunning(const QString &id);
     void sendProjectStopped(const QString &id);
     void sendProjectLogs(const QString &id, const QString &logs);
-
-    void enterPin(const QString &id, const QString &pin);
-    void designStudioFound(const QString &ipv4Addr,
-                           const QString &id = {},
-                           const bool skipPairing = false);
-
-private slots:
-    void designStudioPaired(const QString &id);
-    void designStudioUnpaired(const QString &id);
+    void initDesignStudio(const QString &ipv4Addr, const QString &designStudioId = {});
+    QString getDesignStudioIp(const QString &id) const;
 
 private:
     // Discovery object
     std::unique_ptr<DesignStudioDiscovery> m_discovery;
+    const bool m_enableDiscovery;
 
-    // Discovered Design Studio instances
-    std::vector<std::unique_ptr<DesignStudio>> m_designStudios;
+    // Active Design Studio. Only one can be active at a time.
+    std::unique_ptr<DesignStudio> m_designStudio;
 
     // other members
     const QString m_deviceUuid;
+    const QString m_settingsPath;
 
-    void dsIdChanged(const QString &id, const QString &ipv4Addr);
-    void initializePairedDesignStudios();
-    void initDesignStudio(const QString &ipv4Addr,
-                          const QString &designStudioId = {},
-                          const bool skipPairing = false);
-    void dsDisconnected(const QString &id);
-
+    void initLastKnownDs();
     void updateConfigFile();
+    void dsIdReceived(const QString &id, const QString &ipv4Addr);
+    void designStudioFound(const QString &ipv4Addr, const QString &id);
 
 signals:
-    void pairingPinRequested(const QString &id);
     void projectReceived(const QString &id, const QByteArray &project);
     void designStudioConnected(const QString &id, const QString &ipAddr);
     void designStudioDisconnected(const QString &id, const QString &ipAddr);
     void projectStopRequested(const QString &id);
 };
-
-#endif // DSCONNECTOR_H
diff --git a/src/backend/logger.h b/src/backend/logger.h
index 23efa645ee64e7a3dc730478e450d59ab9f6af3f..6c233f790f0bf9fff3d64a629f36aa17a1be85d4 100644
--- a/src/backend/logger.h
+++ b/src/backend/logger.h
@@ -26,7 +26,6 @@
 #pragma once
 
 #include <QMessageBox>
-#include <QObject>
 
 #include <android/log.h>
 
diff --git a/src/backend/main.cpp b/src/backend/main.cpp
index 734d47148673a8830c1b135828ed282fe74318bf..21412496fcfd933e3bcad1df57142253396627ba 100644
--- a/src/backend/main.cpp
+++ b/src/backend/main.cpp
@@ -27,13 +27,13 @@
 
 #include <QApplication>
 #include <QQmlContext>
+#include <QQmlEngine>
 
 #include "backend.h"
 #include "logger.h"
 
 int main(int argc, char *argv[])
 {
-    // qInstallMessageHandler(messageHandler);
     Logger::instance();
 
     qDebug() << "Starting Qt Design Viewer";
diff --git a/src/backend/projectmanager.cpp b/src/backend/projectmanager.cpp
index a70c9032223bf098207ef3317af91fd266e19334..3aee233eaae5bc6c888586f3c296dd9f29286d49 100644
--- a/src/backend/projectmanager.cpp
+++ b/src/backend/projectmanager.cpp
@@ -26,53 +26,26 @@
 #include "projectmanager.h"
 
 #include <QBuffer>
-#include <QDir>
 #include <QDirIterator>
-#include <QEventLoop>
-#include <QFile>
-#include <QFileInfo>
-#include <QGuiApplication>
-#include <QJsonDocument>
+#include <QQmlEngine>
 #include <QQuickItem>
 #include <QRandomGenerator>
 #include <QRegularExpression>
 #include <QResource>
-#include <QSettings>
 #include <QTemporaryDir>
-#include <QTemporaryFile>
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
 #include <QtCore/private/qzipreader_p.h>
-#else
-#include <QtGui/private/qzipreader_p.h>
-#endif
-
-#include "constants.h"
 
 ProjectManager::ProjectManager(QObject *parent, bool autoScaleProject)
     : QObject(parent)
     , m_autoScaleProject(autoScaleProject)
 {
-    qDebug() << "ProjectManager created.";
-    qDebug() << "Project cache path: " << Constants::Paths::ProjectCachePath;
-    qDebug() << "Demo project cache path: " << Constants::Paths::DemoProjectsPath;
-    qDebug() << "Auto scale project: " << m_autoScaleProject;
-
-    if (!QDir(Constants::Paths::ProjectCachePath).exists()) {
-        qDebug() << "Creating project cache path: " << Constants::Paths::ProjectCachePath;
-        QDir().mkpath(Constants::Paths::ProjectCachePath);
-    }
-
-    if (!QDir(Constants::Paths::DemoProjectsPath).exists()) {
-        qDebug() << "Creating demo project cache path: " << Constants::Paths::DemoProjectsPath;
-        QDir().mkpath(Constants::Paths::DemoProjectsPath);
-    }
+    qDebug() << "ProjectManager created. Auto scale project: " << m_autoScaleProject;
 }
 
 ProjectManager::~ProjectManager()
 {
+    qDebug() << "ProjectManager destroyed. Cleaning up resources.";
     cleanupResources();
-    qDebug() << "ProjectManager destroyed.";
 }
 
 void ProjectManager::cleanupResources()
@@ -109,7 +82,7 @@ QString ProjectManager::unpackProject(const QByteArray &project, bool extractZip
     // maybe it was not a zip file so try it as resource binary
     if (projectPathDir.isEmpty()) {
         if (extractZip)
-            qDebug("File could not be extracted. Trying to open it as a resource file.");
+            qWarning("File could not be extracted. Trying to open it as a resource file.");
 
         cleanupResources();
 
@@ -122,7 +95,7 @@ QString ProjectManager::unpackProject(const QByteArray &project, bool extractZip
         m_projectPath = resourcePath;
 
         if (!QDir(resourcePath).removeRecursively()) {
-            qDebug() << "Could not remove resource path: " << resourcePath;
+            qWarning() << "Could not remove resource path: " << resourcePath;
         }
 
         if (!QResource::registerResource(data, resourcePath)) {
@@ -305,228 +278,6 @@ bool ProjectManager::runProject(const QString &projectPath)
     return true;
 }
 
-bool ProjectManager::cacheProject(const QByteArray &projectData, const QJsonObject &projectInfo)
-{
-    // sample project info
-    /*
-     {
-        "appName": "Testmcu",
-        "id": "0sadf8fa9s8df67s8998690a7sdf",
-        "owner": "",
-        "passwordHash": "",
-        "qdsIsEnterprise": true,
-        "qdsVersion": "Qt Design Studio 4.2.0",
-        "ttlDays": 31,
-        "uploadTime": "2023-10-27T13:57:22",
-        "userHash": "12038740912873462987"
-      },
-    */
-
-    const QString projectId = projectInfo.value("id").toString();
-
-    qDebug() << "Caching project " << projectId << " with last modified "
-             << projectInfo.value("uploadTime");
-    const QString cachePath = Constants::Paths::ProjectCachePath + "/" + projectId;
-
-    // remove old cache
-    if (QDir(cachePath).exists()) {
-        qDebug() << "Removing old cache for project " << projectId;
-        if (!QDir(cachePath).removeRecursively()) {
-            qCritical() << "Could not remove old cache for project " << projectId;
-            return false;
-        }
-    }
-
-    QDir().mkpath(cachePath);
-    const QString tempProjectPath = unpackProject(projectData);
-
-    // copy all files from tempProjectPath to cachePath
-    QDirIterator it(tempProjectPath, QDirIterator::Subdirectories);
-    while (it.hasNext()) {
-        it.next();
-        const QString filePath = it.filePath();
-        const QString relativeFilePath = filePath.mid(tempProjectPath.length());
-        const QString newFilePath = cachePath + relativeFilePath;
-
-        if (QFileInfo(filePath).isDir()) {
-            QDir().mkpath(newFilePath);
-        } else {
-            QFile::copy(filePath, newFilePath);
-        }
-    }
-
-    // write project info to cache
-    QFile lastModifiedFile(cachePath + "/projectInfo.json");
-    if (!lastModifiedFile.open(QIODevice::WriteOnly)) {
-        qCritical() << "Could not open projectInfo file for writing";
-        return false;
-    }
-
-    lastModifiedFile.write(QJsonDocument(projectInfo).toJson());
-    return true;
-}
-
-bool ProjectManager::isProjectCached(const QJsonObject &projectInfo)
-{
-    const QString projectId = projectInfo.value("id").toString();
-    const QString lastModified = projectInfo.value("uploadTime").toString();
-
-    qDebug() << "Checking if project " << projectId << " is cached";
-    const QString cachePath = Constants::Paths::ProjectCachePath + "/" + projectId;
-    if (!QDir(cachePath).exists()) {
-        qDebug() << "Project " << projectId << " is not cached";
-        return false;
-    }
-
-    qDebug() << "Project " << projectId << " is cached. Checking if it is up to date";
-    QFile lastModifiedFile(cachePath + "/projectInfo.json");
-    if (!lastModifiedFile.open(QIODevice::ReadOnly)) {
-        qCritical() << "Could not open projectInfo file for reading";
-        return false;
-    }
-
-    const QJsonObject cachedProjectInfo
-        = QJsonDocument::fromJson(lastModifiedFile.readAll()).object();
-    const QString cachedLastModified = cachedProjectInfo.value("uploadTime").toString();
-
-    qDebug() << "Project " << projectId << " last modified: " << lastModified;
-    qDebug() << "Cached project " << projectId << " last modified: " << cachedLastModified;
-
-    if (lastModified != cachedLastModified) {
-        qDebug() << "Project " << projectId << " is not up to date";
-        return false;
-    }
-
-    qDebug() << "Project " << projectId << " is up to date";
-    return true;
-}
-
-void ProjectManager::clearCachedProject(const QJsonObject &projectInfo)
-{
-    const QString projectId = projectInfo.value("id").toString();
-    qDebug() << "Clearing cache for project " << projectId;
-
-    const QString cachePath = Constants::Paths::ProjectCachePath + "/" + projectId;
-    if (!QDir(cachePath).exists()) {
-        qDebug() << "Project " << projectId << " is not cached";
-    }
-
-    qDebug() << "Removing cache for project " << projectId;
-    QDir(cachePath).removeRecursively();
-}
-
-bool ProjectManager::runCachedProject(const QJsonObject &projectInfo)
-{
-    const QString projectId = projectInfo.value("id").toString();
-    qDebug() << "Running cached project " << projectId;
-
-    const QString projectPath = Constants::Paths::ProjectCachePath + "/" + projectId;
-    return runProject(projectPath);
-}
-
-bool ProjectManager::cacheDemoProject(const QByteArray &projectData, const QJsonObject &projectInfo)
-{
-    // sample project info
-    //[{"lastUpdate":1701947766739.9812,"name":"ClusterTutorial.qmlrc"}]
-    const QString projectName = projectInfo.value("name").toString().remove(".qmlrc");
-    const QString demoProjectPath = Constants::Paths::DemoProjectsPath + "/" + projectName;
-    qDebug() << "Caching demo project " << projectName << " to " << demoProjectPath;
-
-    // remove old cache
-    if (QDir(demoProjectPath).exists()) {
-        qDebug() << "Removing old cache for demo project " << projectName;
-        if (!QDir(demoProjectPath).removeRecursively()) {
-            qCritical() << "Could not remove old cache for demo project " << projectName;
-            return false;
-        }
-    }
-
-    // create new cache
-    if (!QDir().mkpath(demoProjectPath)) {
-        qCritical() << "Could not create new cache for demo project " << projectName;
-        return false;
-    }
-
-    const QString tempProjectPath = unpackProject(projectData);
-
-    // copy all files from tempProjectPath to demoProjectPath
-    QDirIterator it(tempProjectPath, QDirIterator::Subdirectories);
-    while (it.hasNext()) {
-        it.next();
-        const QString filePath = it.filePath();
-        const QString relativeFilePath = filePath.mid(tempProjectPath.length());
-        const QString newFilePath = demoProjectPath + relativeFilePath;
-
-        if (QFileInfo(filePath).isDir()) {
-            QDir().mkpath(newFilePath);
-        } else if (!QFile::copy(filePath, newFilePath)) {
-            qCritical() << "Could not copy " << filePath << " to " << newFilePath;
-            return false;
-        }
-    }
-
-    // write project info to cache
-    QFile demoProjectInfoFile(demoProjectPath + "/projectInfo.json");
-    if (!demoProjectInfoFile.open(QIODevice::WriteOnly)) {
-        qCritical() << "Could not open demo project info file for writing";
-        return false;
-    }
-
-    demoProjectInfoFile.write(QJsonDocument(projectInfo).toJson());
-    return true;
-}
-
-void ProjectManager::clearDemoCaches()
-{
-    qDebug() << "Clearing demo caches:" << Constants::Paths::DemoProjectsPath;
-    QDir(Constants::Paths::DemoProjectsPath).removeRecursively();
-}
-
-bool ProjectManager::isDemoProjectCached(const QJsonObject &projectInfo)
-{
-    // sample project info
-    //[{"lastUpdate":1701947766739.9812,"name":"ClusterTutorial.qmlrc"}]
-    const QString projectName = projectInfo.value("name").toString().remove(".qmlrc");
-    const QString demoProjectPath = Constants::Paths::DemoProjectsPath + "/" + projectName;
-    qDebug() << "Checking if demo project " << projectName << " is cached";
-
-    if (!QDir(demoProjectPath).exists()) {
-        qDebug() << "Demo project " << projectName << " is not cached";
-        return false;
-    }
-
-    qDebug() << "Demo project " << projectName << " is cached. Checking the last update time...";
-    const QString demoProjectInfoPath = demoProjectPath + "/projectInfo.json";
-    QFile demoProjectInfoFile(demoProjectInfoPath);
-    if (!demoProjectInfoFile.open(QIODevice::ReadOnly)) {
-        qCritical() << "Could not open demo project info file for reading";
-        return false;
-    }
-
-    const QJsonObject cachedProjectInfo
-        = QJsonDocument::fromJson(demoProjectInfoFile.readAll()).object();
-
-    const QJsonValue cachedLastModified = cachedProjectInfo.value("lastUpdate");
-    const QJsonValue cloudLastModified = projectInfo.value("lastUpdate");
-    qDebug() << "Demo project" << projectName << "cloud timestamp: " << cloudLastModified
-             << "local timestamp:" << cachedLastModified;
-
-    if (cloudLastModified != cachedLastModified) {
-        qDebug() << "Demo project " << projectName << " is not up to date";
-        return false;
-    }
-
-    qDebug() << "Demo project " << projectName << " is up to date";
-    return true;
-}
-
-bool ProjectManager::runDemoProject(const QString &projectName)
-{
-    const QString demoProjectPath = Constants::Paths::DemoProjectsPath + "/" + projectName;
-    qDebug() << "Running demo project " << projectName << " from " << demoProjectPath;
-    return runProject(demoProjectPath);
-}
-
 void ProjectManager::orientateWindow(Qt::ScreenOrientation orientation)
 {
     if (!m_autoScaleProject)
diff --git a/src/backend/projectmanager.h b/src/backend/projectmanager.h
index 4767ce4a92d0208a51ecf1319496229f2a234892..6a1a746a78a5291a96a690c53f373bbb88b48cdf 100644
--- a/src/backend/projectmanager.h
+++ b/src/backend/projectmanager.h
@@ -23,15 +23,9 @@
 **
 ****************************************************************************/
 
-#ifndef PROJECTMANAGER_H
-#define PROJECTMANAGER_H
+#pragma once
 
-#include <QJsonObject>
-#include <QObject>
-#include <QQmlComponent>
-#include <QQmlEngine>
 #include <QQuickView>
-#include <QQuickWindow>
 
 class ProjectManager : public QObject
 {
@@ -44,16 +38,6 @@ public:
     bool runProject(const QString &projectPath);
     void stopProject();
 
-    bool cacheProject(const QByteArray &projectData, const QJsonObject &projectInfo);
-    bool isProjectCached(const QJsonObject &projectInfo);
-    bool runCachedProject(const QJsonObject &projectInfo);
-    void clearCachedProject(const QJsonObject &projectInfo);
-
-    bool cacheDemoProject(const QByteArray &projectData, const QJsonObject &projectInfo);
-    bool isDemoProjectCached(const QJsonObject &projectName);
-    bool runDemoProject(const QString &projectName);
-    void clearDemoCaches();
-
     void showAppWindow();
     void hideAppWindow();
 
@@ -70,7 +54,6 @@ private:
     QScopedPointer<QQmlEngine> m_qmlEngine;
     QScopedPointer<QQmlComponent> m_qmlComponent;
     QScopedPointer<QQuickWindow> m_quickWindow;
-    QJSValue m_consoleObject;
 
     // Member functions
     QString findFile(const QString &dir, const QString &filter);
@@ -80,11 +63,8 @@ private:
     bool isQt6Project(const QString &qmlProjectFileContent);
 
     void parseQmlProjectFile(const QString &fileName, QString *mainFile, QStringList *importPaths);
-    void cacheProject(const QString &projectName, const QString &projectPath);
     void cleanupResources();
 
 signals:
     void closingProject();
 };
-
-#endif // PROJECTMANAGER_H
diff --git a/src/backend/qrscanner.cpp b/src/backend/qrscanner.cpp
index 7d26ae28cdd24513b47ef67f72529599dfca3efd..3c507e45b35ea4999d3f4a23747ff83438584185 100644
--- a/src/backend/qrscanner.cpp
+++ b/src/backend/qrscanner.cpp
@@ -28,7 +28,6 @@
 #include <QApplication>
 #include <QCamera>
 #include <QCameraDevice>
-#include <QElapsedTimer>
 #include <QImageCapture>
 #include <QMediaDevices>
 #include <QMessageBox>
diff --git a/src/backend/serviceconnector.cpp b/src/backend/serviceconnector.cpp
deleted file mode 100644
index f8314f21ac7005f1293b6f63f632f831536e6f7b..0000000000000000000000000000000000000000
--- a/src/backend/serviceconnector.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2023 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "serviceconnector.h"
-
-#include <QNetworkAccessManager>
-#include <QNetworkReply>
-#include <QEventLoop>
-#include <QJsonDocument>
-#include <QJsonObject>
-
-std::optional<QByteArray> ServiceConnector::fetchResource(const QString &url, const QString &auth)
-{
-    qDebug() << "Fetching resource from" << url;
-
-    QNetworkRequest request(url);
-    request.setRawHeader("Authorization", auth.toUtf8());
-    QSharedPointer<QNetworkReply> reply(m_manager.get(request));
-    QObject::connect(reply.data(),
-                     &QNetworkReply::sslErrors,
-                     this,
-                     [&](const QList<QSslError> &errors) {
-                         qWarning() << errors.first().errorString();
-                     });
-
-    QEventLoop loop;
-    QObject::connect(this, &ServiceConnector::interrupted, reply.data(), [&]() {
-        qDebug() << "Aborting network request";
-        reply->abort();
-        loop.quit();
-    });
-    QObject::connect(reply.data(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
-    QObject::connect(reply.data(),
-                     &QNetworkReply::downloadProgress,
-                     this,
-                     [&](qint64 bytesReceived, qint64 bytesTotal) {
-                         float percentage = roundf((float) bytesReceived / (float) bytesTotal * 100);
-                         qDebug() << "Download progress" << QString::number(percentage) << "% -"
-                                  << QString::number(bytesReceived) << "/"
-                                  << QString::number(bytesTotal);
-                         emit downloadProgress(percentage);
-                     });
-    loop.exec();
-
-    if (reply->error() != QNetworkReply::NoError) {
-        qWarning() << reply->errorString();
-        return {};
-    }
-
-    qDebug() << "Resource fetched successfully";
-    return reply->readAll();
-}
-
-std::optional<QByteArray> ServiceConnector::fetchProject(const QString &url)
-{
-    QString projectUrl = url;
-    if (projectUrl.startsWith(m_serviceUrl + "/#")) {
-        projectUrl = projectUrl.split("#").at(1);
-        projectUrl.prepend(m_serviceUrl + "/qmlprojects/");
-    }
-
-    return fetchResource(projectUrl);
-}
-
-std::optional<QByteArray> ServiceConnector::fetchUserProject(const QString &userHash,
-                                                             const QString &projectName,
-                                                             const QString &password)
-{
-    const QString projectUrl = m_serviceUrl + "/qmlprojects/" + userHash + "/" + projectName
-                               + ".qmlrc";
-
-    return fetchResource(projectUrl, password);
-}
-
-std::optional<QJsonArray> ServiceConnector::fetchUserProjectList(const QString &userHash)
-{
-    auto reply = fetchResource(m_serviceUrl + "/api/v1/qmlrc/list/" + userHash + "?key=818815");
-
-    if (!reply)
-        return {};
-
-    QJsonArray projectList = QJsonDocument::fromJson(reply.value())
-                                 .object()
-                                 .value("data")
-                                 .toObject()
-                                 .value("packages")
-                                 .toArray();
-
-    return projectList;
-}
-
-std::optional<QJsonArray> ServiceConnector::fetchDemoList()
-{
-    auto reply = fetchResource(m_serviceUrl + "/api/v1/demos");
-    if (!reply)
-        return {};
-
-    return QJsonDocument::fromJson(reply.value()).array();
-}
-
-std::optional<QByteArray> ServiceConnector::fetchDemo(const QString &demoName)
-{
-    return fetchResource(m_serviceUrl + "/qmlprojects/demos/" + demoName + ".qmlrc");
-}
diff --git a/src/backend/serviceconnector.h b/src/backend/serviceconnector.h
deleted file mode 100644
index 9d5d4f50e8c521c4f46eda06d49b2c04ff2deb9b..0000000000000000000000000000000000000000
--- a/src/backend/serviceconnector.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2023 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#ifndef SERVICECONNECTOR_H
-#define SERVICECONNECTOR_H
-
-#include <QNetworkAccessManager>
-#include <QJsonArray>
-
-class ServiceConnector : public QObject
-{
-    Q_OBJECT
-public:
-    std::optional<QByteArray> fetchProject(const QString &url);
-    std::optional<QByteArray> fetchUserProject(const QString &userHash,
-                                               const QString &projectName,
-                                               const QString &password);
-    std::optional<QJsonArray> fetchUserProjectList(const QString &userHash);
-    std::optional<QJsonArray> fetchDemoList();
-    std::optional<QByteArray> fetchDemo(const QString &demoName);
-
-private:
-    QNetworkAccessManager m_manager;
-    std::optional<QByteArray> fetchResource(const QString &url, const QString &auth = "");
-
-    const QString m_serviceUrl = "https://designviewer.qt.io";
-
-signals:
-    void downloadProgress(float percentage);
-    void interrupted();
-};
-
-#endif // SERVICECONNECTOR_H
diff --git a/src/backend/settings.cpp b/src/backend/settings.cpp
index 73299cdd54d926e59df0be102f85cdc393293c59..3dfedfdf91e022a7845dfa631d02133882efaee4 100644
--- a/src/backend/settings.cpp
+++ b/src/backend/settings.cpp
@@ -29,54 +29,58 @@
 #include <QJsonDocument>
 #include <QStandardPaths>
 
-#include "constants.h"
-
 /*
     Example of a settings.json file:
     {
         "autoScale": true
-        "userHash": "1234567890",
         "deviceUuid": "1234567890"
     }
 */
 
 Settings::Settings()
-    : m_settingsPath(Constants::Paths::ConfigPathSettings)
+    : m_settingsPath(
+        QStandardPaths::writableLocation(QStandardPaths::ConfigLocation).append("/settings.json"))
 {
     qDebug() << "Settings path:" << m_settingsPath;
-    loadSettings();
+    if (!loadSettings()) {
+        qDebug() << "Failed to load settings. Applying default ones.";
+        applyDefaultSettings();
+    }
+}
+
+void Settings::applyDefaultSettings()
+{
+    m_settings["autoScale"] = true;
+    m_settings["deviceUuid"] = "";
+    saveSettings();
 }
 
-void Settings::loadSettings()
+bool Settings::loadSettings()
 {
     QFile file(m_settingsPath);
-    if (file.open(QIODevice::ReadOnly)) {
-        QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
-        m_settings = doc.object();
-        return;
+    if (!file.open(QIODevice::ReadOnly)) {
+        qWarning() << "Failed to open settings file" << m_settingsPath
+                   << "Reason:" << file.errorString();
+        return false;
     }
 
-    qWarning() << "Failed to load settings from" << m_settingsPath;
-    m_settings.insert("projectManager", QJsonObject{{"autoScale", true}});
-    m_settings.insert("backend", QJsonObject{{"userHash", ""}, {"deviceUuid", ""}});
-
-    if (!file.exists()) {
-        qDebug() << "Settings file not found. Creating a new one.";
-        saveSettings();
-    }
+    QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
+    m_settings = doc.object();
+    return true;
 }
 
 bool Settings::saveSettings()
 {
     QFile file(m_settingsPath);
-    if (file.open(QIODevice::WriteOnly)) {
-        QJsonDocument doc(m_settings);
-        file.write(doc.toJson());
-        return true;
+    if (!file.open(QIODevice::WriteOnly)) {
+        qWarning() << "Failed to save settings to" << m_settingsPath
+                   << "Reason:" << file.errorString();
+        return false;
     }
 
-    qWarning() << "Failed to save settings to" << m_settingsPath;
-    return false;
+    QJsonDocument doc(m_settings);
+    file.write(doc.toJson());
+    return true;
 }
 
 void Settings::setAutoScaleProject(const bool &enabled)
@@ -85,29 +89,18 @@ void Settings::setAutoScaleProject(const bool &enabled)
     saveSettings();
 }
 
-void Settings::setUserHash(const QString &userHash)
-{
-    m_settings["userHash"] = userHash;
-    saveSettings();
-}
-
 void Settings::setDeviceUuid(const QString &deviceUuid)
 {
     m_settings["deviceUuid"] = deviceUuid;
     saveSettings();
 }
 
-QString Settings::userHash()
-{
-    return m_settings["userHash"].toString();
-}
-
-QString Settings::deviceUuid()
+QString Settings::deviceUuid() const
 {
     return m_settings["deviceUuid"].toString();
 }
 
-bool Settings::autoScaleProject()
+bool Settings::autoScaleProject() const
 {
     return m_settings["autoScale"].toBool();
 }
diff --git a/src/backend/settings.h b/src/backend/settings.h
index 1a122b0a78d27e63a0ede9e6b25b8bf386ecd684..96f034f7282162138392fd845ce63ede1391fd54 100644
--- a/src/backend/settings.h
+++ b/src/backend/settings.h
@@ -32,17 +32,16 @@ public:
     Settings();
 
     void setAutoScaleProject(const bool &enabled);
-    void setUserHash(const QString &userHash);
     void setDeviceUuid(const QString &deviceUuid);
 
-    bool autoScaleProject();
-    QString userHash();
-    QString deviceUuid();
+    bool autoScaleProject() const;
+    QString deviceUuid() const;
 
 private:
     QJsonObject m_settings;
     const QString m_settingsPath;
 
-    void loadSettings();
+    bool loadSettings();
     bool saveSettings();
+    void applyDefaultSettings();
 };
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d76888cff0b04461b549068d7d7dc1edf31590f3..b006a33edf751180bfff00a94840d7afa4b98016 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -4,11 +4,9 @@ find_package(Qt6 REQUIRED COMPONENTS Test Core Quick Gui Multimedia WebSockets)
 
 enable_testing(true)
 qt_add_executable(${TARGET_NAME}
-    tst_projectmanager.cpp tst_projectmanager.h
-    tst_serviceconnector.cpp tst_serviceconnector.h
     tst_designstudio.cpp tst_designstudio.h
     tst_dsdiscovery.cpp tst_dsdiscovery.h
-    tst_dsmanager.cpp tst_dsmanager.h
+    tst_settings.cpp tst_settings.h
     mock.h
     main.cpp
 )
diff --git a/tests/main.cpp b/tests/main.cpp
index e991d917f12093112202e0debb16bd0ab17486c7..2947812ec70544b6513edb409f07beaf53356d2d 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -29,8 +29,7 @@
 
 #include "tst_designstudio.h"
 #include "tst_dsdiscovery.h"
-#include "tst_projectmanager.h"
-#include "tst_serviceconnector.h"
+#include "tst_settings.h"
 
 #define DEBUG_LINE qDebug() << "Debugline:" << __LINE__
 
@@ -91,10 +90,9 @@ int main(int argc, char *argv[])
     outputFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
     outputFile.write("<testsuites>\n");
 
-    runTest(new TestServiceConnector);
-    runTest(new TestProjectManager);
     runTest(new TestDesignStudio);
     runTest(new TestDesignStudioDiscovery);
+    runTest(new TestSettings);
 
     outputFile.write("</testsuites>\n");
 
diff --git a/tests/tst_designstudio.cpp b/tests/tst_designstudio.cpp
index e36bfc7b136897c929aa4c78ac3e140e046e8639..5e71c26239ded7523090eed901e547f1bd55ff98 100644
--- a/tests/tst_designstudio.cpp
+++ b/tests/tst_designstudio.cpp
@@ -70,13 +70,6 @@ void TestDesignStudio::testUrl()
     QCOMPARE(ds->url(), QUrl("ws://localhost:40000"));
 }
 
-void TestDesignStudio::testSkipPairing()
-{
-    QVERIFY(!ds->skipPairing());
-    ds->setSkipPairing(true);
-    QVERIFY(ds->skipPairing());
-}
-
 void TestDesignStudio::testConnected()
 {
     QHostAddress addr = QHostAddress::LocalHost;
@@ -84,36 +77,33 @@ void TestDesignStudio::testConnected()
     QVERIFY(server.listen(addr, 40001));
 
     DesignStudio ds(addr.toString(), 40001, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
 }
 
-void TestDesignStudio::testSendRegistrationPin()
+void TestDesignStudio::testConnect()
 {
+    QHostAddress addr = QHostAddress::LocalHost;
     QWebSocketServer server("TestDesignStudio", QWebSocketServer::NonSecureMode);
-    QVERIFY(server.listen(QHostAddress::LocalHost, 40002));
-
-    DesignStudio ds("localhost", 40002, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
-
-    QWebSocket *socket = server.nextPendingConnection();
-    QVERIFY(socket != nullptr);
+    QVERIFY(server.listen(addr, 40002));
 
-    connect(socket, &QWebSocket::textMessageReceived, [](const QString &message) {
-        qDebug() << "Received message" << message;
+    DesignStudio ds(addr.toString(), 40002, "id", "deviceId");
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
+}
 
-        QJsonObject obj = QJsonDocument::fromJson(message.toUtf8()).object();
-        QVERIFY(obj.contains("dataType"));
-        QVERIFY(obj.contains("data"));
-        QVERIFY(obj.value("dataType").toString() == PackageToDesignStudio::pairingPin);
-        QVERIFY(obj.value("data").toString() == "1234");
-    });
+void TestDesignStudio::testDisconnect()
+{
+    QHostAddress addr = QHostAddress::LocalHost;
+    QWebSocketServer server("TestDesignStudio", QWebSocketServer::NonSecureMode);
+    QVERIFY(server.listen(addr, 40002));
 
-    QSignalSpy spy(socket, &QWebSocket::textMessageReceived);
-    QVERIFY(spy.isValid());
+    DesignStudio ds(addr.toString(), 40002, "id", "deviceId");
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
 
-    ds.sendPairingPin("1234");
-    QTRY_COMPARE(spy.count(), 1);
-    QTest::qWait(1000);
+    ds.disconnectFromDesignStudio();
+    QTRY_VERIFY(!ds.isConnected());
 }
 
 void TestDesignStudio::testSendDeviceInfo()
@@ -122,7 +112,8 @@ void TestDesignStudio::testSendDeviceInfo()
     QVERIFY(server.listen(QHostAddress::LocalHost, 40003));
 
     DesignStudio ds("localhost", 40003, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
 
     QWebSocket *socket = server.nextPendingConnection();
     QVERIFY(socket != nullptr);
@@ -154,87 +145,47 @@ void TestDesignStudio::testSendDeviceInfo()
     QTest::qWait(500);
 }
 
-void TestDesignStudio::testRegistrationPinRequestedSignal()
-{
-    QWebSocketServer server("TestDesignStudio", QWebSocketServer::NonSecureMode);
-    QVERIFY(server.listen(QHostAddress::LocalHost, 40005));
-
-    DesignStudio ds("localhost", 40005, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
-
-    QWebSocket *socket = server.nextPendingConnection();
-    QVERIFY(socket != nullptr);
-
-    QSignalSpy spy(&ds, &DesignStudio::pinRequested);
-    QVERIFY(spy.isValid());
-
-    const QJsonObject pinRequestedPackage = createPackage(PackageFromDesignStudio::pinRequested,
-                                                          "data");
-    socket->sendTextMessage(QJsonDocument(pinRequestedPackage).toJson(QJsonDocument::Compact));
-
-    QTRY_COMPARE(spy.count(), 1);
-}
-
-void TestDesignStudio::testPinVerificationFailedSignal()
+void TestDesignStudio::testConnectedSignal()
 {
     QWebSocketServer server("TestDesignStudio", QWebSocketServer::NonSecureMode);
-    QVERIFY(server.listen(QHostAddress::LocalHost, 40006));
-
-    DesignStudio ds("localhost", 40006, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
-
-    QWebSocket *socket = server.nextPendingConnection();
-    QVERIFY(socket != nullptr);
+    QVERIFY(server.listen(QHostAddress::LocalHost, 40010));
 
-    QSignalSpy spy(&ds, &DesignStudio::pinFailed);
+    DesignStudio ds("localhost", 40010, "id", "deviceId");
+    QSignalSpy spy(&ds, &DesignStudio::connected);
+    QSignalSpy spy2(&ds, &DesignStudio::idReceived);
     QVERIFY(spy.isValid());
+    QVERIFY(spy2.isValid());
 
-    const QJsonObject pinVerificationFailedPackage
-        = createPackage(PackageFromDesignStudio::pinFailed, "data");
-    socket->sendTextMessage(
-        QJsonDocument(pinVerificationFailedPackage).toJson(QJsonDocument::Compact));
-
-    QTRY_COMPARE(spy.count(), 1);
-}
-
-void TestDesignStudio::testUnregisteredSignal()
-{
-    QWebSocketServer server("TestDesignStudio", QWebSocketServer::NonSecureMode);
-    QVERIFY(server.listen(QHostAddress::LocalHost, 40009));
-
-    DesignStudio ds("localhost", 40009, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
 
     QWebSocket *socket = server.nextPendingConnection();
     QVERIFY(socket != nullptr);
 
-    QSignalSpy spy(&ds, &DesignStudio::unpaired);
-    QVERIFY(spy.isValid());
-
-    const QJsonObject deviceIdDeclinedPackage
-        = createPackage(PackageFromDesignStudio::deviceIdDeclined, "data");
-    socket->sendTextMessage(QJsonDocument(deviceIdDeclinedPackage).toJson(QJsonDocument::Compact));
+    const QJsonObject dsReadyPackage = createPackage(PackageFromDesignStudio::designStudioReady,
+                                                     "data");
+    socket->sendTextMessage(QJsonDocument(dsReadyPackage).toJson(QJsonDocument::Compact));
 
     QTRY_COMPARE(spy.count(), 1);
+    QTRY_COMPARE(spy2.count(), 1);
 }
 
-void TestDesignStudio::testConnectionAliveSignal()
+void TestDesignStudio::testDisconnectedSignal()
 {
     QWebSocketServer server("TestDesignStudio", QWebSocketServer::NonSecureMode);
-    QVERIFY(server.listen(QHostAddress::LocalHost, 40010));
+    QVERIFY(server.listen(QHostAddress::LocalHost, 40011));
 
-    DesignStudio ds("localhost", 40010, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
+    DesignStudio ds("localhost", 40011, "id", "deviceId");
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
 
     QWebSocket *socket = server.nextPendingConnection();
     QVERIFY(socket != nullptr);
 
-    QSignalSpy spy(&ds, &DesignStudio::paired);
+    QSignalSpy spy(&ds, &DesignStudio::disconnected);
     QVERIFY(spy.isValid());
 
-    const QJsonObject dsReadyPackage = createPackage(PackageFromDesignStudio::deviceIdAccepted,
-                                                     "data");
-    socket->sendTextMessage(QJsonDocument(dsReadyPackage).toJson(QJsonDocument::Compact));
+    ds.disconnectFromDesignStudio();
 
     QTRY_COMPARE(spy.count(), 1);
 }
@@ -245,7 +196,8 @@ void TestDesignStudio::testProjectIncomingSignal()
     QVERIFY(server.listen(QHostAddress::LocalHost, 40011));
 
     DesignStudio ds("localhost", 40011, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
 
     QWebSocket *socket = server.nextPendingConnection();
     QVERIFY(socket != nullptr);
@@ -266,7 +218,8 @@ void TestDesignStudio::testProjectReceivedSignal()
     QVERIFY(server.listen(QHostAddress::LocalHost, 40012));
 
     DesignStudio ds("localhost", 40012, "id", "deviceId");
-    QTRY_VERIFY(ds.connected());
+    ds.connectToDesignStudio();
+    QTRY_VERIFY(ds.isConnected());
 
     QWebSocket *socket = server.nextPendingConnection();
     QVERIFY(socket != nullptr);
diff --git a/tests/tst_designstudio.h b/tests/tst_designstudio.h
index 7573c6b1751cb30fb29e86ae4b1ce1d635dc6d91..3abbf5ff50c8a99ea370204a805303a11214714c 100644
--- a/tests/tst_designstudio.h
+++ b/tests/tst_designstudio.h
@@ -43,20 +43,20 @@ private slots:
     void testId();
     void testPort();
     void testUrl();
-    void testSkipPairing();
 
     // test status check
     void testConnected();
 
+    // test connect/disconnect
+    void testConnect();
+    void testDisconnect();
+
     // test send data
-    void testSendRegistrationPin();
     void testSendDeviceInfo();
 
     // test signals
-    void testRegistrationPinRequestedSignal();
-    void testPinVerificationFailedSignal();
-    void testUnregisteredSignal();
-    void testConnectionAliveSignal();
+    void testConnectedSignal();
+    void testDisconnectedSignal();
     void testProjectIncomingSignal();
     void testProjectReceivedSignal();
 };
diff --git a/tests/tst_dsmanager.cpp b/tests/tst_dsmanager.cpp
deleted file mode 100644
index 51f9a0c2f3077052127b5aea26c0c446166d3aa7..0000000000000000000000000000000000000000
--- a/tests/tst_dsmanager.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2024 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "tst_dsmanager.h"
-
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QTest>
-#include <QUdpSocket>
-
-#include "backend/dsconnector/dsmanager.h"
-#include "mock.h"
-
-void TestDesignStudioManager::testEnterPin()
-{
-    // Test enterPin() function
-}
-
-void TestDesignStudioManager::testDesignStudioRegisteredSignal()
-{
-    // Test designStudioRegisteredSignal() function
-}
-
-void TestDesignStudioManager::testDesignStudioUnregisteredSignal()
-{
-    // Test designStudioUnregisteredSignal() function
-}
-
-void TestDesignStudioManager::testPinRequestedSignal()
-{
-    // Test pinRequestedSignal() function
-}
-
-void TestDesignStudioManager::testProjectReceivedSignal()
-{
-    // Test projectReceivedSignal() function
-}
diff --git a/tests/tst_projectmanager.cpp b/tests/tst_projectmanager.cpp
deleted file mode 100644
index c2caf9a080e29d6cda9a74bf7f72f8c01b70180e..0000000000000000000000000000000000000000
--- a/tests/tst_projectmanager.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2024 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "tst_projectmanager.h"
-
-#include <QJsonArray>
-#include <QTest>
-
-#include "backend/projectmanager.h"
-#include "backend/serviceconnector.h"
-
-#define DEMO_PROJECT_NAME "ClusterTutorial"
-
-void TestProjectManager::initTestCase()
-{
-    qDebug() << "Initialize TestProjectManager";
-    ServiceConnector sc;
-    std::optional<QJsonArray> demoProjectList = sc.fetchDemoList();
-    QVERIFY(demoProjectList.has_value());
-
-    m_demoProjectData = sc.fetchDemo(DEMO_PROJECT_NAME);
-    QVERIFY(m_demoProjectData.has_value());
-
-    QJsonObject projectInfo;
-    for (auto project : demoProjectList.value()) {
-        if (DEMO_PROJECT_NAME == project.toObject().value("name").toString().remove(".qmlrc")) {
-            m_demoInfoCorrect = project.toObject();
-            break;
-        }
-    }
-
-    m_demoInfoIncorrect = QJsonObject{
-        {{"lastUpdate", 1707822220200.017}, {"name", "ClusterTutorial.qmlrc"}}};
-
-    m_userProjectInfoCorrect = QJsonObject{{{"appName", "Testmcu"},
-                                            {"id", "0sadf8fa9s8df67s8998690a7sdf"},
-                                            {"owner", ""},
-                                            {"passwordHash", ""},
-                                            {"qdsIsEnterprise", true},
-                                            {"qdsVersion", "Qt Design Studio 4.2.0"},
-                                            {"ttlDays", 31},
-                                            {"uploadTime", "2023-10-27T13:57:22"},
-                                            {"userHash", "12038740912873462987"}}};
-
-    m_userProjectInfoIncorrect = QJsonObject{{{"appName", "Testmcu"},
-                                              {"id", "0sadf8fa9s8df67s8998690a7sdf"},
-                                              {"owner", ""},
-                                              {"passwordHash", ""},
-                                              {"qdsIsEnterprise", true},
-                                              {"qdsVersion", "Qt Design Studio 4.2.0"},
-                                              {"ttlDays", 31},
-                                              {"uploadTime", "2023-10-27T13:58:22"},
-                                              {"userHash", "12038740912873462987"}}};
-    qDebug() << "TestProjectManager initialized";
-}
-
-void TestProjectManager::cacheDemoProject()
-{
-    ProjectManager pm;
-
-    QCOMPARE(pm.cacheDemoProject(m_demoProjectData.value(), m_demoInfoCorrect), true);
-}
-
-void TestProjectManager::isDemoProjectCachedTrue()
-{
-    ProjectManager pm;
-
-    QVERIFY(pm.cacheDemoProject(m_demoProjectData.value(), m_demoInfoCorrect));
-    QCOMPARE(pm.isDemoProjectCached(m_demoInfoCorrect), true);
-}
-
-void TestProjectManager::isDemoProjectCachedFalse()
-{
-    ProjectManager pm;
-
-    QVERIFY(pm.cacheDemoProject(m_demoProjectData.value(), m_demoInfoCorrect));
-    QCOMPARE(pm.isDemoProjectCached(m_demoInfoIncorrect), false);
-}
-
-void TestProjectManager::clearDemoProjectCache()
-{
-    ProjectManager pm;
-    QVERIFY(pm.cacheDemoProject(m_demoProjectData.value(), m_demoInfoCorrect));
-
-    pm.clearDemoCaches();
-    QCOMPARE(pm.isDemoProjectCached(m_demoInfoCorrect), false);
-}
-
-void TestProjectManager::cacheUserProject()
-{
-    ProjectManager pm;
-    QCOMPARE(pm.cacheProject(m_demoProjectData.value(), m_userProjectInfoCorrect), true);
-}
-
-void TestProjectManager::isUserProjectCachedTrue()
-{
-    ProjectManager pm;
-    pm.cacheProject(m_demoProjectData.value(), m_userProjectInfoCorrect);
-    QCOMPARE(pm.isProjectCached(m_userProjectInfoCorrect), true);
-}
-
-void TestProjectManager::isUserProjectCachedFalse()
-{
-    ProjectManager pm;
-    QVERIFY(pm.cacheProject(m_demoProjectData.value(), m_userProjectInfoCorrect));
-    QCOMPARE(pm.isProjectCached(m_userProjectInfoIncorrect), false);
-}
-
-void TestProjectManager::clearUserProjectCache()
-{
-    ProjectManager pm;
-    QVERIFY(pm.cacheProject(m_demoProjectData.value(), m_userProjectInfoCorrect));
-    QVERIFY(pm.isProjectCached(m_userProjectInfoCorrect));
-
-    pm.clearCachedProject(m_userProjectInfoCorrect);
-    QCOMPARE(pm.isProjectCached(m_userProjectInfoCorrect), false);
-}
-
-void TestProjectManager::clearNonExistentUserProjectCache()
-{
-    ProjectManager pm;
-    QVERIFY(!pm.isProjectCached(m_userProjectInfoIncorrect));
-    pm.clearCachedProject(m_userProjectInfoIncorrect);
-    QCOMPARE(pm.isProjectCached(m_userProjectInfoIncorrect), false);
-}
diff --git a/tests/tst_projectmanager.h b/tests/tst_projectmanager.h
deleted file mode 100644
index 4e7635a356cc1ae3acd8ebf0e9507de3e8514752..0000000000000000000000000000000000000000
--- a/tests/tst_projectmanager.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2024 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QJsonObject>
-
-class TestProjectManager : public QObject
-{
-    Q_OBJECT
-private:
-    std::optional<QByteArray> m_demoProjectData;
-    QJsonObject m_demoInfoCorrect;
-    QJsonObject m_demoInfoIncorrect;
-    QJsonObject m_userProjectInfoCorrect;
-    QJsonObject m_userProjectInfoIncorrect;
-
-private slots:
-    // init
-    void initTestCase();
-
-    // project manager tests - demo project
-    void cacheDemoProject();
-    void isDemoProjectCachedTrue();
-    void isDemoProjectCachedFalse();
-    void clearDemoProjectCache();
-
-    // project manager tests - user project
-    void cacheUserProject();
-    void isUserProjectCachedTrue();
-    void isUserProjectCachedFalse();
-    void clearUserProjectCache();
-    void clearNonExistentUserProjectCache();
-};
diff --git a/tests/tst_serviceconnector.cpp b/tests/tst_serviceconnector.cpp
deleted file mode 100644
index 9b6c66e9ea7a8a4fde24eb668f91f54bbbd58c39..0000000000000000000000000000000000000000
--- a/tests/tst_serviceconnector.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2024 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "tst_serviceconnector.h"
-
-#include <QJsonObject>
-#include <QTest>
-
-#include "backend/serviceconnector.h"
-
-#define DEMO_PROJECT_NAME "ClusterTutorial"
-
-void TestServiceConnector::initTestCase()
-{
-    qDebug() << "Initialize TestServiceConnector";
-    ServiceConnector sc;
-    m_demoProjectList = sc.fetchDemoList();
-    QVERIFY(m_demoProjectList.has_value());
-
-    m_demoProjectData = sc.fetchDemo(DEMO_PROJECT_NAME);
-    QVERIFY(m_demoProjectData.has_value());
-
-    qDebug() << "TestServiceConnector initialized";
-}
-
-void TestServiceConnector::fetchDemoProjectList()
-{
-    QStringList projectNames{"ClusterTutorial.qmlrc",
-                             "CoffeeMachine.qmlrc",
-                             "EBikeDesign.qmlrc",
-                             "MaterialBundle.qmlrc",
-                             "SideMenu.qmlrc",
-                             "WebinarDemo.qmlrc"};
-
-    QStringList projectNamesFromJson;
-    for (const auto &project : m_demoProjectList.value()) {
-        projectNamesFromJson.append(project.toObject().value("name").toString());
-    }
-
-    QCOMPARE(projectNamesFromJson, projectNames);
-}
-
-void TestServiceConnector::fetchDemoProject()
-{
-    QCOMPARE(m_demoProjectData.has_value(), true);
-}
diff --git a/tests/tst_serviceconnector.h b/tests/tst_settings.cpp
similarity index 71%
rename from tests/tst_serviceconnector.h
rename to tests/tst_settings.cpp
index b0dfa99706193d3c3c100475fff8f03c732a9055..dcb5ffc6f885e94fbce008583b4e2808a9dbfc5d 100644
--- a/tests/tst_serviceconnector.h
+++ b/tests/tst_settings.cpp
@@ -23,21 +23,26 @@
 **
 ****************************************************************************/
 
-#pragma once
+#include "tst_settings.h"
 
-#include <QJsonArray>
+#include <QTest>
 
-class TestServiceConnector : public QObject
+#include "backend/settings.h"
+
+void TestSettings::testAutoScaleProject()
 {
-    Q_OBJECT
-private:
-    std::optional<QJsonArray> m_demoProjectList;
-    std::optional<QByteArray> m_demoProjectData;
+    Settings settings;
+    QVERIFY(settings.autoScaleProject());
+
+    settings.setAutoScaleProject(false);
+    QVERIFY(!settings.autoScaleProject());
+}
 
-private slots:
-    void initTestCase();
+void TestSettings::testDeviceUuid()
+{
+    Settings settings;
+    QVERIFY(settings.deviceUuid().isEmpty());
 
-    // service connector tests
-    void fetchDemoProjectList();
-    void fetchDemoProject();
-};
+    settings.setDeviceUuid("1234567890");
+    QCOMPARE(settings.deviceUuid(), QString("1234567890"));
+}
diff --git a/tests/tst_dsmanager.h b/tests/tst_settings.h
similarity index 81%
rename from tests/tst_dsmanager.h
rename to tests/tst_settings.h
index 07442f2a9a7aa4f6590b6f8f7ff86f632481d33d..18ed10d762d0072177bd555f46025e3cbdc80a86 100644
--- a/tests/tst_dsmanager.h
+++ b/tests/tst_settings.h
@@ -27,18 +27,11 @@
 
 #include <QObject>
 
-class TestDesignStudioManager : public QObject
+class TestSettings : public QObject
 {
     Q_OBJECT
-private:
 private slots:
 
-    // test setters
-    void testEnterPin();
-
-    // test signals
-    void testDesignStudioRegisteredSignal();
-    void testDesignStudioUnregisteredSignal();
-    void testPinRequestedSignal();
-    void testProjectReceivedSignal();
+    void testAutoScaleProject();
+    void testDeviceUuid();
 };