36 KiB
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 facadeProtocolManager),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(без отдельногоProtocolGatewayImplproxy-класса).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:
LoggedOutAuthInProgress(publicKey?, reason)Ready(account, reason)
4.2 Модель событий
SessionAction:
LoggedOutAuthInProgressReadySyncFromCachedAccount
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 lifecycleProtocol(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 и snapshotStateFlow.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 bridgewaitPacket/unwaitPacket/packetFlowAPI поверх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 (dialogQueuesemantics).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:
SendTextMessageUseCaseSendMediaMessageUseCaseSendForwardUseCaseSendVoiceMessageUseCaseSendTypingIndicatorUseCaseSendReadReceiptUseCaseCreateFileAttachmentUseCaseCreateAvatarAttachmentUseCaseCreateVideoCircleAttachmentUseCaseEncryptAndUploadAttachmentUseCase
Роли 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.
Текущий поток отправки:
- Feature VM/Coordinator через
ChatViewModel-host формирует command + encryption context. - UseCase строит payload/decision (
PacketMessageили typed decision model). ProtocolGateway.sendMessageWithRetry(...)уводит пакет в network runtime.RuntimeComposition(черезProtocolRuntime) регистрирует пакет вRetryQueueServiceи отправляет в сеть.- До
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-классы:
MessagesViewModelVoiceRecordingViewModelAttachmentsViewModelTypingViewModel
Они живут в 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 (localUricleanup после отправки).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.ktRequestsSection->ChatsListRequestsSection.ktDrawerContent->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:
DISCONNECTEDCONNECTINGHANDSHAKINGAUTHENTICATEDBOOTSTRAPPINGREADYDEVICE_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.ktapp/src/main/java/com/rosetta/messenger/network/ProtocolRuntime.ktapp/src/main/java/com/rosetta/messenger/network/RuntimeComposition.ktapp/src/main/java/com/rosetta/messenger/network/RuntimeTransportAssembly.ktapp/src/main/java/com/rosetta/messenger/network/RuntimeMessagingAssembly.ktapp/src/main/java/com/rosetta/messenger/network/RuntimeStateAssembly.ktapp/src/main/java/com/rosetta/messenger/network/RuntimeRoutingAssembly.ktapp/src/main/java/com/rosetta/messenger/network/RuntimeConnectionControlFacade.ktapp/src/main/java/com/rosetta/messenger/network/RuntimeDirectoryFacade.ktapp/src/main/java/com/rosetta/messenger/network/RuntimePacketIoFacade.ktapp/src/main/java/com/rosetta/messenger/network/ProtocolClient.ktapp/src/main/java/com/rosetta/messenger/network/ProtocolRuntimeAccess.ktapp/src/main/java/com/rosetta/messenger/session/AppSessionCoordinator.ktapp/src/main/java/com/rosetta/messenger/session/SessionStore.ktapp/src/main/java/com/rosetta/messenger/session/SessionReducer.ktapp/src/main/java/com/rosetta/messenger/session/SessionAction.ktapp/src/main/java/com/rosetta/messenger/session/IdentityStore.ktapp/src/main/java/com/rosetta/messenger/network/ProtocolManager.ktapp/src/main/java/com/rosetta/messenger/network/PacketSubscriptionRegistry.ktapp/src/main/java/com/rosetta/messenger/network/ProtocolConnectionModels.ktapp/src/main/java/com/rosetta/messenger/network/ProtocolConnectionSupervisor.ktapp/src/main/java/com/rosetta/messenger/network/ReadyPacketGate.ktapp/src/main/java/com/rosetta/messenger/network/connection/ConnectionOrchestrator.ktapp/src/main/java/com/rosetta/messenger/network/connection/ProtocolInstanceManager.ktapp/src/main/java/com/rosetta/messenger/network/connection/RuntimeLifecycleStateMachine.ktapp/src/main/java/com/rosetta/messenger/network/connection/RuntimeInitializationCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/ProtocolLifecycleStateStoreImpl.ktapp/src/main/java/com/rosetta/messenger/network/connection/OwnProfileFallbackTimerService.ktapp/src/main/java/com/rosetta/messenger/network/connection/AuthRestoreService.ktapp/src/main/java/com/rosetta/messenger/network/connection/RuntimeShutdownCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/ConnectionEventRouter.ktapp/src/main/java/com/rosetta/messenger/network/connection/NetworkConnectivityFacade.ktapp/src/main/java/com/rosetta/messenger/network/connection/PacketSubscriptionFacade.ktapp/src/main/java/com/rosetta/messenger/network/connection/ProtocolLifecycleCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/ProtocolAccountSessionCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/ReadyPacketDispatchCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/ProtocolPostAuthBootstrapCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/BootstrapCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/SyncCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/PresenceTypingService.ktapp/src/main/java/com/rosetta/messenger/network/connection/AuthBootstrapCoordinator.ktapp/src/main/java/com/rosetta/messenger/network/connection/NetworkReconnectWatcher.ktapp/src/main/java/com/rosetta/messenger/network/connection/DeviceVerificationService.ktapp/src/main/java/com/rosetta/messenger/network/connection/DeviceRuntimeService.ktapp/src/main/java/com/rosetta/messenger/network/connection/CallSignalBridge.ktapp/src/main/java/com/rosetta/messenger/network/connection/InboundPacketHandlerRegistrar.ktapp/src/main/java/com/rosetta/messenger/network/connection/InboundTaskQueueService.ktapp/src/main/java/com/rosetta/messenger/network/connection/OutgoingMessagePipelineService.ktapp/src/main/java/com/rosetta/messenger/network/connection/ProtocolDebugLogService.ktapp/src/main/java/com/rosetta/messenger/network/connection/PacketRouter.ktapp/src/main/java/com/rosetta/messenger/network/connection/OwnProfileSyncService.ktapp/src/main/java/com/rosetta/messenger/network/connection/RetryQueueService.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatViewModel.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatFeatureViewModels.ktapp/src/main/java/com/rosetta/messenger/ui/chats/MessagesCoordinator.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ForwardCoordinator.ktapp/src/main/java/com/rosetta/messenger/ui/chats/AttachmentsCoordinator.ktapp/src/main/java/com/rosetta/messenger/ui/chats/AttachmentsFeatureCoordinator.ktapp/src/main/java/com/rosetta/messenger/ui/chats/OutgoingEncryptionContext.ktapp/src/main/java/com/rosetta/messenger/ui/chats/OutgoingSendContext.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatsListChatItem.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatsListRequestsSection.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatsListDrawerContent.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatsListDrawerSections.ktapp/src/main/java/com/rosetta/messenger/ui/chats/ChatsListRequestsScreen.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendTextMessageUseCase.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendMediaMessageUseCase.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendForwardUseCase.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendVoiceMessageUseCase.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendTypingIndicatorUseCase.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/SendReadReceiptUseCase.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/CreateAttachmentUseCases.ktapp/src/main/java/com/rosetta/messenger/domain/chats/usecase/EncryptAndUploadAttachmentUseCase.ktapp/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 против переусложнения
Чтобы декомпозиция не превращалась в «архитектуру ради архитектуры», применяются следующие правила:
- Лимит глубины runtime-цепочки вызова: не более 3 логических слоев после DI-entry (
ProtocolRuntime -> Runtime*Facade -> service;RuntimeCompositionостается composition-root/wiring-слоем, а не обязательным proxy-hop). - Новый слой/класс допускается только если он дает измеримый выигрыш:
- убирает минимум 80-120 строк связанной orchestration-логики из текущего класса, или
- убирает минимум 2 внешние зависимости из текущего класса.
- Каждый шаг рефакторинга считается завершенным только после:
compileDebugKotlin+ минимум одного smoke-сценария по затронутому флоу + обновленияArchitecture.md. - Если после выноса сложность чтения/изменения не снизилась (по факту код не стал проще), такой вынос считается кандидатом на откат/консолидацию.
- Для event-driven runtime-chain (
ProtocolConnectionSupervisor+ConnectionEventRouter) эти два элемента считаются одним orchestration-этапом при анализе hop-depth. 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,ProtocolManagerlegacy), что повышает cognitive load для новых разработчиков. - Стоимость входа в кодовую базу выросла: для трассировки одного бизнес-флоу нужно проходить больше слоев, чем раньше.
13.3 Итог оценки
- Текущая архитектура стала заметно лучше по управляемости зависимостей и изоляции ответственности.
- Главные риски сместились из “монолитного класса” в “размер composition/API surface и недотестированность orchestration”.
- При соблюдении guardrails (секция 12) и фокусе на тестах/дальнейшей локальной декомпозиции архитектура остается управляемой и не уходит в избыточную сложность.