Files
forkmessager/client-mobile/chats/ARCHITECTURE.md
Халимов Рустам 7c66e1c0c0 Кэш чатов
2026-04-20 00:25:40 +03:00

6.1 KiB
Raw Blame History

Архитектура Offline-first для мессенджера Knot

Обзор

Система кэширования истории чатов реализует паттерн Offline-first с использованием:

  • Room - локальная база данных
  • Paging 3 - пагинация с RemoteMediator
  • WorkManager - фоновая синхронизация
  • SignalR - real-time обновления

Компоненты

1. Data Layer

MessageEntity

@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

@HiltViewModel
class ChatViewModel @Inject constructor(
    private val repository: ChatRepository
) : ViewModel() {
    
    val messages: Flow<PagingData<Message>> = 
        repository.getMessagesPaging(chatId)
            .cachedIn(viewModelScope)
}

Офлайн отправка

// Сообщение сразу появится в UI
val message = repository.sendMessage(
    chatId = chatId,
    content = "Hello"
)

// Синхронизация произойдёт в фоне

Миграции

При обновлении схемы БД используется миграция MIGRATION_1_2:

  • Добавляет поля синхронизации
  • Сохраняет существующие данные
  • Устанавливает значения по умолчанию

Тестирование

Юнит-тесты

  • MessageDao тесты
  • MessageRemoteMediator тесты
  • ChatRepositoryImpl тесты

Интеграционные тесты

  • Синхронизация с сервером
  • Обработка конфликтов
  • WorkManager сценарии