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 -> ProtocolRuntime"]
      D2["SessionCoordinator"]
      D3["IdentityGateway"]
      D4["AccountManager / PreferencesManager"]
      D5["MessageRepository / GroupRepository"]
    end

    subgraph CHAT_UI["Chat UI Orchestration"]
      C1["ChatDetailScreen / ChatsListScreen"]
      C2["ChatViewModel (host-state)"]
      C3["Feature VM: Messages/Voice/Attachments/Typing"]
      C4["Coordinators: Messages/Forward/Attachments"]
    end

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

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

    subgraph NET["Network Runtime"]
      N0["ProtocolRuntime"]
      N1["RuntimeComposition (wiring only)"]
      N2["RuntimeConnectionControlFacade"]
      N3["RuntimeDirectoryFacade"]
      N4["RuntimePacketIoFacade"]
      N5["Assemblies: Transport / Messaging / State / Routing"]
      N6["ProtocolInstanceManager -> Protocol"]
      N7["ProtocolManager (legacy compat)"]
    end

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

    ENTRY --> DI
    DI --> SESSION
    DI --> DATA
    DI --> CHAT_UI
    DI --> N0
    CHAT_UI --> CHAT_DOMAIN
    CHAT_UI --> R1
    CHAT_DOMAIN --> D1
    D1 --> N0
    N0 --> N1
    N1 --> N2
    N1 --> N3
    N1 --> N4
    N1 --> N5
    N5 --> N6
    N7 --> N0
    SESSION --> N0
    R1 --> N0
    R1 --> R2

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 --> RTA["RuntimeTransportAssembly"]
    RC --> RMA["RuntimeMessagingAssembly"]
    RC --> RSA["RuntimeStateAssembly"]
    RC --> RRA["RuntimeRoutingAssembly"]

    RTA --> PIM["ProtocolInstanceManager"]
    RTA --> PSF["PacketSubscriptionFacade"]
    RTA --> NCF["NetworkConnectivityFacade"]

    RMA --> SC["SyncCoordinator"]
    RMA --> PROUTER["PacketRouter"]
    RMA --> OMPS["OutgoingMessagePipelineService"]
    RMA --> CSB["CallSignalBridge"]
    RMA --> IPR["InboundPacketHandlerRegistrar"]

    RSA --> RLSM["RuntimeLifecycleStateMachine"]
    RSA --> BC["BootstrapCoordinator"]
    RSA --> RPG["ReadyPacketGate"]
    RSA --> PLSS["ProtocolLifecycleStateStoreImpl"]

    RRA --> SUP["ProtocolConnectionSupervisor"]
    RRA --> CER["ConnectionEventRouter"]

    CER --> CO["ConnectionOrchestrator"]
    CER --> PLC["ProtocolLifecycleCoordinator"]
    CER --> PAC["ProtocolAccountSessionCoordinator"]
    CER --> RPDC["ReadyPacketDispatchCoordinator"]

    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 PR as ProtocolRuntime
    participant RPF as RuntimePacketIoFacade
    participant PSF as PacketSubscriptionFacade
    participant REG as PacketSubscriptionRegistry
    participant P as Protocol

    Feature->>PR: waitPacket(0x03, callback)
    PR->>RPF: waitPacket(0x03, callback)
    RPF->>PSF: waitPacket(0x03, callback)
    PSF->>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.send / sendMessageWithRetry"]
    GW --> PR["ProtocolRuntime"]
    PR --> RPF["RuntimePacketIoFacade"]
    RPF --> OMP["OutgoingMessagePipelineService"]
    OMP --> RQ["RetryQueueService"]
    OMP --> RR["RuntimeRoutingAssembly"]
    RR --> RG["ReadyPacketGate / ReadyPacketDispatchCoordinator"]
    RG --> 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 (host-state)"]
    TVM --> CVM
    VVM --> CVM
    AVM --> CVM
    CVM --> MCO["MessagesCoordinator"]
    CVM --> FCO["ForwardCoordinator"]
    CVM --> ACO["AttachmentsCoordinator"]
    AVM --> AFCO["AttachmentsFeatureCoordinator"]
    CVM --> U["domain/chats/usecase/*"]
    MCO --> U
    FCO --> U
    ACO --> U
    AFCO --> 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 PR as ProtocolRuntime
    participant RCC as RuntimeConnectionControlFacade
    participant RRA as RuntimeRoutingAssembly
    participant RSA as RuntimeStateAssembly
    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)

    PG->>PR: runtime API calls
    PR->>RCC: connection/auth commands
    RCC->>RRA: post(ConnectionEvent.*)
    RRA-->>RRA: Supervisor + Router route events
    RRA-->>RSA: apply lifecycle transitions
    RSA-->>RSA: AUTHENTICATED -> BOOTSTRAPPING -> 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 --> HANDSHAKING
    AUTHENTICATED --> DISCONNECTED
    BOOTSTRAPPING --> DISCONNECTED
    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 строки): публичные proxy-методы уже убраны, но внутри все еще смешаны wiring и часть helper-логики (setupStateMonitoring, event-bridge, log helpers). Следующий шаг: вынести эти helper-блоки в отдельные adapters/services.
  • ProtocolRuntime + ProtocolRuntimePort все еще имеют широкий API surface (connection + directory + packet IO + call signaling + debug). Нужен audit и сужение публичных контрактов по use-case группам.
  • ChatViewModel остается очень крупным host-классом (около 4391 строки) с большим bridge/proxy surface к feature/coordinator/use-case слоям.
  • AttachmentsFeatureCoordinator остается крупным (около 761 строки): high-level media сценарии стоит резать на более узкие upload/transform/packet-assembly сервисы.
  • Тестовое покрытие архитектурно-критичных слоев недостаточно: app/src/test = 7, app/src/androidTest = 1; не покрыты runtime-routing/lifecycle компоненты (RuntimeRoutingAssembly, ConnectionEventRouter, ProtocolLifecycle*, ReadyPacketDispatchCoordinator) и chat coordinators (Messages/Forward/Attachments*).
  • В runtime все еще несколько точек входа (ProtocolRuntime, ProtocolRuntimeAccess, ProtocolManager legacy), что повышает cognitive load; целевой шаг — дальнейшее сокращение legacy/static call-sites.

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

  • 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) и фокусе на тестах/дальнейшей локальной декомпозиции архитектура остается управляемой и не уходит в избыточную сложность.