Files
MCAdroidApp/CHAT_API_DOCUMENTATION.md
Viktoria Polyakova 9f8b968452 Updated
2026-01-30 16:58:30 +03:00

1237 lines
39 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.
# Chat API Documentation
## Обзор
Система чата является комплексным решением для обмена сообщениями в CRM системе, поддерживающим множественные провайдеры (WhatsApp, Telegram, Messenger и др.), персональные и групповые чаты, а также интеграцию с сущностями системы.
## Архитектура
### Компоненты системы
1. **Backend (NestJS)**
- REST API для управления чатами
- WebSocket для real-time сообщений
- Интеграция с внешними провайдерами
2. **Frontend (React/TypeScript)**
- Веб-интерфейс для управления чатами
- Модальные окна и встроенные компоненты
3. **Android приложение**
- Мобильный клиент для Android устройств
- Полная функциональность чата
4. **База данных**
- PostgreSQL с TypeORM
- Комплексная схема для чатов, сообщений, пользователей
## Backend API
### Детальная спецификация API
#### MultichatController (`/chat`)
Основной контроллер для общих операций с чатами.
```typescript
@ApiTags('multichat')
@Controller('chat')
@JwtAuthorized()
export class MultichatController {
// Получение количества непрочитанных сообщений
@Get('unseen-count')
async getUnseenCount(): Promise<number>
// Обновление статуса сообщений для всех чатов
@Put('status/:status')
async updateMessagesStatus()
}
```
##### GET /chat/unseen-count
**Описание:** Получить общее количество непрочитанных сообщений для текущего пользователя.
**Аутентификация:** JWT токен обязательна
**Параметры:** Нет
**Ответ:**
```json
{
"statusCode": 200,
"data": 5
}
```
##### PUT /chat/status/{status}
**Описание:** Обновить статус всех сообщений во всех чатах пользователя.
**Аутентификация:** JWT токен обязательна
**Параметры пути:**
- `status` (string): Новый статус (received/seen)
**Тело запроса:**
```json
{
"accountId": 1,
"user": {...},
"status": "seen"
}
```
**Ответ:**
```json
{
"statusCode": 200,
"message": "Messages status updated"
}
```
#### ChatController (`/chat/chats`)
Контроллер для операций с конкретными чатами.
**Создание чатов:**
- `POST /personal` - персональный чат
- `POST /group` - групповой чат
- `POST /external` - внешний чат
**Получение чатов:**
- `GET /` - список чатов с пагинацией
- `GET /find` - простой поиск
- `GET /find/full` - полный поиск с дополнительными данными
- `GET /find/full/personal` - поиск по имени пользователя
- `GET /find/full/by-message-content` - поиск по содержимому сообщений
- `GET /:chatId` - получение конкретного чата
**Управление чатами:**
- `PATCH /group/:chatId` - обновление группового чата
- `DELETE /:chatId` - удаление чата
- `PUT /:chatId/pin/:messageId` - закрепление сообщения
- `PUT /:chatId/unpin/:messageId` - открепление сообщения
- `PUT /:chatId/status/:status` - обновление статуса сообщений в чате
**Дополнительные операции:**
- `POST /:chatId/contact` - создание контакта и лида
#### ChatMessageController (`/chat/chats/:chatId/messages`)
Контроллер для работы с сообщениями в чате.
**Операции с сообщениями:**
- `POST /` - отправка сообщения
- `GET /` - получение списка сообщений
- `GET /:messageId` - получение конкретного сообщения
- `PUT /:messageId` - редактирование сообщения
- `DELETE /:messageId` - удаление сообщения
**Статусы сообщений:**
- `POST /status/:status` - обновление статуса нескольких сообщений
- `PUT /:messageId/status/:status` - обновление статуса одного сообщения
**Реакции:**
- `PUT /:messageId/react/:reaction` - добавление реакции
- `PUT /:messageId/unreact/:reactionId` - удаление реакции
#### ChatProviderController (`/chat/providers`)
Контроллер для работы с провайдерами чатов.
```typescript
@ApiTags('multichat/providers')
@Controller('chat/providers')
@JwtAuthorized()
export class ChatProviderController {
@Get()
async findMany(): Promise<ChatProviderDto[]>
}
```
### Модели данных
#### Chat (Чат)
```typescript
export class ChatDto {
id: number; // ID чата
providerId: number; // ID провайдера
createdBy: number; // ID создателя
externalId: string | null; // Внешний ID
type: ChatType; // Тип чата (PERSONAL/GROUP)
title: string | null; // Название
entityId: number | null; // ID связанной сущности
createdAt: string; // Дата создания
users: ChatUserDto[]; // Пользователи чата
pinnedMessages: ChatMessageDto[]; // Закрепленные сообщения
lastMessage: ChatMessageDto | null; // Последнее сообщение
unseenCount: number; // Количество непрочитанных
updatedAt: string; // Дата обновления
entityInfo: EntityInfoDto | null; // Информация о сущности
hasAccess?: boolean | null; // Доступ пользователя
}
```
#### ChatMessage (Сообщение)
```typescript
export class ChatMessageDto {
id: number; // ID сообщения
chatId: number; // ID чата
chatUserId: number; // ID пользователя чата
text: string | null; // Текст сообщения
replyToId: number | null; // ID сообщения-ответа
createdAt: string; // Дата создания
files: ChatMessageFileDto[]; // Прикрепленные файлы
reactions: ChatMessageReactionDto[]; // Реакции
status: ChatMessageStatus; // Статус для текущего пользователя
}
```
#### ChatUser (Пользователь чата)
```typescript
export class ChatUserDto {
id: number; // ID в чате
chatId: number; // ID чата
userId: number | null; // ID пользователя системы
role: ChatUserRole; // Роль в чате
name: string | null; // Имя
avatarUrl: string | null; // URL аватара
}
```
#### ChatProvider (Провайдер)
```typescript
export class ChatProviderDto {
id: number; // ID провайдера
type: ChatProviderType; // Тип провайдера
title: string; // Название
status: ChatProviderStatus; // Статус
transport: ChatProviderTransport; // Транспорт
unseenCount: number; // Непрочитанные сообщения
}
```
### Статусы и типы
#### ChatType
```typescript
export enum ChatType {
PERSONAL = 'personal', // Персональный чат между двумя пользователями
GROUP = 'group' // Групповой чат с множеством участников
}
```
#### ChatMessageStatus
```typescript
export enum ChatMessageStatus {
RECEIVED = 'received', // Сообщение получено
SEEN = 'seen' // Сообщение просмотрено
}
```
#### ChatProviderType
```typescript
export enum ChatProviderType {
Amwork = 'amwork', // Внутренняя система Amwork
Twilio = 'twilio', // Twilio WhatsApp
Facebook = 'facebook', // Facebook Messenger
Wazzup = 'wazzup' // Wazzup WhatsApp
}
```
#### ChatProviderTransport
```typescript
export enum ChatProviderTransport {
Amwork = 'amwork', // Внутренняя система
Whatsapp = 'whatsapp', // WhatsApp
Messenger = 'messenger', // Facebook Messenger
Telegram = 'telegram', // Telegram
Instagram = 'instagram', // Instagram
Vk = 'vk', // VKontakte
Avito = 'avito' // Avito
}
```
#### ChatProviderStatus
```typescript
export enum ChatProviderStatus {
Draft = 'draft', // Черновик настройки
Active = 'active', // Активен
Inactive = 'inactive', // Неактивен
Deleted = 'deleted' // Удален
}
```
#### ChatUserRole
```typescript
export enum ChatUserRole {
OWNER = 'owner', // Владелец чата
ADMIN = 'admin', // Администратор
SUPERVISOR = 'supervisor', // Супервайзер
USER = 'user', // Обычный пользователь
EXTERNAL = 'external' // Внешний пользователь
}
```
### DTOs для создания чатов
#### CreatePersonalChatDto
```typescript
export class CreatePersonalChatDto {
@ApiProperty({ description: 'Provider ID' })
@IsNumber()
providerId: number;
@ApiProperty({ description: 'User ID of chat companion' })
@IsNumber()
companionId: number;
}
```
**Пример запроса:**
```json
{
"providerId": 1,
"companionId": 123
}
```
#### CreateGroupChatDto
```typescript
export class CreateGroupChatDto {
@ApiProperty({ description: 'Provider ID' })
@IsNumber()
providerId: number;
@ApiProperty({ description: 'Chat title' })
@IsString()
title: string;
@ApiProperty({ description: 'User IDs of chat participants', type: [Number] })
@IsArray()
participantIds: number[];
@ApiPropertyOptional({ description: 'Entity ID associated with the chat', nullable: true })
@IsOptional()
@IsNumber()
entityId?: number | null;
}
```
**Пример запроса:**
```json
{
"providerId": 1,
"title": "Проект Alpha",
"participantIds": [123, 456, 789],
"entityId": 1001
}
```
### DTOs для сообщений
#### SendChatMessageDto
```typescript
export class SendChatMessageDto {
@ApiPropertyOptional()
@IsOptional()
@IsNumber()
replyToId?: number | null;
@ApiProperty()
@IsString()
text: string;
@ApiPropertyOptional({ nullable: true })
@IsOptional()
@IsArray()
fileIds?: string[] | null;
}
```
**Пример запроса:**
```json
{
"text": "Привет, как дела?",
"replyToId": 123,
"fileIds": ["file_123", "file_456"]
}
```
## База данных
### Основные таблицы
#### chat
```sql
CREATE TABLE public.chat (
id integer NOT NULL,
provider_id integer NOT NULL,
created_by integer,
external_id character varying,
type character varying NOT NULL,
title character varying,
entity_id integer,
account_id integer NOT NULL,
created_at timestamp without time zone NOT NULL
);
```
#### chat_message
```sql
CREATE TABLE public.chat_message (
id integer NOT NULL,
chat_id integer NOT NULL,
chat_user_id integer NOT NULL,
external_id character varying,
text text,
account_id integer NOT NULL,
created_at timestamp without time zone NOT NULL,
reply_to_id integer
);
```
#### chat_user
```sql
CREATE TABLE public.chat_user (
id integer NOT NULL,
chat_id integer NOT NULL,
user_id integer,
role character varying NOT NULL,
account_id integer NOT NULL
);
```
#### chat_provider
```sql
CREATE TABLE public.chat_provider (
id integer NOT NULL,
created_by integer,
type character varying NOT NULL,
title character varying NOT NULL,
account_id integer NOT NULL,
created_at timestamp without time zone NOT NULL,
status character varying NOT NULL,
transport character varying NOT NULL
);
```
#### chat_message_reaction
```sql
CREATE TABLE public.chat_message_reaction (
id integer NOT NULL,
message_id integer NOT NULL,
chat_user_id integer NOT NULL,
reaction character varying NOT NULL,
account_id integer NOT NULL,
created_at timestamp without time zone NOT NULL
);
```
#### chat_message_user_status
```sql
CREATE TABLE public.chat_message_user_status (
chat_id integer NOT NULL,
message_id integer NOT NULL,
chat_user_id integer NOT NULL,
status character varying NOT NULL,
account_id integer NOT NULL,
created_at timestamp without time zone NOT NULL
);
```
## Frontend
### Архитектура компонентов
Система чата построена на базе React с использованием контекстов для управления состоянием и кастомных хуков для работы с API.
#### MultichatProvider
Контекст-провайдер для глобального управления состоянием чата в приложении.
**Ключевые свойства:**
```typescript
interface MultichatContextValue {
// Видимость модальных окон
opened: boolean;
pageOpened: boolean;
hide: () => void;
toggle: () => void;
// Активный чат
activeChatId: number | null;
activeProviderId: number | null;
setActiveChatId: (id: number | null) => void;
setActiveProviderId: (id: number | null) => void;
// Управление сообщениями
editMessageId: number | null;
replyToId: number | null;
setEditMessageId: (id: number | null) => void;
setReplyToId: (id: number | null) => void;
// Навигация
show: (params: { activeChatId?: number; activeProviderId?: number }) => void;
openPage: (returnUrl?: string) => void;
closePage: () => void;
}
```
**Использование:**
```tsx
const { show, opened, activeChatId } = useMultichatContext();
// Открыть чат
show({ activeChatId: 123, activeProviderId: 1 });
// Проверить видимость
if (opened) {
// Показать модальное окно
}
```
#### MultichatModal
Модальное окно для отображения интерфейса чата в модальном режиме.
**Особенности:**
- Перетаскиваемое и изменяемое по размеру
- Адаптивный дизайн
- Сохранение позиции и размера
- Интеграция с основным UI
**Props:**
```typescript
interface MultichatModalProps {
children?: ReactNode;
modalBounds?: DraggableResizableControlBounds;
setModalBounds?: (bounds: DraggableResizableControlBounds) => void;
}
```
#### MultichatControl
Основной контейнер управления чатом с боковой панелью и областью сообщений.
**Структура:**
```
MultichatControl
├── MultichatControlHeader (при модальном просмотре)
├── ChatsSidebar
│ ├── ChatList
│ ├── CreateAmworkChatButton
│ └── ProviderSelector
└── ChatMessagesPanel
├── ChatMessagesPanelHeader
├── ChatMessagesList
└── SendChatMessageBlock
```
#### ChatMessagesPanel
Компонент для отображения и управления сообщениями в чате.
**Ключевые функции:**
- Ленивая загрузка сообщений
- Автоматическая прокрутка к новым сообщениям
- Отметка сообщений как прочитанные
- Обработка реакций и ответов
**Props:**
```typescript
interface ChatMessagesPanelProps {
activeChatId: number;
mobileView?: boolean;
providers?: ChatProvider[];
activeProvider?: ChatProvider;
modalWidth?: string;
onBack?: () => void;
}
```
#### SendChatMessageBlock
Компонент для отправки сообщений с поддержкой различных типов контента.
**Возможности:**
- Текстовые сообщения
- Файловые вложения (drag & drop)
- Ответы на сообщения
- Редактирование сообщений
- Отправка через Enter или кнопку
**Состояния:**
- Обычное сообщение
- Ответ на сообщение
- Редактирование сообщения
- Отправка файла
### Кастомные хуки
#### useGetChat
Получение данных о конкретном чате.
```typescript
const { data: chat, isLoading, error } = useGetChat(chatId);
```
#### useGetChatMessages
Получение сообщений чата с пагинацией.
```typescript
const {
data: messages,
hasNextPage,
fetchNextPage,
isLoading
} = useGetChatMessages(chatId);
```
#### useSendChatMessage
Отправка сообщений в чат.
```typescript
const { mutateAsync: sendMessage, isPending } = useSendChatMessage({
chatId,
providerId
});
// Отправка
await sendMessage({
text: "Привет!",
fileIds: ["file_123"]
});
```
#### useCreateGroupChat
Создание группового чата.
```typescript
const { mutateAsync: createChat } = useCreateGroupChat();
// Создание
const newChat = await createChat({
providerId: 1,
title: "Новый проект",
participantIds: [123, 456]
});
```
### API интеграция
#### ChatApi
Основной API клиент для работы с чатами:
```typescript
export const chatApi = {
// Получение чатов
getChats: (params: CursorPagingQuery) =>
api.get('/chat/chats', { params }),
getChat: (chatId: number) =>
api.get(`/chat/chats/${chatId}`),
// Создание чатов
createPersonalChat: (data: CreatePersonalChatDto) =>
api.post('/chat/chats/personal', data),
createGroupChat: (data: CreateGroupChatDto) =>
api.post('/chat/chats/group', data),
createExternalChat: (data: CreateExternalChatDto) =>
api.post('/chat/chats/external', data),
// Поиск чатов
findChats: (params: { filter: ChatFindFilterDto; paging: PagingQuery }) =>
api.get('/chat/chats/find', { params }),
findChatsFull: (params: { filter: ChatFindFilterDto; paging: PagingQuery }) =>
api.get('/chat/chats/find/full', { params }),
// Сообщения
getChatMessages: (chatId: number, params: ChatMessagesFilterDto & PagingQuery) =>
api.get(`/chat/chats/${chatId}/messages`, { params }),
sendMessage: (chatId: number, data: SendChatMessageDto) =>
api.post(`/chat/chats/${chatId}/messages`, data),
updateMessage: (chatId: number, messageId: number, data: SendChatMessageDto) =>
api.put(`/chat/chats/${chatId}/messages/${messageId}`, data),
deleteMessage: (chatId: number, messageId: number) =>
api.delete(`/chat/chats/${chatId}/messages/${messageId}`),
// Статусы
markAllChatMessagesAsRead: (chatId: number) =>
api.put(`/chat/chats/${chatId}/status/read`),
updateMessageStatus: (chatId: number, messageId: number, status: ChatMessageStatus) =>
api.put(`/chat/chats/${chatId}/messages/${messageId}/status/${status}`),
// Реакции
reactToMessage: (chatId: number, messageId: number, reaction: string) =>
api.put(`/chat/chats/${chatId}/messages/${messageId}/react/${reaction}`),
unreactToMessage: (chatId: number, messageId: number, reactionId: number) =>
api.put(`/chat/chats/${chatId}/messages/${messageId}/unreact/${reactionId}`),
// Управление чатами
updateGroupChat: (chatId: number, data: UpdateGroupChatDto) =>
api.patch(`/chat/chats/group/${chatId}`, data),
deleteChat: (chatId: number) =>
api.delete(`/chat/chats/${chatId}`),
pinMessage: (chatId: number, messageId: number) =>
api.put(`/chat/chats/${chatId}/pin/${messageId}`),
unpinMessage: (chatId: number, messageId: number) =>
api.put(`/chat/chats/${chatId}/unpin/${messageId}`),
// Провайдеры
getChatProviders: () =>
api.get('/chat/providers'),
// Счетчики
getUnseenCount: () =>
api.get('/chat/unseen-count'),
};
```
### React Query интеграция
Система использует React Query для кеширования и синхронизации данных:
```typescript
// Ключи запросов
export const MULTICHAT_QUERY_KEYS = {
chats: ['multichat', 'chats'] as const,
chat: (chatId: number) => ['multichat', 'chats', chatId] as const,
chatMessages: (chatId: number) => ['multichat', 'chats', chatId, 'messages'] as const,
chatProviders: ['multichat', 'providers'] as const,
unseenCount: ['multichat', 'unseen-count'] as const,
} as const;
// Инвалидация кеша
queryClient.invalidateQueries({ queryKey: MULTICHAT_QUERY_KEYS.chats });
```
### Стилизация
Компоненты используют styled-components с поддержкой тем:
```typescript
const Root = styled.div`
background-color: var(--graphite-graphite-20);
border-radius: 8px;
${p => p.$mobileView && css`
width: calc(100vw - var(--sidebar-width));
`}
`;
```
### Обработка событий
Система поддерживает real-time обновления через WebSocket события:
```typescript
// Обработчик событий чата
const chatEventHandler = {
subscribe: (context: MultichatContextValue) => {
// Подписка на события
},
unsubscribe: () => {
// Отписка от событий
}
};
```
## Android приложение
### Архитектура
Приложение построено на базе **MVVM** архитектуры с использованием **Android Architecture Components**:
- **Activities/Fragments** - представление данных
- **ViewModels** - бизнес-логика и управление состоянием
- **Repositories** - абстракция доступа к данным
- **Retrofit** - HTTP клиент для API
- **Room** - локальная база данных (опционально)
- **WorkManager** - фоновая синхронизация
### Основные Activity
#### ChatActivity
Основная активность для отображения чата с полным жизненным циклом управления.
**Жизненный цикл:**
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityChatBinding.inflate(layoutInflater)
setContentView(binding.root)
// Инициализация ViewModel
viewModel.initialize(serverUrl, token, apiKey, chatId)
// Настройка UI компонентов
setupViews()
observeViewModel()
observeAddressBook()
}
override fun onResume() {
super.onResume()
viewModel.setChatActive(true) // Активация чата
}
override fun onPause() {
super.onPause()
viewModel.setChatActive(false) // Деактивация чата
}
```
**Основные функции:**
- Отображение списка сообщений с `RecyclerView`
- Отправка текстовых сообщений
- Отправка файлов через `FilePicker`
- Ответы на сообщения с визуальным индикатором
- Автоматическая отметка сообщений как прочитанные при прокрутке
- Управление прикрепленными файлами
**Ключевые компоненты:**
- `MessageAdapter` - адаптер для `RecyclerView` с поддержкой разных типов сообщений
- `ChatViewModel` - управление состоянием чата и бизнес-логикой
- `NotificationHelper` - обработка push-уведомлений
- `BackgroundSyncWorker` - фоновая синхронизация
#### MainActivity
Главная активность с навигацией и списком чатов.
**Особенности:**
- `BottomNavigationView` для переключения разделов
- `SwipeRefreshLayout` для обновления списка чатов
- `FloatingActionButton` для создания новых чатов
- Управление жизненным циклом всех чатов
#### CreateChatActivity
Активность для создания новых чатов с пошаговым мастером.
**Этапы создания:**
1. Выбор типа чата (персональный/групповой)
2. Выбор участников через `UserSelectionActivity`
3. Настройка параметров чата
4. Создание и переход к чату
### ViewModels
#### ChatViewModel
Управляет состоянием конкретного чата и сообщениями.
**Состояния:**
```kotlin
sealed class ChatState {
object Loading : ChatState()
data class Success(val chat: Chat) : ChatState()
data class Error(val message: String) : ChatState()
}
sealed class MessagesState {
object Loading : MessagesState()
data class Success(val messages: List<ChatMessage>) : MessagesState()
data class Error(val message: String) : MessagesState()
}
sealed class SendMessageState {
object Loading : SendMessageState()
object Success : SendMessageState()
data class Error(val message: String) : SendMessageState()
}
```
**Ключевые методы:**
```kotlin
// Загрузка данных чата
fun refreshChat()
// Загрузка сообщений
fun refreshMessages()
// Отправка сообщения
fun sendMessage(text: String, replyToMessage: ChatMessage?, fileIds: List<String>? = null)
// Отправка файла
fun sendFileMessage(uri: Uri, contentResolver: ContentResolver)
// Отметка как прочитанное
fun markMessagesAsRead()
// Управление активностью чата
fun setChatActive(active: Boolean)
```
#### MainViewModel
Глобальная ViewModel для управления приложением.
**Функции:**
- Управление списком чатов
- Кеширование данных пользователей (адресная книга)
- Синхронизация состояния между активностями
- Управление подключением к серверу
**Ключевые методы:**
```kotlin
// Получение имени пользователя
fun getUserName(userId: Long): String
// Получение URL аватара
fun getUserAvatarUrl(userId: Long): String?
// Уведомление об обновлении чата
fun notifyChatUpdated(chatId: Long)
// Управление адресной книгой
fun refreshAddressBook()
```
### Репозитории
#### ChatRepository
Репозиторий для работы с API чатов с поддержкой кеширования.
**Основные методы:**
```kotlin
suspend fun getChats(): Result<List<Chat>>
suspend fun getChat(chatId: Long): Result<Chat>
suspend fun getMessages(chatId: Long, limit: Int = 50, offset: Long? = null): Result<List<ChatMessage>>
suspend fun sendMessage(chatId: Long, message: SendChatMessageDto): Result<ChatMessage>
suspend fun uploadFile(uri: Uri, contentResolver: ContentResolver): Result<List<UploadedFile>>
suspend fun markAsRead(chatId: Long): Result<Unit>
suspend fun updateMessageStatus(chatId: Long, messageId: Long, status: ChatMessageStatus): Result<Unit>
```
**Обработка ошибок:**
```kotlin
sealed class Result<T> {
data class Success<T>(val data: T) : Result<T>()
data class Failure<T>(val exception: Throwable) : Result<T>()
}
```
### Модели данных
#### ChatRequests.kt
DTO для запросов к API:
```kotlin
data class CreatePersonalChatRequest(
val providerId: Long,
val companionId: Long
)
data class CreateGroupChatRequest(
val providerId: Long,
val title: String,
val participantIds: List<Long>,
val entityId: Long? = null
)
data class UpdateGroupChatRequest(
val title: String? = null,
val participantIds: List<Long>? = null
)
```
#### ChatModels.kt
Основные модели данных приложения:
```kotlin
data class Chat(
val id: Long,
val providerId: Long,
val type: String,
val title: String?,
val users: List<ChatUserItem>,
val lastMessage: ChatMessage?,
val unseenCount: Int,
val createdAt: String
)
data class ChatMessage(
val id: Long,
val chatId: Long,
val chatUserId: Long,
val text: String?,
val replyToId: Long?,
val files: List<ChatMessageFile>,
val reactions: List<ChatMessageReaction>,
val status: ChatMessageStatus,
val createdAt: String
)
data class ChatUserItem(
val id: Long,
val userId: Long?,
val name: String?,
val avatarUrl: String?
)
```
### UI Компоненты
#### MessageAdapter
Адаптер для отображения сообщений в `RecyclerView`.
**Типы ViewHolder:**
- `TextMessageViewHolder` - текстовые сообщения
- `FileMessageViewHolder` - сообщения с файлами
- `ReplyMessageViewHolder` - ответы на сообщения
- `SystemMessageViewHolder` - системные сообщения
**Особенности:**
- Поддержка разных типов сообщений через `getItemViewType()`
- Оптимизация производительности с `DiffUtil`
- Обработка кликов и долгого нажатия
- Анимации для новых сообщений
#### MessageAdapter.kt
```kotlin
class MessageAdapter(
private val getUserName: (Long) -> String,
private val chatUsers: List<ChatUserItem>?,
private val onScrollToMessage: (Long) -> Unit,
private val onReplyToMessage: (ChatMessage) -> Unit,
private val serverUrl: String,
private val token: String?,
private val apiKey: String?
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val messages = mutableListOf<ChatMessage>()
fun submitList(newMessages: List<ChatMessage>) {
val diffResult = DiffUtil.calculateDiff(MessageDiffCallback(messages, newMessages))
messages.clear()
messages.addAll(newMessages)
diffResult.dispatchUpdatesTo(this)
}
}
```
### Background Sync
#### BackgroundSyncWorker
Worker для фоновой синхронизации данных.
**Функции:**
- Периодическая проверка новых сообщений
- Обновление уведомлений
- Синхронизация аватаров пользователей
- Обработка оффлайн режима
**Конфигурация:**
```kotlin
val syncWork = PeriodicWorkRequestBuilder<BackgroundSyncWorker>(
15, TimeUnit.MINUTES // Синхронизация каждые 15 минут
)
.addConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
```
### Уведомления
#### NotificationHelper
Управление push-уведомлениями и локальными уведомлениями.
**Функции:**
- Создание уведомлений о новых сообщениях
- Группировка уведомлений по чатам
- Кастомные звуки и вибрация
- Deep linking в конкретные чаты
```kotlin
fun showMessageNotification(
chatId: Long,
message: ChatMessage,
senderName: String,
chatTitle: String
) {
val intent = Intent(context, ChatActivity::class.java).apply {
putExtra("chat_id", chatId)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
context, chatId.toInt(), intent, PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle(chatTitle)
.setContentText("$senderName: ${message.text}")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
notificationManager.notify(chatId.toInt(), notification)
}
```
### Работа с файлами
#### File Handling
Обработка загрузки и отображения файлов.
**Поддерживаемые операции:**
- Выбор файлов через `Intent.ACTION_GET_CONTENT`
- Загрузка файлов на сервер
- Отображение превью изображений
- Скачивание файлов
- Управление разрешениями на хранение
```kotlin
private fun uploadFileAndSendMessage(message: String) {
selectedFileUri?.let { uri ->
lifecycleScope.launch {
try {
val result = ChatRepository(apiClient).uploadFile(uri, contentResolver)
result.fold(
onSuccess = { files ->
viewModel.sendMessage(message, replyingToMessage, files.map { it.id })
clearFileSelection()
},
onFailure = { error ->
Toast.makeText(this@ChatActivity, "Upload failed: ${error.message}", Toast.LENGTH_SHORT).show()
}
)
} catch (e: Exception) {
Toast.makeText(this@ChatActivity, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
```
### Темизация и локализация
**Поддержка тем:**
- Светлая тема
- Темная тема
- Системная тема
**Локализация:**
- Русский язык
- Английский язык
- Поддержка RTL для арабского и иврита
### Производительность
**Оптимизации:**
- ViewBinding вместо findViewById
- DiffUtil для RecyclerView
- Кеширование изображений с Glide
- Пейджинг для больших списков
- Background threading для тяжелых операций
## Интеграция с внешними провайдерами
### Поддерживаемые провайдеры
1. **Facebook Messenger**
- Требует: `page_id`, `page_access_token`, `user_access_token`
- Транспорт: `messenger`
2. **Telegram**
- Интеграция через Telegram API
3. **WhatsApp (Twilio)**
- Требует: `account_sid`, `auth_token`, `phone_number`
- Транспорт: `whatsapp`
4. **Whazzup**
- Требует: `api_key`, `channel_id`, `plain_id`
- Транспорт: `whatsapp`
### Настройка провайдеров
Провайдеры настраиваются через интерфейс интеграций в разделе "Settings > Integrations".
## Безопасность
### Аутентификация
- JWT токены для API запросов
- Проверка прав доступа на уровне аккаунта
- Валидация принадлежности пользователя к чату
### Авторизация
- Проверка доступа к чатам
- Ролевая модель для групповых чатов
- Ограничение действий с сообщениями
## Real-time обновления
### WebSocket
- Автоматическое обновление сообщений
- Статусы прочтения в реальном времени
- Уведомления о новых сообщениях
### Background Sync (Android)
- `BackgroundSyncWorker` для синхронизации в фоне
- Обновление уведомлений
- Синхронизация аватаров пользователей
## Файловые вложения
### Поддерживаемые форматы
- Изображения, документы, видео, аудио
- Максимальный размер файла настраивается
### Загрузка файлов
- Backend: хранение в файловом хранилище
- Frontend: drag & drop, выбор файла
- Android: выбор из галереи/файлового менеджера
### Безопасность файлов
- Валидация MIME типов
- Сканирование на вирусы (опционально)
- Ограничение доступа по ссылкам
## Поиск и фильтрация
### Поиск чатов
- По имени пользователя (персональные чаты)
- По содержимому сообщений
- По связанным сущностям
- Фильтрация по провайдеру
### Полнотекстовый поиск
- Индексы в базе данных
- Поиск по тексту сообщений
- Поддержка регулярных выражений
## Мониторинг и логирование
### Метрики
- Количество активных чатов
- Статистика сообщений
- Производительность API
### Логи
- Детальное логирование API запросов
- Ошибки интеграции с провайдерами
- Аудит действий пользователей
## Расширение системы
### Добавление нового провайдера
1. Создать конфигурацию провайдера в базе данных
2. Реализовать интеграцию в `ChatProviderService`
3. Добавить DTO для настроек
4. Создать миграцию для новой таблицы провайдера
5. Обновить UI для настройки
### Кастомизация UI
- Темизация компонентов
- Кастомные аватары
- Дополнительные поля в сообщениях
## Заключение
Система чата предоставляет полнофункциональное решение для коммуникации в CRM, поддерживая множественные каналы связи, real-time обновления и интеграцию с бизнес-логикой системы. Архитектура обеспечивает масштабируемость, безопасность и гибкость для будущих расширений.