# Архитектура Offline-first для мессенджера Knot ## Обзор Система кэширования истории чатов реализует паттерн **Offline-first** с использованием: - **Room** - локальная база данных - **Paging 3** - пагинация с RemoteMediator - **WorkManager** - фоновая синхронизация - **SignalR** - real-time обновления ## Компоненты ### 1. Data Layer #### MessageEntity ```kotlin @Entity(tableName = "messages") data class MessageEntity( @PrimaryKey val id: String, val chatId: String, val senderId: String, val content: String?, val sequenceId: Int, val createdAt: String, // Поля синхронизации val syncStatus: SyncStatus, // SYNCED, SYNCING, FAILED val isDeletedLocally: Boolean, // Помечено на удаление val isEditedLocally: Boolean, // Помечено на редактирование val editedContent: String?, // Новое содержимое val lastUpdated: Long // Время последнего изменения ) ``` #### MessageDao Основные методы: - `getMessagesPagingSource()` - PagingSource для Paging 3 - `upsertMessage()` - Вставка/обновление с разрешением конфликтов - `markAsDeletedLocally()` - Пометка на удаление - `markAsEditedLocally()` - Пометка на редактирование - `getPendingSyncMessages()` - Получение сообщений для синхронизации ### 2. Pagination (Paging 3) #### MessageRemoteMediator Управляет загрузкой данных: - **REFRESH** - первая загрузка последних сообщений - **APPEND** - загрузка более старых сообщений (прокрутка вниз) - **PREPEND** - загрузка более новых сообщений (прокрутка вверх) Логика: 1. Проверяет наличие данных в Room 2. При необходимости загружает из API 3. Сохраняет в Room 4. Paging читает из локальной базы ### 3. Background Sync (WorkManager) #### MessageSyncWorker Обрабатывает отложенную синхронизацию: - Отправка новых сообщений (SYNCING) - Обновление отредактированных (isEditedLocally = true) - Удаление помеченных (isDeletedLocally = true) - Повтор при ошибках (FAILED) Политика повторных попыток: - Экспоненциальная задержка - Максимум 3 попытки - Требуется подключение к сети ### 4. Real-time Updates (SignalR) #### MessageSignalRHandler Обрабатывает события: - `new_message` - новое сообщение - `message_edited` - редактирование - `message_deleted` - удаление - `messages_read` - прочтение - `reaction_added/removed` - реакции Все изменения сразу записываются в Room → UI обновляется через Flow ### 5. Repository #### ChatRepositoryImpl Единая точка входа для ViewModel: - `getMessagesPaging()` - Paging 3 поток - `getMessagesFlow()` - простой Flow списка - `sendMessage()` - отправка с локальным сохранением - `deleteLocalMessage()` - локальное удаление - `editLocalMessage()` - локальное редактирование ## Conflict Resolution Приоритет данных: 1. **Сообщения в процессе отправки (SYNCING)** - локальные данные имеют приоритет 2. **Сообщения в процессе редактирования** - локальные данные имеют приоритет 3. **Все остальные случаи** - серверные данные имеют приоритет ## Схема работы ### Отправка сообщения ``` User → sendMessage() → Сохранение в Room (SYNCING) → UI показывает сообщение → WorkManager планирует синхронизацию → Отправка на сервер → Обновление статуса (SYNCED) ``` ### Получение сообщений ``` UI ← getMessagesPaging() ← Room ← RemoteMediator ← API ↑ └─── SignalR обновления ``` ### Удаление сообщения ``` User → deleteLocalMessage() → Пометка (isDeletedLocally = true) → WorkManager удаляет на сервере → Удаление из Room ``` ## Использование ### Paging 3 в ViewModel ```kotlin @HiltViewModel class ChatViewModel @Inject constructor( private val repository: ChatRepository ) : ViewModel() { val messages: Flow> = repository.getMessagesPaging(chatId) .cachedIn(viewModelScope) } ``` ### Офлайн отправка ```kotlin // Сообщение сразу появится в UI val message = repository.sendMessage( chatId = chatId, content = "Hello" ) // Синхронизация произойдёт в фоне ``` ## Миграции При обновлении схемы БД используется миграция `MIGRATION_1_2`: - Добавляет поля синхронизации - Сохраняет существующие данные - Устанавливает значения по умолчанию ## Тестирование ### Юнит-тесты - MessageDao тесты - MessageRemoteMediator тесты - ChatRepositoryImpl тесты ### Интеграционные тесты - Синхронизация с сервером - Обработка конфликтов - WorkManager сценарии