diff --git a/index2.html b/index2.html
new file mode 100644
index 0000000..b42f104
--- /dev/null
+++ b/index2.html
@@ -0,0 +1,159 @@
+
+
+
+    Socket.IO Test Client
+    
+
+
+    Socket.IO Test Client
+
+    
+        
Подключение
+        
+        
+        
+        
+    
+
+    
+        
Отправка клиентского сообщения
+        
+        
+    
+
+    
+        
Настройки
+        
+    
+
+    Логи 
+    
+
+    
+    
+
+
diff --git a/yobble.xcodeproj/project.pbxproj b/yobble.xcodeproj/project.pbxproj
index a3e6849..9f2db6b 100644
--- a/yobble.xcodeproj/project.pbxproj
+++ b/yobble.xcodeproj/project.pbxproj
@@ -6,6 +6,10 @@
 	objectVersion = 77;
 	objects = {
 
+/* Begin PBXBuildFile section */
+		1A85C6CC2EA6FD73009FA847 /* SocketIO in Frameworks */ = {isa = PBXBuildFile; productRef = 1A85C6CB2EA6FD73009FA847 /* SocketIO */; };
+/* End PBXBuildFile section */
+
 /* Begin PBXContainerItemProxy section */
 		1A6D61DB2E7CD04000B9F736 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
@@ -52,6 +56,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				1A85C6CC2EA6FD73009FA847 /* SocketIO in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -112,6 +117,7 @@
 			);
 			name = yobble;
 			packageProductDependencies = (
+				1A85C6CB2EA6FD73009FA847 /* SocketIO */,
 			);
 			productName = yobble;
 			productReference = 1A6D61CC2E7CD03E00B9F736 /* yobble.app */;
@@ -196,6 +202,9 @@
 			);
 			mainGroup = 1A6D61C32E7CD03E00B9F736;
 			minimizedProjectReferenceProxies = 1;
+			packageReferences = (
+				1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */,
+			);
 			preferredProjectObjectVersion = 77;
 			productRefGroup = 1A6D61CD2E7CD03E00B9F736 /* Products */;
 			projectDirPath = "";
@@ -598,6 +607,25 @@
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+		1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/socketio/socket.io-client-swift";
+			requirement = {
+				kind = exactVersion;
+				version = 16.1.1;
+			};
+		};
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+		1A85C6CB2EA6FD73009FA847 /* SocketIO */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = 1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */;
+			productName = SocketIO;
+		};
+/* End XCSwiftPackageProductDependency section */
 	};
 	rootObject = 1A6D61C42E7CD03E00B9F736 /* Project object */;
 }
diff --git a/yobble.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/yobble.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
new file mode 100644
index 0000000..c865547
--- /dev/null
+++ b/yobble.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -0,0 +1,24 @@
+{
+  "originHash" : "c9fb241c5f575df8f20b39649006995779013948e60c51c3f85b729f83b054e7",
+  "pins" : [
+    {
+      "identity" : "socket.io-client-swift",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/socketio/socket.io-client-swift",
+      "state" : {
+        "revision" : "42da871d9369f290d6ec4930636c40672143905b",
+        "version" : "16.1.1"
+      }
+    },
+    {
+      "identity" : "starscream",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/daltoniam/Starscream",
+      "state" : {
+        "revision" : "c6bfd1af48efcc9a9ad203665db12375ba6b145a",
+        "version" : "4.0.8"
+      }
+    }
+  ],
+  "version" : 3
+}
diff --git a/yobble/Network/AuthNotifications.swift b/yobble/Network/AuthNotifications.swift
new file mode 100644
index 0000000..a4867e0
--- /dev/null
+++ b/yobble/Network/AuthNotifications.swift
@@ -0,0 +1,5 @@
+import Foundation
+
+extension Notification.Name {
+    static let accessTokenDidChange = Notification.Name("accessTokenDidChange")
+}
diff --git a/yobble/Network/AuthService.swift b/yobble/Network/AuthService.swift
index 47aeab3..7e0e590 100644
--- a/yobble/Network/AuthService.swift
+++ b/yobble/Network/AuthService.swift
@@ -69,6 +69,8 @@ final class AuthService {
                     }
                     UserDefaults.standard.set(username, forKey: "currentUser")
 
+                    NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
+
                     completion(true, nil)
                 } catch {
                     completion(false, NSLocalizedString("Не удалось обработать ответ сервера.", comment: ""))
@@ -175,6 +177,8 @@ final class AuthService {
 
         UserDefaults.standard.removeObject(forKey: "currentUser")
 
+        NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
+
         let allUsers = KeychainService.shared.getAllServices()
         for user in allUsers {
             let hasAccessToken = KeychainService.shared.get(forKey: "access_token", service: user) != nil
@@ -183,6 +187,7 @@ final class AuthService {
             if hasAccessToken && hasRefreshToken {
                 UserDefaults.standard.set(user, forKey: "currentUser")
                 if AppConfig.DEBUG { print("Logout: переключились на пользователя \(user)") }
+                NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
                 completion(true, nil)
                 return
             }
diff --git a/yobble/Network/NetworkClient.swift b/yobble/Network/NetworkClient.swift
index 185b2ae..c17a50e 100644
--- a/yobble/Network/NetworkClient.swift
+++ b/yobble/Network/NetworkClient.swift
@@ -266,6 +266,8 @@ final class NetworkClient {
                             KeychainService.shared.save(userId, forKey: "userId", service: tokenInfo.login)
                         }
 
+                        NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
+
                         self.completeRefresh(success: true)
                     } catch {
                         self.completeRefresh(success: false)
diff --git a/yobble/Services/SocketService.swift b/yobble/Services/SocketService.swift
new file mode 100644
index 0000000..4bbddf0
--- /dev/null
+++ b/yobble/Services/SocketService.swift
@@ -0,0 +1,135 @@
+import Foundation
+#if canImport(SocketIO)
+import SocketIO
+#endif
+
+final class SocketService {
+    static let shared = SocketService()
+
+    private let syncQueue = DispatchQueue(label: "org.yobble.socket.service")
+    private var currentToken: String?
+    private var currentAuthPayload: [String: Any] = [:]
+
+    #if canImport(SocketIO)
+    private var manager: SocketManager?
+    private var socket: SocketIOClient?
+    #endif
+
+    private init() {}
+
+    func connectForCurrentUser() {
+        syncQueue.async { [weak self] in
+            guard let self else { return }
+            guard let token = self.resolveCurrentAccessToken() else {
+                if AppConfig.DEBUG { print("[SocketService] No access token available, disconnecting") }
+                self.currentToken = nil
+                self.disconnectInternal()
+                return
+            }
+
+            self.connectInternal(with: token)
+        }
+    }
+
+    func connect(withToken token: String) {
+        syncQueue.async { [weak self] in
+            self?.connectInternal(with: token)
+        }
+    }
+
+    func disconnect() {
+        syncQueue.async { [weak self] in
+            guard let self else { return }
+            self.currentToken = nil
+            self.disconnectInternal()
+        }
+    }
+
+    private func resolveCurrentAccessToken() -> String? {
+        guard
+            let login = UserDefaults.standard.string(forKey: "currentUser"),
+            !login.isEmpty
+        else {
+            return nil
+        }
+
+        return KeychainService.shared.get(forKey: "access_token", service: login)
+    }
+
+    private func connectInternal(with token: String) {
+        #if canImport(SocketIO)
+        if token == currentToken,
+           let socket,
+           socket.status == .connected || socket.status == .connecting {
+            if AppConfig.DEBUG { print("[SocketService] Already connected with current token") }
+            return
+        }
+
+        currentToken = token
+        currentAuthPayload = ["token": token]
+        setupSocket(with: token)
+        socket?.connect(withPayload: currentAuthPayload)
+        #else
+        if AppConfig.DEBUG {
+            print("[SocketService] SocketIO framework not available; skipping connection")
+        }
+        #endif
+    }
+
+    #if canImport(SocketIO)
+    private func setupSocket(with token: String) {
+        guard let baseURL = URL(string: AppConfig.API_SERVER) else {
+            if AppConfig.DEBUG { print("[SocketService] Invalid socket URL: \(AppConfig.API_SERVER)") }
+            return
+        }
+
+        disconnectInternal()
+
+        let configuration: SocketIOClientConfiguration = [
+            .log(AppConfig.DEBUG),
+            .compress,
+            .secure(AppConfig.PROTOCOL.lowercased() == "https"),
+            .path(AppConfig.SOCKET_PATH),
+            .reconnects(true),
+            .reconnectWait(2),
+            .forceWebsockets(true),
+            .extraHeaders(["Authorization": "Bearer \(token)"]),
+            .connectParams(["token": token])
+        ]
+
+        let manager = SocketManager(socketURL: baseURL, config: configuration)
+        manager.handleQueue = syncQueue
+        let socket = manager.defaultSocket
+
+        if AppConfig.DEBUG {
+            socket.onAny { event in
+                print("[SocketService] onAny event=\(event.event) data=\(event.items ?? [])")
+            }
+        }
+
+        socket.on(clientEvent: .connect) { _, _ in
+            if AppConfig.DEBUG { print("[SocketService] Connected") }
+        }
+
+        socket.on(clientEvent: .disconnect) { data, _ in
+            if AppConfig.DEBUG { print("[SocketService] Disconnected: \(data)") }
+        }
+
+        socket.on(clientEvent: .error) { data, _ in
+            if AppConfig.DEBUG { print("[SocketService] Error: \(data)") }
+        }
+
+        self.manager = manager
+        self.socket = socket
+    }
+
+    private func disconnectInternal() {
+        socket?.disconnect()
+        manager?.disconnect()
+        socket = nil
+        manager = nil
+    }
+    #else
+    private func disconnectInternal() { }
+    #endif
+}
diff --git a/yobble/ViewModels/LoginViewModel.swift b/yobble/ViewModels/LoginViewModel.swift
index 8b07628..9f73a08 100644
--- a/yobble/ViewModels/LoginViewModel.swift
+++ b/yobble/ViewModels/LoginViewModel.swift
@@ -18,6 +18,7 @@ class LoginViewModel: ObservableObject {
     @Published var isLoggedIn: Bool = false
 
     private let authService = AuthService()
+    private let socketService = SocketService.shared
 
     private enum DefaultsKeys {
         static let currentUser = "currentUser"
@@ -38,10 +39,12 @@ class LoginViewModel: ObservableObject {
                 if success {
                     self?.loadStoredUser()
                     self?.isLoggedIn = true
+                    self?.socketService.connectForCurrentUser()
                 } else {
                     self?.isLoggedIn = false
                     self?.errorMessage = error ?? NSLocalizedString("Произошла ошибка.", comment: "")
                     self?.showError = false
+                    self?.socketService.disconnect()
                 }
                 self?.isLoading = false
             }
@@ -59,9 +62,11 @@ class LoginViewModel: ObservableObject {
                 if success {
                     self?.loadStoredUser()
                     self?.isLoggedIn = true
+                    self?.socketService.connectForCurrentUser()
                 } else {
                     self?.errorMessage = error ?? NSLocalizedString("Неизвестная ошибка", comment: "")
                     self?.showError = true
+                    self?.socketService.disconnect()
                 }
             }
         }
@@ -73,6 +78,9 @@ class LoginViewModel: ObservableObject {
                 if success {
                     self?.isLoggedIn = true // 👈 переключаем на главный экран после автологина
                     self?.loadStoredUser()
+                    self?.socketService.connectForCurrentUser()
+                } else {
+                    self?.socketService.disconnect()
                 }
                 completion(success, message)
             }
@@ -87,6 +95,7 @@ class LoginViewModel: ObservableObject {
                     self?.password = ""
                     self?.isLoggedIn = true
                     self?.showError = false
+                    self?.socketService.connectForCurrentUser()
                 } else {
                     self?.username = ""
                     self?.userId = ""
@@ -94,6 +103,7 @@ class LoginViewModel: ObservableObject {
                     self?.isLoggedIn = false
                     self?.errorMessage = error ?? NSLocalizedString("Ошибка при деавторизации.", comment: "")
                     self?.showError = false
+                    self?.socketService.disconnect()
                 }
             }
         }
diff --git a/yobble/config.swift b/yobble/config.swift
index 5cf05d8..7d55cac 100644
--- a/yobble/config.swift
+++ b/yobble/config.swift
@@ -5,6 +5,7 @@ struct AppConfig {
     //static let SERVICE = Bundle.main.bundleIdentifier ?? "default.service"
     static let PROTOCOL = "https"
     static let API_SERVER = "\(PROTOCOL)://api.yobble.org"
+    static let SOCKET_PATH = "/socket.io/"
 
     static let USER_AGENT = "yobble ios"
     static let APP_BUILD = "appstore" // appstore / freestore