Files
mobile-android/Architecture.md

36 KiB
Raw Blame History

Rosetta Android — Architecture

Документ отражает текущее состояние rosetta-android (ветка dev) по коду на 2026-04-19.

1. Архитектурный профиль

Приложение сейчас устроено как layered + service-oriented архитектура:

  • UI: MainActivity + Compose-экраны + ViewModel.
  • Chat feature orchestration: ChatViewModel (host-state) + feature-facade VM + coordinators.
  • DI: Hilt (@HiltAndroidApp, @AndroidEntryPoint, модули в di/AppContainer.kt).
  • Runtime orchestration: ProtocolGateway/ProtocolRuntime -> RuntimeComposition (+ legacy facade ProtocolManager), CallManager, TransportManager, UpdateManager.
  • Session/Identity runtime state: SessionStore, SessionReducer, IdentityStore.
  • Domain сценарии отправки чата: domain/chats/usecase/* (text/media/forward/voice/typing/read-receipt/attachments/upload).
  • Data: MessageRepository, GroupRepository, AccountManager, PreferencesManager.
  • Persistence: Room (RosettaDatabase) + DataStore/SharedPreferences.

Основная runtime-логика сети вынесена в RuntimeComposition, а DI-вход в runtime идет напрямую через ProtocolRuntime. ProtocolManager переведен в минимальный legacy compatibility facade поверх ProtocolRuntimeAccess. DI-вход в network core идет через ProtocolRuntime (Hilt singleton).


2. Слои и границы

flowchart TB
    subgraph ENTRY["Android Entry Points"]
      E1["RosettaApplication"]
      E2["MainActivity"]
      E3["RosettaFirebaseMessagingService"]
      E4["IncomingCallActivity / CallForegroundService"]
    end

    subgraph DI["Hilt Singleton Graph"]
      D1["ProtocolGateway"]
      D1A["ProtocolRuntime"]
      D2["SessionCoordinator"]
      D3["IdentityGateway"]
      D4["AccountManager / PreferencesManager"]
      D5["MessageRepository / GroupRepository"]
    end

    subgraph CHAT_UI["Chat UI Orchestration"]
      C1["ChatDetailScreen / ChatsListScreen"]
      C2["ChatViewModel (host)"]
      C3["Messages/Voice/Attachments/Typing ViewModel"]
      C4["Messages/Forward/Attachments Coordinator"]
    end

    subgraph CHAT_DOMAIN["Chat Domain UseCases"]
      U1["SendText / SendMedia / SendForward"]
      U2["SendVoice / SendTyping / SendReadReceipt"]
      U3["CreateAttachment / EncryptAndUpload"]
    end

    subgraph SESSION["Session / Identity Runtime"]
      S1["SessionStore"]
      S2["SessionReducer"]
      S3["IdentityStore"]
      S4["AppSessionCoordinator"]
    end

    subgraph NET["Network Runtime"]
      N0["ProtocolRuntime"]
      N1C["RuntimeComposition"]
      N1A["ProtocolManager (compat facade)"]
      N2["Protocol"]
      N3["PacketSubscriptionRegistry"]
      N4["ReadyPacketGate"]
    end

    subgraph DATA["Data + Persistence"]
      R1["MessageRepository"]
      R2["GroupRepository"]
      R3["Room: RosettaDatabase"]
    end

    ENTRY --> DI
    DI --> SESSION
    DI --> NET
    DI --> DATA
    DI --> CHAT_UI
    CHAT_UI --> CHAT_DOMAIN
    CHAT_UI --> DATA
    CHAT_DOMAIN --> D1
    D1 --> D1A
    D1A --> N1C
    N1A --> N1C
    SESSION --> NET
    DATA --> NET
    DATA --> R3
    N1C --> N2

3. DI и composition root

3.1 Hilt

  • RosettaApplication помечен @HiltAndroidApp.
  • Entry points уровня Android-компонентов: MainActivity, IncomingCallActivity, CallForegroundService, RosettaFirebaseMessagingService.
  • Основные модули:
  • AppDataModule: AccountManager, PreferencesManager.
  • AppGatewayModule: биндинги ProtocolGateway, SessionCoordinator, IdentityGateway, ProtocolClient.
  • ProtocolGateway теперь биндится напрямую на ProtocolRuntime (без отдельного ProtocolGatewayImpl proxy-класса).
  • ProtocolClientImpl остается узким техническим adapter-слоем для repository (send/sendWithRetry/addLog/wait/unwait) и делегирует в ProtocolRuntime через Provider<ProtocolRuntime>.

3.2 UI bridge для composable-слоя

UI-композаблы больше не получают runtime-зависимости через UiEntryPoint/EntryPointAccessors. UiDependencyAccess.get(...) из ui/* удален (DoD: 0 вхождений).

Для non-Hilt object-ов (CallManager, TransportManager, UpdateManager, utils) используется ProtocolRuntimeAccess + ProtocolRuntimePort:

  • runtime ставится в RosettaApplication через ProtocolRuntimeAccess.install(protocolRuntime);
  • доступ до install запрещен (fail-fast), чтобы не было тихого отката в legacy facade.

3.3 Разрыв DI-cycle (Hilt)

После перехода на ProtocolRuntime был закрыт цикл зависимостей: MessageRepository -> ProtocolClient -> ProtocolRuntime -> MessageRepository.

Текущее решение:

  • ProtocolClientImpl получает Provider<ProtocolRuntime> (ленивая резолюция).
  • ProtocolRuntime остается singleton-композицией для MessageRepository/GroupRepository/AccountManager.
  • На assembleDebug/assembleRelease больше нет Dagger/DependencyCycle.

4. Session lifecycle: единый source of truth

4.1 Модель состояния

SessionState:

  • LoggedOut
  • AuthInProgress(publicKey?, reason)
  • Ready(account, reason)

4.2 Модель событий

SessionAction:

  • LoggedOut
  • AuthInProgress
  • Ready
  • SyncFromCachedAccount

4.3 Контур изменения состояния

  • Только SessionStore владеет MutableStateFlow<SessionState>.
  • Только SessionReducer вычисляет next-state.
  • SessionCoordinator/AppSessionCoordinator больше не мутируют состояние напрямую, а делают dispatch(action).
  • SessionStore.dispatch(...) синхронно обновляет IdentityStore для консистентности account/profile/auth-runtime.
flowchart LR
    A["AuthFlow / MainActivity / Unlock / SetPassword"] --> B["SessionCoordinator.dispatch(action)"]
    B --> C["SessionStore.dispatch(action)"]
    C --> D["SessionReducer.reduce(current, action)"]
    D --> E["StateFlow<SessionState>"]
    C --> F["IdentityStore sync"]

4.4 State machine

stateDiagram-v2
    [*] --> LoggedOut
    LoggedOut --> AuthInProgress: dispatch(AuthInProgress)
    AuthInProgress --> Ready: dispatch(Ready)
    AuthInProgress --> LoggedOut: dispatch(LoggedOut)
    Ready --> LoggedOut: dispatch(LoggedOut)
    Ready --> Ready: dispatch(SyncFromCachedAccount(account))

5. Network orchestration после декомпозиции

ProtocolRuntime — DI-фасад runtime слоя и реализация ProtocolGateway/ProtocolRuntimePort. RuntimeComposition — composition-root runtime слоя (сборка service graph + orchestration wiring) и делегирует отдельные зоны ответственности:

  • Публичные runtime API proxy-методы (connect/auth/directory/packet I/O) убраны из RuntimeComposition; публичный runtime surface теперь удерживается в ProtocolRuntime + Runtime*Facade.
  • RuntimeTransportAssembly: отдельный assembly-блок transport/network wiring (NetworkReconnectWatcher, NetworkConnectivityFacade, ProtocolInstanceManager, PacketSubscriptionRegistry/Facade).
  • RuntimeMessagingAssembly: отдельный assembly-блок packet/message/sync wiring (PacketRouter, OutgoingMessagePipelineService, PresenceTypingService, SyncCoordinator, CallSignalBridge, InboundPacketHandlerRegistrar).
  • RuntimeStateAssembly: отдельный assembly-блок connection-state wiring (ReadyPacketGate, BootstrapCoordinator, RuntimeLifecycleStateMachine, OwnProfileFallbackTimerService, ProtocolLifecycleStateStoreImpl).
  • RuntimeRoutingAssembly: отдельный assembly-блок event-routing wiring (ConnectionEventRouter + ProtocolConnectionSupervisor как единый orchestration-шаг).
  • RuntimeConnectionControlFacade: high-level connection/session control API (initialize*, connect/reconnect/sync/auth, disconnect/destroy, auth/connect checks).
  • RuntimeDirectoryFacade: directory/device/typing API (resolve/search user, cached user lookup, own-profile signal, device accept/decline, typing snapshot by dialog).
  • RuntimePacketIoFacade: packet I/O API (send/sendWithRetry/resolveRetry, call/webrtc/ice bridge, wait/unwait/packetFlow).
  • ProtocolInstanceManager: singleton lifecycle Protocol (create/state/lastError/disconnect/destroy/isAuthenticated/isConnected).
  • RuntimeLifecycleStateMachine: runtime lifecycle state (ConnectionLifecycleState + ConnectionBootstrapContext) и пересчет transition-логики через BootstrapCoordinator.
  • RuntimeInitializationCoordinator: one-time bootstrap runtime (initialize, регистрация packet handlers, старт state monitoring, проверка bound DI dependencies).
  • ProtocolLifecycleStateStoreImpl: отдельное lifecycle-state хранилище (bootstrapContext, sessionGeneration, last-subscribed-token clear hooks, own-profile fallback timer hooks).
  • OwnProfileFallbackTimerService: управление таймером own-profile fallback (schedule/cancel) с генерацией timeout-события.
  • AuthRestoreService: восстановление auth-handshake credentials из локального кеша аккаунта (preferredPublicKey/fallback + validation + authenticate trigger).
  • RuntimeShutdownCoordinator: централизованный graceful runtime shutdown (stop watcher, destroy subscriptions/protocol, clear runtime state/services, cancel scope).
  • ConnectionEventRouter: маршрутизация ConnectionEvent к соответствующим coordinator/service handlers без when(event) внутри core.
  • NetworkConnectivityFacade: единая обертка network-availability/wait/stop policy поверх NetworkReconnectWatcher.
  • ConnectionOrchestrator: connect/reconnect/authenticate + network-aware поведение.
  • ProtocolLifecycleCoordinator: lifecycle/auth/bootstrap transitions (ProtocolStateChanged, SyncCompleted, own-profile resolved/fallback).
  • ProtocolAccountSessionCoordinator: account-bound transitions (InitializeAccount, Disconnect) и reset account/session state.
  • ReadyPacketDispatchCoordinator: обработка SendPacket через ready-gate (bypass/enqueue/flush trigger + reconnect policy).
  • ProtocolPostAuthBootstrapCoordinator: post-auth orchestration (canRun/tryRun bootstrap, own profile fetch, push subscribe, post-sync retry/missing-user-info).
  • BootstrapCoordinator: пересчет lifecycle (AUTHENTICATED/BOOTSTRAPPING/READY) и работа с ReadyPacketGate.
  • SyncCoordinator: sync state machine (request/timeout, BATCH_START/BATCH_END/NOT_NEEDED, foreground/manual sync).
  • PresenceTypingService: in-memory typing presence с TTL и snapshot StateFlow.
  • PacketRouter: user/search cache + resolve/search continuation routing.
  • OwnProfileSyncService: применение собственного профиля из search и синхронизация IdentityStore.
  • RetryQueueService: retry очереди отправки PacketMessage.
  • AuthBootstrapCoordinator: session-aware post-auth bootstrap (transport/update/profile/sync/push).
  • NetworkReconnectWatcher: единый watcher ожидания сети и fast-reconnect триггеры.
  • DeviceVerificationService: состояние списка устройств + pending verification + resolve packets.
  • DeviceRuntimeService: device-id/handshake device + device verification orchestration.
  • CallSignalBridge: call/webrtc/ice signal send+subscribe bridge.
  • PacketSubscriptionFacade: thin bridge waitPacket/unwaitPacket/packetFlow API поверх PacketSubscriptionRegistry.
  • PacketSubscriptionRegistry: централизованные подписки на пакеты и fan-out.
  • InboundPacketHandlerRegistrar: централизованная регистрация inbound packet handlers (0x03/0x05/0x06/0x07/0x08/0x09/0x0B/0x0F/0x14/0x17/0x19) и делегирование в sync/repository/device/typing/profile сервисы.
  • InboundTaskQueueService: sequential inbound task queue (enqueue + whenTasksFinish) для Desktop parity (dialogQueue semantics).
  • OutgoingMessagePipelineService: отправка PacketMessage с retry/error policy.
  • ProtocolDebugLogService: буферизация UI-логов, throttle flush и персистентный protocol trace.

На hot-path ProtocolRuntime берет runtime API (RuntimeConnectionControlFacade/RuntimeDirectoryFacade/RuntimePacketIoFacade) напрямую из RuntimeComposition, поэтому лишний proxy-hop через публичные методы composition не используется.

    flowchart TB
    PR["ProtocolRuntime (ProtocolGateway impl)"] --> RC["RuntimeComposition"]
    RC --> RCC["RuntimeConnectionControlFacade"]
    RC --> RDF["RuntimeDirectoryFacade"]
    RC --> RPF["RuntimePacketIoFacade"]
    RC --> CO["ConnectionOrchestrator"]
    RC --> PIM["ProtocolInstanceManager"]
    RC --> RLSM["RuntimeLifecycleStateMachine"]
    RC --> RIC["RuntimeInitializationCoordinator"]
    RC --> PLSS["ProtocolLifecycleStateStoreImpl"]
    RC --> OPFT["OwnProfileFallbackTimerService"]
    RC --> ARS["AuthRestoreService"]
    RC --> RSC["RuntimeShutdownCoordinator"]
    RC --> CER["ConnectionEventRouter"]
    RC --> NCF["NetworkConnectivityFacade"]
    RC --> PLC["ProtocolLifecycleCoordinator"]
    RC --> PAC["ProtocolAccountSessionCoordinator"]
    RC --> RPDC["ReadyPacketDispatchCoordinator"]
    RC --> PABC["ProtocolPostAuthBootstrapCoordinator"]
    RC --> BC["BootstrapCoordinator"]
    RC --> SC["SyncCoordinator"]
    RC --> PT["PresenceTypingService"]
    RC --> PR["PacketRouter"]
    RC --> OPS["OwnProfileSyncService"]
    RC --> RQ["RetryQueueService"]
    RC --> ABC["AuthBootstrapCoordinator"]
    RC --> NRW["NetworkReconnectWatcher"]
    RC --> DVS["DeviceVerificationService"]
    RC --> CSB["CallSignalBridge"]
    RC --> PSF["PacketSubscriptionFacade"]
    RC --> PSR["PacketSubscriptionRegistry"]
    RC --> IPR["InboundPacketHandlerRegistrar"]
    RC --> IQ["InboundTaskQueueService"]
    RC --> SUP["ProtocolConnectionSupervisor"]
    RC --> RPG["ReadyPacketGate"]
    PIM --> P["Protocol (WebSocket + packet codec)"]

6. Централизация packet-subscriptions

Проблема дублирующихся low-level подписок закрыта через PacketSubscriptionRegistry:

  • На каждый packetId создается один bus и один bridge на Protocol.waitPacket(...).
  • Дальше packet fan-out идет в:
  • callback API (waitPacket/unwaitPacket),
  • SharedFlow (packetFlow(packetId)).
sequenceDiagram
    participant Feature as Feature/Service
    participant PM as Runtime API (Core/Facade)
    participant REG as PacketSubscriptionRegistry
    participant P as Protocol

    Feature->>PM: waitPacket(0x03, callback)
    PM->>REG: addCallback(0x03, callback)
    REG->>P: waitPacket(0x03, protocolBridge) [once per packetId]

    P-->>REG: Packet(0x03)
    REG-->>Feature: callback(packet)
    REG-->>Feature: packetFlow(0x03).emit(packet)

7. Чат-модуль: декомпозиция и message pipeline

7.1 Domain слой для сценариев отправки

Use-case слой вынесен из UI-пакета в domain/chats/usecase:

  • SendTextMessageUseCase
  • SendMediaMessageUseCase
  • SendForwardUseCase
  • SendVoiceMessageUseCase
  • SendTypingIndicatorUseCase
  • SendReadReceiptUseCase
  • CreateFileAttachmentUseCase
  • CreateAvatarAttachmentUseCase
  • CreateVideoCircleAttachmentUseCase
  • EncryptAndUploadAttachmentUseCase

Роли use-case слоя:

  • SendTextMessageUseCase/SendMediaMessageUseCase: сборка PacketMessage + dispatch через ProtocolGateway (с учетом isSavedMessages).
  • SendForwardUseCase: сборка forward-reply JSON, сборка forward attachment и dispatch.
  • SendVoiceMessageUseCase/SendTypingIndicatorUseCase: normalization/decision логика (preview waveform, throttle/guard).
  • SendReadReceiptUseCase: отдельный сценарий отправки PacketRead.
  • Create*AttachmentUseCase: типобезопасная сборка attachment-моделей.
  • EncryptAndUploadAttachmentUseCase: общий шаг encrypt + upload с возвратом transportTag/transportServer.

Текущий поток отправки:

  1. Feature VM/Coordinator через ChatViewModel-host формирует command + encryption context.
  2. UseCase строит payload/decision (PacketMessage или typed decision model).
  3. ProtocolGateway.sendMessageWithRetry(...) уводит пакет в network runtime.
  4. RuntimeComposition (через ProtocolRuntime) регистрирует пакет в RetryQueueService и отправляет в сеть.
  5. До READY пакет буферизуется через ReadyPacketGate, затем flush.
flowchart LR
    FVM["Feature ViewModel"] --> CVM["ChatViewModel (host)"]
    CVM --> COORD["Messages/Forward/Attachments Coordinator"]
    CVM --> UC["domain/chats/usecase/*"]
    COORD --> UC
    UC --> GW["ProtocolGateway.sendMessageWithRetry"]
    GW --> PR["ProtocolRuntime"]
    PR --> RC["RuntimeComposition"]
    RC --> RQ["RetryQueueService"]
    RC --> RG["ReadyPacketGate"]
    RC --> P["Protocol.sendPacket"]

7.2 Декомпозиция ChatViewModel (host + feature/coordinator слой)

Для UI-слоя введены feature-facade viewmodel-классы:

  • MessagesViewModel
  • VoiceRecordingViewModel
  • AttachmentsViewModel
  • TypingViewModel

Они живут в ui/chats/ChatFeatureViewModels.kt и компонуются внутри ChatViewModel. Текущий статус:

  • VoiceRecordingViewModel содержит реальный send-pipeline голосовых сообщений.
  • TypingViewModel содержит реальную отправку typing indicator (throttle + packet send).
  • MessagesViewModel содержит orchestration-level entrypoint (sendMessage, retryMessage), а core text send pipeline вынесен в MessagesCoordinator (pending recovery/throttle + reply/forward packet assembly).
  • ForwardCoordinator вынесен из ChatViewModel: sendForwardDirectly + forward rewrite/re-upload helper-ветка (включая payload resolve из cache/download).
  • AttachmentsCoordinator вынесен из ChatViewModel: updateOptimisticImageMessage, sendImageMessageInternal, sendVideoCircleMessageInternal + local cache/update (localUri cleanup после отправки).
  • AttachmentsFeatureCoordinator вынесен из AttachmentsViewModel: high-level media orchestration для sendImageGroup*, sendFileMessage, sendVideoCircleFromUri, sendAvatarMessage.
  • AttachmentsViewModel теперь концентрируется на facade-методах и sendImageFromUri/sendImageMessage, делегируя крупные media-ветки в coordinator-слой.
flowchart TB
    CD["ChatDetailScreen"] --> MVM["MessagesViewModel"]
    CD --> TVM["TypingViewModel"]
    CD --> VVM["VoiceRecordingViewModel"]
    CD --> AVM["AttachmentsViewModel"]
    MVM --> CVM["ChatViewModel"]
    TVM --> CVM
    VVM --> CVM
    AVM --> CVM
    CVM --> MCO["MessagesCoordinator"]
    CVM --> FCO["ForwardCoordinator"]
    CVM --> ACO["AttachmentsCoordinator"]
    CVM --> U["domain/chats/usecase/*"]
    MCO --> U
    FCO --> U
    ACO --> U

Важно: после вынесения MessagesCoordinator, ForwardCoordinator и AttachmentsCoordinator ChatViewModel выступает как host-state и bridge для feature/coordinator подсистем.

7.3 Декомпозиция ChatsListScreen

Из ChatsListScreen.kt вынесены отдельные composable-секции:

  • ChatItem -> ChatsListChatItem.kt
  • RequestsSection -> ChatsListRequestsSection.kt
  • DrawerContent -> ChatsListDrawerContent.kt

Результат:

  • основной файл экрана меньше и проще для навигации;
  • повторно используемые куски UI имеют явные file boundaries;
  • дальнейший рефакторинг drawer/request/chat list можно делать независимо.

8. Auth/bootstrap: фактический runtime flow

sequenceDiagram
    participant UI as Auth UI (SetPassword/Unlock)
    participant SC as SessionCoordinatorImpl
    participant SS as SessionStore
    participant PG as ProtocolGateway
    participant RC as RuntimeComposition
    participant AM as AccountManager

    UI->>SC: bootstrapAuthenticatedSession(account, reason)
    SC->>SS: dispatch(AuthInProgress)
    SC->>PG: initializeAccount(public, private)
    SC->>PG: connect()
    SC->>PG: authenticate(public, privateHash)
    SC->>PG: reconnectNowIfNeeded(...)
    SC->>AM: setCurrentAccount(public)
    SC->>SS: dispatch(Ready)

    RC-->>RC: HANDSHAKE -> AUTHENTICATED -> BOOTSTRAPPING
    RC-->>RC: SyncCompleted + OwnProfileResolved
    RC-->>RC: connectionLifecycleState = READY

Важно: SessionState.Ready (app-session готова) и connectionLifecycleState = READY (сеть готова) — это разные state-модели.


9. Состояния соединения (network lifecycle)

RuntimeComposition.connectionLifecycleState:

  • DISCONNECTED
  • CONNECTING
  • HANDSHAKING
  • AUTHENTICATED
  • BOOTSTRAPPING
  • READY
  • DEVICE_VERIFICATION_REQUIRED
stateDiagram-v2
    [*] --> DISCONNECTED
    DISCONNECTED --> CONNECTING
    CONNECTING --> HANDSHAKING
    HANDSHAKING --> DEVICE_VERIFICATION_REQUIRED
    HANDSHAKING --> AUTHENTICATED
    AUTHENTICATED --> BOOTSTRAPPING
    BOOTSTRAPPING --> READY
    READY --> DISCONNECTED
    DEVICE_VERIFICATION_REQUIRED --> CONNECTING

10. Ключевые файлы новой архитектуры

  • app/src/main/java/com/rosetta/messenger/di/AppContainer.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolRuntime.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimeComposition.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimeTransportAssembly.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimeMessagingAssembly.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimeStateAssembly.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimeRoutingAssembly.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimeConnectionControlFacade.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimeDirectoryFacade.kt
  • app/src/main/java/com/rosetta/messenger/network/RuntimePacketIoFacade.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolClient.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolRuntimeAccess.kt
  • app/src/main/java/com/rosetta/messenger/session/AppSessionCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/session/SessionStore.kt
  • app/src/main/java/com/rosetta/messenger/session/SessionReducer.kt
  • app/src/main/java/com/rosetta/messenger/session/SessionAction.kt
  • app/src/main/java/com/rosetta/messenger/session/IdentityStore.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt
  • app/src/main/java/com/rosetta/messenger/network/PacketSubscriptionRegistry.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolConnectionModels.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolConnectionSupervisor.kt
  • app/src/main/java/com/rosetta/messenger/network/ReadyPacketGate.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ConnectionOrchestrator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ProtocolInstanceManager.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/RuntimeLifecycleStateMachine.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/RuntimeInitializationCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ProtocolLifecycleStateStoreImpl.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/OwnProfileFallbackTimerService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/AuthRestoreService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/RuntimeShutdownCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ConnectionEventRouter.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/NetworkConnectivityFacade.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/PacketSubscriptionFacade.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ProtocolLifecycleCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ProtocolAccountSessionCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ReadyPacketDispatchCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ProtocolPostAuthBootstrapCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/BootstrapCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/SyncCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/PresenceTypingService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/AuthBootstrapCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/NetworkReconnectWatcher.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/DeviceVerificationService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/DeviceRuntimeService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/CallSignalBridge.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/InboundPacketHandlerRegistrar.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/InboundTaskQueueService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/OutgoingMessagePipelineService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/ProtocolDebugLogService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/PacketRouter.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/OwnProfileSyncService.kt
  • app/src/main/java/com/rosetta/messenger/network/connection/RetryQueueService.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatViewModel.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatFeatureViewModels.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/MessagesCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ForwardCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/AttachmentsCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/AttachmentsFeatureCoordinator.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/OutgoingEncryptionContext.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/OutgoingSendContext.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListChatItem.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListRequestsSection.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListDrawerContent.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListDrawerSections.kt
  • app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListRequestsScreen.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendTextMessageUseCase.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendMediaMessageUseCase.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendForwardUseCase.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendVoiceMessageUseCase.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendTypingIndicatorUseCase.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendReadReceiptUseCase.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/CreateAttachmentUseCases.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/EncryptAndUploadAttachmentUseCase.kt
  • app/src/main/java/com/rosetta/messenger/domain/chats/usecase/VideoCircleMediaUseCases.kt

11. Что осталось как технический долг

Актуальные открытые хвосты:

  • RuntimeComposition остается composition-root, но уже существенно сжат (около 501 строки) после выноса RuntimeTransportAssembly, RuntimeMessagingAssembly, RuntimeStateAssembly, RuntimeRoutingAssembly и удаления публичных proxy-методов; следующий шаг — перенос части lifecycle/orchestration helper-кода в отдельные domain-oriented service/adapters.
  • ProtocolRuntime и ProtocolRuntimePort все еще имеют широкий proxy-surface; нужен audit методов и дальнейшее сужение публичного API по use-case группам.
  • ChatViewModel остается крупным host-классом (state + bridge/proxy API к feature/coordinator/use-case слоям).
  • High-level media сценарии теперь в AttachmentsFeatureCoordinator, но остаются крупными и требуют дальнейшей декомпозиции на более узкие coordinator/service/use-case блоки.
  • Тестовое покрытие архитектурных слоев все еще недостаточно:
  • сейчас в app/src/test всего 7 unit-тестов (в основном crypto/data/helpers), в app/src/androidTest — 1 тест;
  • не покрыты network runtime/coordinator слои (RuntimeComposition, ConnectionEventRouter, ProtocolLifecycle*, ReadyPacketDispatchCoordinator) и chat orchestration (Messages/Forward/Attachments*).

Уже закрыто и больше не считается техдолгом:

  • UiDependencyAccess.get(...) удален из ui/*.
  • UiEntryPoint/EntryPointAccessors убраны из UI-экранов (явная передача зависимостей через MainActivity/ViewModel).
  • DI-cycle MessageRepository -> ProtocolClient -> ProtocolRuntime -> MessageRepository закрыт через Provider<ProtocolRuntime>.
  • ProtocolManager переведен в минимальный legacy compatibility API (тонкие прокси к ProtocolRuntimeAccess).

12. Guardrails против переусложнения

Чтобы декомпозиция не превращалась в «архитектуру ради архитектуры», применяются следующие правила:

  1. Лимит глубины runtime-цепочки вызова: не более 3 логических слоев после DI-entry (ProtocolRuntime -> Runtime*Facade -> service; RuntimeComposition остается composition-root/wiring-слоем, а не обязательным proxy-hop).
  2. Новый слой/класс допускается только если он дает измеримый выигрыш:
  • убирает минимум 80-120 строк связанной orchestration-логики из текущего класса, или
  • убирает минимум 2 внешние зависимости из текущего класса.
  1. Каждый шаг рефакторинга считается завершенным только после: compileDebugKotlin + минимум одного smoke-сценария по затронутому флоу + обновления Architecture.md.
  2. Если после выноса сложность чтения/изменения не снизилась (по факту код не стал проще), такой вынос считается кандидатом на откат/консолидацию.
  3. Для event-driven runtime-chain (ProtocolConnectionSupervisor + ConnectionEventRouter) эти два элемента считаются одним orchestration-этапом при анализе hop-depth.
  4. ProtocolClientImpl трактуется как инфраструктурный DI-adapter и учитывается отдельно от business-flow hop budget.

13. Плюсы и минусы текущей архитектуры

13.1 Плюсы

  • Четко выделены слои: UI, domain use-cases, network runtime, session/identity, data/persistence.
  • DI через Hilt и ProtocolGateway/SessionCoordinator снижает прямую связанность между UI и transport/runtime.
  • Убраны UiEntryPoint/EntryPointAccessors из UI-экранов, что улучшило явность зависимостей.
  • Закрыт критичный DI-cycle MessageRepository -> ProtocolClient -> ProtocolRuntime -> MessageRepository через Provider<ProtocolRuntime>.
  • Network runtime декомпозирован на отдельные сервисы/coordinator-ы с более узкими зонами ответственности.
  • Сокращен DI runtime path: ProtocolGateway биндится напрямую на ProtocolRuntime, runtime работает напрямую с RuntimeComposition.
  • Централизован packet subscription fan-out (PacketSubscriptionRegistry + PacketSubscriptionFacade), что снижает риск дублирующих low-level подписок.
  • В chat-модуле выделен domain use-case слой и вынесены крупные сценарии в coordinators.

13.2 Минусы

  • RuntimeComposition и ChatViewModel остаются очень крупными hotspot-классами и концентрируют много связей.
  • Runtime API-слой пока широкий: много proxy-методов усложняют контроль границ и эволюцию surface API.
  • В части chat/media orchestration (AttachmentsFeatureCoordinator, MessagesCoordinator, ForwardCoordinator) сохраняются большие high-level сценарии.
  • Мало unit/integration тестов на архитектурно-критичные runtime/chat orchestration компоненты.
  • В проекте остаются несколько точек доступа к runtime (ProtocolRuntime, ProtocolRuntimePort, ProtocolManager legacy), что повышает cognitive load для новых разработчиков.
  • Стоимость входа в кодовую базу выросла: для трассировки одного бизнес-флоу нужно проходить больше слоев, чем раньше.

13.3 Итог оценки

  • Текущая архитектура стала заметно лучше по управляемости зависимостей и изоляции ответственности.
  • Главные риски сместились из “монолитного класса” в “размер composition/API surface и недотестированность orchestration”.
  • При соблюдении guardrails (секция 12) и фокусе на тестах/дальнейшей локальной декомпозиции архитектура остается управляемой и не уходит в избыточную сложность.