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 -> 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(без отдельного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 --> 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:
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.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-классы:
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 (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.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 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:
DISCONNECTEDCONNECTINGHANDSHAKINGAUTHENTICATEDBOOTSTRAPPINGREADYDEVICE_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.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 строки): публичные 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,ProtocolManagerlegacy), что повышает 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 против переусложнения
Чтобы декомпозиция не превращалась в «архитектуру ради архитектуры», применяются следующие правила:
- Лимит глубины 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) и фокусе на тестах/дальнейшей локальной декомпозиции архитектура остается управляемой и не уходит в избыточную сложность.