Files
forkmessager/client-mobile/chats/ARCHITECTURE.md
T

168 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Архитектура 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<PagingData<Message>> =
repository.getMessagesPaging(chatId)
.cachedIn(viewModelScope)
}
```
### Офлайн отправка
```kotlin
// Сообщение сразу появится в UI
val message = repository.sendMessage(
chatId = chatId,
content = "Hello"
)
// Синхронизация произойдёт в фоне
```
## Миграции
При обновлении схемы БД используется миграция `MIGRATION_1_2`:
- Добавляет поля синхронизации
- Сохраняет существующие данные
- Устанавливает значения по умолчанию
## Тестирование
### Юнит-тесты
- MessageDao тесты
- MessageRemoteMediator тесты
- ChatRepositoryImpl тесты
### Интеграционные тесты
- Синхронизация с сервером
- Обработка конфликтов
- WorkManager сценарии