# Rosetta Android — Architecture > Документ отражает текущее состояние `rosetta-android` (ветка `dev`) по коду на 2026-04-18. ## 1. Архитектурный профиль Приложение сейчас устроено как layered + service-oriented архитектура: - UI: `MainActivity` + Compose-экраны + ViewModel. - DI: Hilt (`@HiltAndroidApp`, `@AndroidEntryPoint`, модули в `di/AppContainer.kt`). - Runtime orchestration: `ProtocolManager`, `CallManager`, `TransportManager`, `UpdateManager`. - Session/Identity runtime state: `SessionStore`, `SessionReducer`, `IdentityStore`. - Data: `MessageRepository`, `GroupRepository`, `AccountManager`, `PreferencesManager`. - Persistence: Room (`RosettaDatabase`) + DataStore/SharedPreferences. `ProtocolManager` остается крупным runtime orchestrator-объектом, но критичные зоны уже вынесены в отдельные сервисы. --- ## 2. Слои и границы ```mermaid flowchart TB subgraph ENTRY["Android Entry Points"] E1["RosettaApplication"] E2["MainActivity"] E3["RosettaFirebaseMessagingService"] E4["IncomingCallActivity / CallForegroundService"] end subgraph DI["Hilt Singleton Graph"] D1["ProtocolGateway"] D2["SessionCoordinator"] D3["IdentityGateway"] D4["AccountManager / PreferencesManager"] D5["MessageRepository / GroupRepository"] D6["UiEntryPoint + UiDependencyAccess"] end subgraph SESSION["Session / Identity Runtime"] S1["SessionStore"] S2["SessionReducer"] S3["IdentityStore"] S4["AppSessionCoordinator"] end subgraph NET["Network Runtime"] N1["ProtocolManager"] 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 SESSION --> NET DATA --> NET DATA --> R3 NET --> N2 ``` --- ## 3. DI и composition root ### 3.1 Hilt - `RosettaApplication` помечен `@HiltAndroidApp`. - Entry points уровня Android-компонентов: `MainActivity`, `IncomingCallActivity`, `CallForegroundService`, `RosettaFirebaseMessagingService`. - Основные модули: - `AppDataModule`: `AccountManager`, `PreferencesManager`. - `AppGatewayModule`: биндинги `ProtocolGateway`, `SessionCoordinator`, `IdentityGateway`. ### 3.2 UI bridge для не-Hilt классов Часть UI/VM пока получает зависимости через `UiDependencyAccess` -> `UiEntryPoint`. Это transitional-слой, чтобы не тащить singleton `getInstance(...)` в UI и постепенно перейти на чистый constructor injection. --- ## 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`. - Только `SessionReducer` вычисляет next-state. - `SessionCoordinator`/`AppSessionCoordinator` больше не мутируют состояние напрямую, а делают `dispatch(action)`. - `SessionStore.dispatch(...)` синхронно обновляет `IdentityStore` для консистентности account/profile/auth-runtime. ```mermaid 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"] C --> F["IdentityStore sync"] ``` ### 4.4 State machine ```mermaid 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 после декомпозиции `ProtocolManager` теперь делегирует отдельные зоны ответственности: - `ConnectionOrchestrator`: connect/reconnect/authenticate + network-aware поведение. - `BootstrapCoordinator`: пересчет lifecycle (`AUTHENTICATED`/`BOOTSTRAPPING`/`READY`) и работа с `ReadyPacketGate`. - `PacketRouter`: user/search cache + resolve/search continuation routing. - `OwnProfileSyncService`: применение собственного профиля из search и синхронизация `IdentityStore`. - `RetryQueueService`: retry очереди отправки `PacketMessage`. - `PacketSubscriptionRegistry`: централизованные подписки на пакеты и fan-out. ```mermaid flowchart TB PM["ProtocolManager"] --> CO["ConnectionOrchestrator"] PM --> BC["BootstrapCoordinator"] PM --> PR["PacketRouter"] PM --> OPS["OwnProfileSyncService"] PM --> RQ["RetryQueueService"] PM --> PSR["PacketSubscriptionRegistry"] PM --> SUP["ProtocolConnectionSupervisor"] PM --> RPG["ReadyPacketGate"] PM --> 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)`). ```mermaid sequenceDiagram participant Feature as Feature/Service participant PM as ProtocolManager 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. Отправка сообщений: use-cases + retry Из `ChatViewModel` выделены use-cases: - `SendTextMessageUseCase` - `SendMediaMessageUseCase` - `SendForwardUseCase` Текущий поток: 1. ViewModel готовит command и шифрованный payload. 2. UseCase собирает `PacketMessage`. 3. UseCase вызывает `protocolGateway.sendMessageWithRetry(packet)`. 4. `ProtocolManager` регистрирует пакет в `RetryQueueService` и отправляет в сеть. 5. Если lifecycle еще не `READY`, пакет попадает в `ReadyPacketGate` и flush после `READY`. ```mermaid flowchart LR VM["ChatViewModel"] --> UC["Send*UseCase"] UC --> GW["ProtocolGateway.sendMessageWithRetry"] GW --> PM["ProtocolManager"] PM --> RQ["RetryQueueService"] PM --> RG["ReadyPacketGate"] PM --> P["Protocol.sendPacket"] ``` --- ## 8. Auth/bootstrap: фактический runtime flow ```mermaid sequenceDiagram participant UI as Auth UI (SetPassword/Unlock) participant SC as SessionCoordinatorImpl participant SS as SessionStore participant PG as ProtocolGateway participant PM as ProtocolManager 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) PM-->>PM: HANDSHAKE -> AUTHENTICATED -> BOOTSTRAPPING PM-->>PM: SyncCompleted + OwnProfileResolved PM-->>PM: connectionLifecycleState = READY ``` Важно: `SessionState.Ready` (app-session готова) и `connectionLifecycleState = READY` (сеть готова) — это разные state-модели. --- ## 9. Состояния соединения (network lifecycle) `ProtocolManager.connectionLifecycleState`: - `DISCONNECTED` - `CONNECTING` - `HANDSHAKING` - `AUTHENTICATED` - `BOOTSTRAPPING` - `READY` - `DEVICE_VERIFICATION_REQUIRED` ```mermaid 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/di/UiEntryPoint.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/BootstrapCoordinator.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/usecase/SendTextMessageUseCase.kt` - `app/src/main/java/com/rosetta/messenger/ui/chats/usecase/SendMediaMessageUseCase.kt` - `app/src/main/java/com/rosetta/messenger/ui/chats/usecase/SendForwardUseCase.kt` --- ## 11. Что осталось как технический долг - `ProtocolManager` все еще содержит много cross-cutting логики и требует дальнейшей декомпозиции. - Не весь UI перешел на constructor injection (`UiDependencyAccess` пока нужен для части ViewModel). - Часть data-слоя напрямую знает о network singleton (`ProtocolManager`) и требует окончательного разрыва через интерфейсы.