1054 lines
42 KiB
Markdown
1054 lines
42 KiB
Markdown
[Назад](/README.md)
|
||
|
||
# Архитектура системы TaskManager
|
||
|
||
## Содержание
|
||
1. [Общее описание](#общее-описание)
|
||
2. [Архитектурные принципы](#архитектурные-принципы)
|
||
3. [Компоненты системы](#компоненты-системы)
|
||
4. [Микросервисы](#микросервисы)
|
||
5. [Модель данных](#модель-данных)
|
||
6. [Коммуникация между сервисами](#коммуникация-между-сервисами)
|
||
7. [Контракт сообщений](#контракт-сообщений)
|
||
8. [Безопасность и авторизация](#безопасность-и-авторизация)
|
||
9. [Масштабирование](#масштабирование)
|
||
10. [Технологический стек](#технологический-стек)
|
||
|
||
---
|
||
|
||
## Общее описание
|
||
|
||
TaskManager - это интеграционная платформа для управления задачами между различными подразделениями отеля и внешними системами. Система выступает в роли мастер-приложения, объединяющего разрозненные системы (PMS, ERP, системы управления уборкой и т.д.) через адаптеры.
|
||
|
||
### Ключевые особенности:
|
||
- **Мультитенантность**: поддержка нескольких отелей одного владельца (1-50+ отелей)
|
||
- **Модульность**: возможность продажи отдельных модулей (базовый функционал, модуль мероприятий, модуль уборки и т.д.)
|
||
- **Расширяемость**: простота добавления новых адаптеров для интеграции с внешними системами
|
||
- **Гибкость**: настраиваемые роли, статусы задач, правила маршрутизации
|
||
|
||
---
|
||
|
||
## Архитектурные принципы
|
||
|
||
### 1. Микросервисная архитектура
|
||
Система построена на микросервисах, каждый из которых отвечает за свою domain-область.
|
||
|
||
### 2. Event-Driven Architecture
|
||
Использование Apache Kafka для асинхронной коммуникации и обработки событий.
|
||
|
||
### 3. Адаптер-паттерн для интеграций
|
||
Каждая внешняя система имеет свой адаптер, который:
|
||
- Преобразует данные внешней системы в стандартизированный формат
|
||
- Работает как по push, так и по pull модели (в зависимости от возможностей внешней системы)
|
||
- Изолирует логику интеграции от бизнес-логики
|
||
|
||
### 4. API Gateway
|
||
Единая точка входа для клиентских приложений с поддержкой:
|
||
- REST API для простых запросов
|
||
- gRPC для высокопроизводительной коммуникации
|
||
- WebSocket для real-time обновлений
|
||
|
||
### 5. CQRS (Command Query Responsibility Segregation)
|
||
Разделение операций чтения и записи для повышения производительности.
|
||
|
||
---
|
||
|
||
## Компоненты системы
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Client Layer │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ Web Admin │ Mobile Apps │ External Systems │ Telegram Bot│
|
||
└──────┬────────────┬─────────────────┬────────────────┬──────────┘
|
||
│ │ │ │
|
||
└────────────┴─────────────────┴────────────────┘
|
||
│
|
||
┌───────────────────────────┼───────────────────────────────────────┐
|
||
│ API Gateway Layer │
|
||
├───────────────────────────┴───────────────────────────────────────┤
|
||
│ REST API │ gRPC │ WebSocket │
|
||
└───────────────────────────┬───────────────────────────────────────┘
|
||
│
|
||
┌───────────────────────────┼───────────────────────────────────────┐
|
||
│ Service Layer │
|
||
├───────────────────────────┴───────────────────────────────────────┤
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ Tasks │ │ Connections │ │ Users │ │
|
||
│ │ Service │ │ Service │ │ Service │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │Notification │ │ File Storage │ │ Audit │ │
|
||
│ │ Service │ │ Service │ │ Service │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ Scheduler │ │ Permissions │ │ Events │ │
|
||
│ │ Service │ │ Service │ │ Service │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
└───────────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌───────────────────────────┼───────────────────────────────────────┐
|
||
│ Message Broker (Kafka) │
|
||
├───────────────────────────┴───────────────────────────────────────┤
|
||
│ Topics: tasks.created, tasks.updated, tasks.completed, │
|
||
│ notifications.send, audit.log, etc. │
|
||
└───────────────────────────┬───────────────────────────────────────┘
|
||
│
|
||
┌───────────────────────────┼───────────────────────────────────────┐
|
||
│ Adapter Layer │
|
||
├───────────────────────────┴───────────────────────────────────────┤
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │PMS Adapter │ │ERP Adapter │ │Housekeeping │ │
|
||
│ │ (Opera/...) │ │ │ │ Adapter │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │Telegram Bot │ │ Custom │ │ Custom │ │
|
||
│ │ Adapter │ │ Adapter #N │ │ Adapter #M │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
└───────────────────────────┬───────────────────────────────────────┘
|
||
│
|
||
┌───────────────────────────┼───────────────────────────────────────┐
|
||
│ Data Layer │
|
||
├───────────────────────────┴───────────────────────────────────────┤
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ PostgreSQL │ │ Redis │ │ S3 │ │
|
||
│ │ (Main DB) │ │ (Cache) │ │ (File Store) │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
└───────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## Микросервисы
|
||
|
||
### 1. API Gateway
|
||
**Назначение**: Единая точка входа для всех клиентских приложений
|
||
|
||
**Ответственность**:
|
||
- Маршрутизация запросов к соответствующим микросервисам
|
||
- Аутентификация и авторизация
|
||
- Rate limiting
|
||
- Request/Response трансформация
|
||
- Логирование запросов
|
||
|
||
**Технологии**: Kong / Envoy / NGINX + gRPC Gateway
|
||
|
||
**Endpoints**:
|
||
- REST API: `/api/v1/*`
|
||
- gRPC: порт 50051
|
||
- WebSocket: `/ws/*`
|
||
|
||
---
|
||
|
||
### 2. Tasks Service
|
||
**Назначение**: Управление жизненным циклом задач
|
||
|
||
**Ответственность**:
|
||
- CRUD операции с задачами
|
||
- Управление статусами задач (с поддержкой кастомных статусов)
|
||
- Управление зависимостями между задачами
|
||
- Назначение исполнителей
|
||
- Версионирование задач (история изменений)
|
||
- Прикрепление файлов к задачам
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `tasks`, `task_statuses`, `task_dependencies`, `task_history`, `task_attachments`
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `tasks.created`, `tasks.updated`, `tasks.status_changed`, `tasks.completed`, `tasks.cancelled`
|
||
- Подписан на: `scheduler.task_trigger`, `connections.route_task`
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service TaskService {
|
||
rpc CreateTask(CreateTaskRequest) returns (Task);
|
||
rpc UpdateTask(UpdateTaskRequest) returns (Task);
|
||
rpc GetTask(GetTaskRequest) returns (Task);
|
||
rpc ListTasks(ListTasksRequest) returns (ListTasksResponse);
|
||
rpc ChangeTaskStatus(ChangeStatusRequest) returns (Task);
|
||
rpc AddDependency(AddDependencyRequest) returns (TaskDependency);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. Connections Service
|
||
**Назначение**: Управление связями между системами и правилами маршрутизации
|
||
|
||
**Ответственность**:
|
||
- Хранение конфигурации связей между адаптерами
|
||
- Определение правил маршрутизации сообщений
|
||
- Динамическое обновление правил без перезапуска
|
||
- Валидация связей
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `connections`, `routing_rules`, `adapters`
|
||
|
||
**Модель связи** (направленная):
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"source_adapter_id": "uuid",
|
||
"target_adapter_id": "uuid",
|
||
"routing_rules": [
|
||
{
|
||
"condition": "task_type == 'cleaning'",
|
||
"action": "route",
|
||
"enabled": true
|
||
}
|
||
],
|
||
"enabled": true,
|
||
"created_at": "timestamp",
|
||
"updated_at": "timestamp"
|
||
}
|
||
```
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `connections.updated`, `connections.route_task`
|
||
- Подписан на: `tasks.created`, `adapters.message_received`
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service ConnectionService {
|
||
rpc CreateConnection(CreateConnectionRequest) returns (Connection);
|
||
rpc UpdateConnection(UpdateConnectionRequest) returns (Connection);
|
||
rpc DeleteConnection(DeleteConnectionRequest) returns (Empty);
|
||
rpc ListConnections(ListConnectionsRequest) returns (ListConnectionsResponse);
|
||
rpc RouteMessage(RouteMessageRequest) returns (RouteMessageResponse);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. Users Service
|
||
**Назначение**: Управление пользователями и их профилями
|
||
|
||
**Ответственность**:
|
||
- CRUD операции с пользователями
|
||
- Управление профилями
|
||
- Привязка к отелям и подразделениям
|
||
- Хранение настроек пользователя
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `users`, `user_profiles`, `user_hotels`, `departments`
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `users.created`, `users.updated`, `users.deleted`
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service UserService {
|
||
rpc CreateUser(CreateUserRequest) returns (User);
|
||
rpc GetUser(GetUserRequest) returns (User);
|
||
rpc UpdateUser(UpdateUserRequest) returns (User);
|
||
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 5. Permissions Service
|
||
**Назначение**: Управление ролями и правами доступа (RBAC)
|
||
|
||
**Ответственность**:
|
||
- Управление ролями (с поддержкой кастомных ролей на уровне отеля)
|
||
- Управление правами доступа
|
||
- Проверка прав доступа
|
||
- Привязка пользователей к ролям
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `roles`, `permissions`, `role_permissions`, `user_roles`
|
||
|
||
**Предопределенные роли**:
|
||
- `system_admin` - системный администратор
|
||
- `support` - техническая поддержка
|
||
- `hotel_admin` - администратор отеля
|
||
- `department_head` - руководитель подразделения
|
||
- `worker` - сотрудник
|
||
|
||
**Кастомные роли**: отель может создавать свои роли на основе базовых
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service PermissionService {
|
||
rpc CreateRole(CreateRoleRequest) returns (Role);
|
||
rpc AssignRole(AssignRoleRequest) returns (UserRole);
|
||
rpc CheckPermission(CheckPermissionRequest) returns (PermissionResponse);
|
||
rpc ListRoles(ListRolesRequest) returns (ListRolesResponse);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 6. Notification Service
|
||
**Назначение**: Отправка уведомлений через различные каналы
|
||
|
||
**Ответственность**:
|
||
- Отправка Email
|
||
- Отправка Push-уведомлений
|
||
- Отправка SMS
|
||
- Отправка сообщений в Telegram
|
||
- Отправка сообщений в другие мессенджеры (WhatsApp, Viber и т.д.)
|
||
- Управление шаблонами уведомлений
|
||
- Управление подписками пользователей
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `notification_templates`, `notification_subscriptions`, `notification_log`
|
||
|
||
**Kafka Topics**:
|
||
- Подписан на: `notifications.send`, `tasks.created`, `tasks.assigned`, `tasks.completed`
|
||
|
||
**Интеграции**:
|
||
- Email: SMTP
|
||
- Push: Firebase Cloud Messaging (FCM) / Apple Push Notification Service (APNS)
|
||
- SMS: Twilio / другие провайдеры
|
||
- Telegram: Telegram Bot API
|
||
- WhatsApp: WhatsApp Business API
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service NotificationService {
|
||
rpc SendNotification(SendNotificationRequest) returns (NotificationResponse);
|
||
rpc CreateTemplate(CreateTemplateRequest) returns (Template);
|
||
rpc Subscribe(SubscribeRequest) returns (Subscription);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 7. File Storage Service
|
||
**Назначение**: Управление файлами и изображениями
|
||
|
||
**Ответственность**:
|
||
- Загрузка файлов в S3
|
||
- Генерация временных ссылок для скачивания
|
||
- Управление метаданными файлов
|
||
- Оптимизация изображений (resize, compress)
|
||
- Удаление файлов
|
||
|
||
**Хранилище**: AWS S3 / MinIO (S3-compatible)
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `files`, `file_metadata`
|
||
|
||
**REST API**:
|
||
- `POST /api/v1/files/upload` - загрузка файла
|
||
- `GET /api/v1/files/{id}` - получение метаданных
|
||
- `GET /api/v1/files/{id}/download` - генерация signed URL
|
||
- `DELETE /api/v1/files/{id}` - удаление файла
|
||
|
||
---
|
||
|
||
### 8. Audit Service
|
||
**Назначение**: Логирование всех действий в системе
|
||
|
||
**Ответственность**:
|
||
- Запись всех изменений в системе
|
||
- Хранение истории действий пользователей
|
||
- Предоставление API для просмотра логов
|
||
- Ретеншн политика (удаление старых логов)
|
||
|
||
**База данных**: PostgreSQL (с партиционированием по дате)
|
||
- Таблицы: `audit_log` (партиционирована)
|
||
|
||
**Kafka Topics**:
|
||
- Подписан на: `*.created`, `*.updated`, `*.deleted`, `tasks.*`, `users.*`
|
||
|
||
**Модель лога**:
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"timestamp": "2025-12-13T10:00:00Z",
|
||
"user_id": "uuid",
|
||
"hotel_id": "uuid",
|
||
"action": "task.created",
|
||
"entity_type": "task",
|
||
"entity_id": "uuid",
|
||
"changes": {
|
||
"before": {},
|
||
"after": {}
|
||
},
|
||
"ip_address": "192.168.1.1",
|
||
"user_agent": "Mozilla/5.0..."
|
||
}
|
||
```
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service AuditService {
|
||
rpc LogAction(LogActionRequest) returns (Empty);
|
||
rpc GetAuditLog(GetAuditLogRequest) returns (GetAuditLogResponse);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 9. Scheduler Service
|
||
**Назначение**: Управление периодическими задачами
|
||
|
||
**Ответственность**:
|
||
- Создание расписаний для задач (cron-подобный синтаксис)
|
||
- Триггеринг создания задач по расписанию
|
||
- Управление повторяющимися задачами
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `schedules`, `schedule_executions`
|
||
|
||
**Модель расписания**:
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"name": "Уборка холла каждый день в 8:00",
|
||
"cron_expression": "0 8 * * *",
|
||
"task_template": {
|
||
"title": "Уборка холла",
|
||
"description": "Провести уборку холла",
|
||
"task_type": "cleaning",
|
||
"assignee_id": "uuid"
|
||
},
|
||
"enabled": true,
|
||
"timezone": "Europe/Moscow",
|
||
"next_run": "2025-12-14T08:00:00Z"
|
||
}
|
||
```
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `scheduler.task_trigger`
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service SchedulerService {
|
||
rpc CreateSchedule(CreateScheduleRequest) returns (Schedule);
|
||
rpc UpdateSchedule(UpdateScheduleRequest) returns (Schedule);
|
||
rpc DeleteSchedule(DeleteScheduleRequest) returns (Empty);
|
||
rpc ListSchedules(ListSchedulesRequest) returns (ListSchedulesResponse);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 10. Events Service
|
||
**Назначение**: Управление мероприятиями (модуль Events Management)
|
||
|
||
**Ответственность**:
|
||
- Создание мероприятий
|
||
- Автоматическая генерация задач для разных подразделений
|
||
- Генерация документа "функшн"
|
||
- Управление конференц-залами и ресурсами
|
||
|
||
**База данных**: PostgreSQL
|
||
- Таблицы: `events`, `event_tasks`, `conference_rooms`, `event_resources`
|
||
|
||
**Модель мероприятия**:
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"title": "Конференция по маркетингу",
|
||
"description": "Описание мероприятия",
|
||
"start_time": "2025-12-20T10:00:00Z",
|
||
"end_time": "2025-12-20T18:00:00Z",
|
||
"conference_room_id": "uuid",
|
||
"tasks": [
|
||
{
|
||
"department": "housemen",
|
||
"title": "Расставить 50 стульев и 10 столов",
|
||
"due_before": "2025-12-20T09:00:00Z"
|
||
},
|
||
{
|
||
"department": "it",
|
||
"title": "Подготовить проектор и экран",
|
||
"due_before": "2025-12-20T09:30:00Z"
|
||
},
|
||
{
|
||
"department": "restaurant",
|
||
"title": "Организовать кофе-брейк на 50 человек",
|
||
"due_before": "2025-12-20T12:00:00Z"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `events.created`, `events.task_generated`
|
||
|
||
**gRPC Service**:
|
||
```protobuf
|
||
service EventService {
|
||
rpc CreateEvent(CreateEventRequest) returns (Event);
|
||
rpc UpdateEvent(UpdateEventRequest) returns (Event);
|
||
rpc GenerateTasks(GenerateTasksRequest) returns (GenerateTasksResponse);
|
||
rpc GenerateFunction(GenerateFunctionRequest) returns (FunctionDocument);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Adapter Layer (Адаптеры)
|
||
|
||
### Общая архитектура адаптера
|
||
|
||
Каждый адаптер - это отдельный микросервис, который:
|
||
1. Подключается к внешней системе (API, БД, Webhook endpoint)
|
||
2. Слушает Kafka топики для исходящих сообщений
|
||
3. Преобразует данные в/из стандартизированного формата
|
||
4. Публикует входящие сообщения в Kafka
|
||
|
||
**Базовая структура адаптера**:
|
||
```
|
||
adapter/
|
||
├── connector/ # Логика подключения к внешней системе
|
||
│ ├── api_client.py # REST/SOAP/GraphQL клиент
|
||
│ ├── db_client.py # Прямое подключение к БД (если требуется)
|
||
│ └── webhook.py # Обработчик входящих webhook'ов
|
||
├── transformer/ # Преобразование данных
|
||
│ ├── inbound.py # Внешний формат -> Стандартный формат
|
||
│ └── outbound.py # Стандартный формат -> Внешний формат
|
||
├── kafka/
|
||
│ ├── consumer.py # Обработка исходящих сообщений
|
||
│ └── producer.py # Публикация входящих сообщений
|
||
└── config.py # Конфигурация адаптера
|
||
```
|
||
|
||
### Примеры адаптеров
|
||
|
||
#### 1. PMS Adapter (например, Opera)
|
||
**Функции**:
|
||
- Получение информации о бронированиях
|
||
- Создание задач на основе заездов/выездов
|
||
- Обновление статуса номеров
|
||
|
||
**Режим работы**: Pull (опрос API) + Push (Webhook для событий)
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `adapters.pms.reservation_created`, `adapters.pms.checkout`
|
||
- Подписан на: `tasks.room_ready`, `tasks.room_cleaned`
|
||
|
||
---
|
||
|
||
#### 2. Housekeeping Adapter
|
||
**Функции**:
|
||
- Получение задач на уборку номеров
|
||
- Отправка статусов выполнения уборки
|
||
- Загрузка фото до/после уборки
|
||
|
||
**Режим работы**: Push (мобильное приложение отправляет данные)
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `adapters.housekeeping.task_started`, `adapters.housekeeping.task_completed`
|
||
- Подписан на: `tasks.cleaning_assigned`
|
||
|
||
---
|
||
|
||
#### 3. Telegram Bot Adapter
|
||
**Функции**:
|
||
- Прием запросов от гостей через Telegram
|
||
- Отправка уведомлений сотрудникам
|
||
- Интерактивные кнопки для частых запросов
|
||
|
||
**Режим работы**: Push (Telegram Webhook)
|
||
|
||
**Kafka Topics**:
|
||
- Публикует: `adapters.telegram.guest_request`
|
||
- Подписан на: `notifications.send`, `tasks.assigned`
|
||
|
||
---
|
||
|
||
## Модель данных
|
||
|
||
### Основные сущности
|
||
|
||
#### 1. Hotels (Отели)
|
||
```sql
|
||
CREATE TABLE hotels (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
name VARCHAR(255) NOT NULL,
|
||
address TEXT,
|
||
owner_id UUID NOT NULL, -- один владелец, несколько отелей
|
||
settings JSONB DEFAULT '{}',
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
#### 2. Departments (Подразделения)
|
||
```sql
|
||
CREATE TABLE departments (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
hotel_id UUID REFERENCES hotels(id),
|
||
name VARCHAR(255) NOT NULL,
|
||
type VARCHAR(50), -- housekeeping, technical, it, restaurant, etc.
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
#### 3. Users (Пользователи)
|
||
```sql
|
||
CREATE TABLE users (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
email VARCHAR(255) UNIQUE NOT NULL,
|
||
phone VARCHAR(50),
|
||
first_name VARCHAR(100),
|
||
last_name VARCHAR(100),
|
||
password_hash VARCHAR(255),
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE user_hotels (
|
||
user_id UUID REFERENCES users(id),
|
||
hotel_id UUID REFERENCES hotels(id),
|
||
department_id UUID REFERENCES departments(id),
|
||
PRIMARY KEY (user_id, hotel_id)
|
||
);
|
||
```
|
||
|
||
#### 4. Tasks (Задачи)
|
||
```sql
|
||
CREATE TABLE tasks (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
hotel_id UUID REFERENCES hotels(id),
|
||
title VARCHAR(500) NOT NULL,
|
||
description TEXT,
|
||
task_type VARCHAR(100), -- cleaning, maintenance, delivery, etc.
|
||
priority VARCHAR(20) DEFAULT 'normal', -- low, normal, high, urgent
|
||
status_id UUID REFERENCES task_statuses(id),
|
||
|
||
-- Исполнители
|
||
creator_id UUID REFERENCES users(id),
|
||
assignee_id UUID REFERENCES users(id),
|
||
department_id UUID REFERENCES departments(id),
|
||
|
||
-- Временные метки
|
||
due_date TIMESTAMP,
|
||
started_at TIMESTAMP,
|
||
completed_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW(),
|
||
|
||
-- Мета-информация
|
||
metadata JSONB DEFAULT '{}', -- для хранения дополнительных полей
|
||
source_system VARCHAR(100), -- откуда пришла задача
|
||
external_id VARCHAR(255) -- ID во внешней системе
|
||
);
|
||
|
||
CREATE INDEX idx_tasks_assignee ON tasks(assignee_id);
|
||
CREATE INDEX idx_tasks_hotel ON tasks(hotel_id);
|
||
CREATE INDEX idx_tasks_status ON tasks(status_id);
|
||
CREATE INDEX idx_tasks_created ON tasks(created_at);
|
||
```
|
||
|
||
#### 5. Task Statuses (Статусы задач)
|
||
```sql
|
||
CREATE TABLE task_statuses (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
hotel_id UUID REFERENCES hotels(id), -- NULL для глобальных статусов
|
||
name VARCHAR(100) NOT NULL,
|
||
code VARCHAR(50) NOT NULL, -- created, assigned, in_progress, completed, cancelled, rejected
|
||
is_final BOOLEAN DEFAULT FALSE, -- финальный статус (completed, cancelled)
|
||
color VARCHAR(7), -- HEX цвет для UI
|
||
order_index INT, -- порядок отображения
|
||
is_custom BOOLEAN DEFAULT FALSE, -- кастомный статус отеля
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- Предопределенные статусы
|
||
INSERT INTO task_statuses (name, code, is_final, order_index) VALUES
|
||
('Создана', 'created', FALSE, 1),
|
||
('Назначена', 'assigned', FALSE, 2),
|
||
('В работе', 'in_progress', FALSE, 3),
|
||
('Выполнена', 'completed', TRUE, 4),
|
||
('Отменена', 'cancelled', TRUE, 5),
|
||
('Отклонена', 'rejected', TRUE, 6);
|
||
```
|
||
|
||
#### 6. Task Dependencies (Зависимости задач)
|
||
```sql
|
||
CREATE TABLE task_dependencies (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
|
||
depends_on_task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
|
||
dependency_type VARCHAR(50) DEFAULT 'finish_to_start', -- finish_to_start, start_to_start
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
UNIQUE(task_id, depends_on_task_id)
|
||
);
|
||
```
|
||
|
||
#### 7. Task History (История изменений)
|
||
```sql
|
||
CREATE TABLE task_history (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
|
||
user_id UUID REFERENCES users(id),
|
||
action VARCHAR(100), -- created, status_changed, assigned, updated
|
||
changes JSONB, -- {"field": "status", "old": "created", "new": "in_progress"}
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE INDEX idx_task_history_task ON task_history(task_id, created_at DESC);
|
||
```
|
||
|
||
#### 8. Task Attachments (Вложения)
|
||
```sql
|
||
CREATE TABLE task_attachments (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
|
||
file_id UUID REFERENCES files(id),
|
||
attachment_type VARCHAR(50), -- photo_before, photo_after, document, voice
|
||
uploaded_by UUID REFERENCES users(id),
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
#### 9. Files (Файлы)
|
||
```sql
|
||
CREATE TABLE files (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
filename VARCHAR(500),
|
||
file_size BIGINT,
|
||
mime_type VARCHAR(100),
|
||
s3_bucket VARCHAR(255),
|
||
s3_key VARCHAR(500),
|
||
uploaded_by UUID REFERENCES users(id),
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
#### 10. Connections (Связи между адаптерами)
|
||
```sql
|
||
CREATE TABLE adapters (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
name VARCHAR(255) NOT NULL,
|
||
type VARCHAR(100), -- pms, erp, housekeeping, telegram, custom
|
||
config JSONB, -- конфигурация подключения
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE connections (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
source_adapter_id UUID REFERENCES adapters(id),
|
||
target_adapter_id UUID REFERENCES adapters(id),
|
||
routing_rules JSONB DEFAULT '[]', -- массив правил маршрутизации
|
||
is_enabled BOOLEAN DEFAULT TRUE,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
#### 11. Schedules (Расписания)
|
||
```sql
|
||
CREATE TABLE schedules (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
hotel_id UUID REFERENCES hotels(id),
|
||
name VARCHAR(255),
|
||
cron_expression VARCHAR(100), -- "0 8 * * *"
|
||
task_template JSONB, -- шаблон задачи для создания
|
||
timezone VARCHAR(50) DEFAULT 'UTC',
|
||
is_enabled BOOLEAN DEFAULT TRUE,
|
||
next_run TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE schedule_executions (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
schedule_id UUID REFERENCES schedules(id),
|
||
executed_at TIMESTAMP DEFAULT NOW(),
|
||
task_id UUID REFERENCES tasks(id), -- созданная задача
|
||
status VARCHAR(50) -- success, failed
|
||
);
|
||
```
|
||
|
||
#### 12. Roles & Permissions
|
||
```sql
|
||
CREATE TABLE roles (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
hotel_id UUID REFERENCES hotels(id), -- NULL для глобальных ролей
|
||
name VARCHAR(100) NOT NULL,
|
||
code VARCHAR(50), -- system_admin, support, hotel_admin, etc.
|
||
is_custom BOOLEAN DEFAULT FALSE,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE permissions (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
resource VARCHAR(100), -- tasks, users, connections, etc.
|
||
action VARCHAR(50), -- create, read, update, delete
|
||
description TEXT
|
||
);
|
||
|
||
CREATE TABLE role_permissions (
|
||
role_id UUID REFERENCES roles(id),
|
||
permission_id UUID REFERENCES permissions(id),
|
||
PRIMARY KEY (role_id, permission_id)
|
||
);
|
||
|
||
CREATE TABLE user_roles (
|
||
user_id UUID REFERENCES users(id),
|
||
role_id UUID REFERENCES roles(id),
|
||
hotel_id UUID REFERENCES hotels(id), -- в контексте какого отеля
|
||
PRIMARY KEY (user_id, role_id, hotel_id)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## Коммуникация между сервисами
|
||
|
||
### 1. Синхронная коммуникация (gRPC)
|
||
Используется для:
|
||
- Запросы на чтение (GET операции)
|
||
- Операции требующие немедленного ответа
|
||
- Проверка прав доступа
|
||
|
||
**Примеры**:
|
||
- API Gateway → Tasks Service: получение списка задач
|
||
- API Gateway → Users Service: получение профиля пользователя
|
||
- Tasks Service → Permissions Service: проверка прав доступа
|
||
|
||
### 2. Асинхронная коммуникация (Kafka)
|
||
Используется для:
|
||
- Операции записи (создание, обновление)
|
||
- Распространение событий
|
||
- Интеграция между сервисами
|
||
|
||
**Структура Kafka топиков**:
|
||
```
|
||
tasks.created # Создана новая задача
|
||
tasks.updated # Задача обновлена
|
||
tasks.status_changed # Изменен статус задачи
|
||
tasks.assigned # Задача назначена
|
||
tasks.completed # Задача выполнена
|
||
|
||
users.created
|
||
users.updated
|
||
users.deleted
|
||
|
||
connections.updated # Обновлены связи
|
||
connections.route_task # Маршрутизация задачи
|
||
|
||
notifications.send # Отправить уведомление
|
||
|
||
scheduler.task_trigger # Триггер для создания задачи по расписанию
|
||
|
||
adapters.*.message # Сообщения от адаптеров (подстановочные топики)
|
||
|
||
audit.* # Все события для аудита
|
||
```
|
||
|
||
### 3. REST API (для внешних клиентов)
|
||
Используется для:
|
||
- Web админка
|
||
- Мобильные приложения (если gRPC не поддерживается)
|
||
- Webhook endpoints для адаптеров
|
||
|
||
---
|
||
|
||
## Контракт сообщений
|
||
|
||
### Стандартизированное сообщение (Kafka Event)
|
||
|
||
```json
|
||
{
|
||
"event_id": "uuid",
|
||
"event_type": "task.created",
|
||
"timestamp": "2025-12-13T10:00:00Z",
|
||
"version": "1.0",
|
||
|
||
"source": {
|
||
"service": "tasks-service",
|
||
"adapter_id": "uuid",
|
||
"system": "pms_opera"
|
||
},
|
||
|
||
"target": {
|
||
"adapter_id": "uuid",
|
||
"system": "housekeeping_app"
|
||
},
|
||
|
||
"payload": {
|
||
"task": {
|
||
"id": "uuid",
|
||
"hotel_id": "uuid",
|
||
"title": "Уборка номера 305",
|
||
"description": "Гость выехал, требуется полная уборка",
|
||
"task_type": "cleaning",
|
||
"priority": "normal",
|
||
"status": "created",
|
||
|
||
"assignee": {
|
||
"id": "uuid",
|
||
"name": "Иванова Мария",
|
||
"department": "housekeeping"
|
||
},
|
||
|
||
"metadata": {
|
||
"room_number": "305",
|
||
"checkout_time": "2025-12-13T12:00:00Z",
|
||
"guest_name": "Петров А.А.",
|
||
"special_requirements": []
|
||
},
|
||
|
||
"due_date": "2025-12-13T14:00:00Z",
|
||
"created_at": "2025-12-13T10:00:00Z"
|
||
}
|
||
},
|
||
|
||
"correlation_id": "uuid", // для трейсинга
|
||
"causation_id": "uuid" // ID события, которое вызвало это событие
|
||
}
|
||
```
|
||
|
||
### Стандартизированное сообщение для адаптеров
|
||
|
||
Адаптеры преобразуют внешний формат в этот контракт:
|
||
|
||
```json
|
||
{
|
||
"message_id": "uuid",
|
||
"message_type": "task_create_request",
|
||
"timestamp": "2025-12-13T10:00:00Z",
|
||
|
||
"source_system": "pms_opera",
|
||
"target_system": "taskmanager",
|
||
|
||
"hotel_id": "uuid",
|
||
|
||
"data": {
|
||
"task": {
|
||
// стандартные поля задачи
|
||
}
|
||
},
|
||
|
||
"external_reference": {
|
||
"system": "pms_opera",
|
||
"id": "OPERA-12345",
|
||
"type": "reservation"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Безопасность и авторизация
|
||
|
||
### 1. Аутентификация
|
||
- **JWT токены** для API Gateway
|
||
- **mTLS** для межсервисной коммуникации (gRPC)
|
||
- **API Keys** для внешних систем (адаптеры)
|
||
|
||
### 2. Авторизация (RBAC)
|
||
Проверка прав на уровне:
|
||
- API Gateway (базовая проверка роли)
|
||
- Каждый сервис (детальная проверка permissions)
|
||
|
||
**Формат JWT токена**:
|
||
```json
|
||
{
|
||
"sub": "user_id",
|
||
"email": "user@example.com",
|
||
"hotels": ["hotel_id_1", "hotel_id_2"],
|
||
"roles": [
|
||
{
|
||
"hotel_id": "hotel_id_1",
|
||
"role": "hotel_admin"
|
||
}
|
||
],
|
||
"exp": 1234567890
|
||
}
|
||
```
|
||
|
||
### 3. Изоляция данных
|
||
- Все запросы фильтруются по `hotel_id` на уровне БД
|
||
- Row Level Security (RLS) в PostgreSQL
|
||
- Пользователи видят только данные отелей, к которым у них есть доступ
|
||
|
||
---
|
||
|
||
## Масштабирование
|
||
|
||
### 1. Horizontal Scaling
|
||
- Все сервисы stateless и могут масштабироваться горизонтально
|
||
- Kubernetes HPA (Horizontal Pod Autoscaler) на основе CPU/Memory
|
||
|
||
### 2. Database Scaling
|
||
- **Read Replicas** для PostgreSQL
|
||
- **Connection Pooling** (PgBouncer)
|
||
- **Партиционирование** для больших таблиц (audit_log, task_history)
|
||
|
||
### 3. Kafka Scaling
|
||
- Партиционирование топиков по `hotel_id`
|
||
- Consumer Groups для параллельной обработки
|
||
|
||
### 4. Caching
|
||
- **Redis** для кэширования:
|
||
- Данных пользователей
|
||
- Разрешений (permissions)
|
||
- Конфигурации связей (connections)
|
||
- Списков задач
|
||
|
||
---
|
||
|
||
## Технологический стек
|
||
|
||
### Backend Services
|
||
- **Язык**: Python 3.11+
|
||
- **Фреймворк**: FastAPI (для REST) + gRPC
|
||
- **ORM**: SQLAlchemy
|
||
- **Миграции БД**: Alembic
|
||
|
||
### Message Broker
|
||
- **Apache Kafka** (одиночный инстанс для MVP)
|
||
|
||
### Databases
|
||
- **PostgreSQL 15+** (основная БД)
|
||
- **Redis 7+** (кэш, сессии)
|
||
|
||
### File Storage
|
||
- **AWS S3** / MinIO (S3-compatible)
|
||
|
||
### API Gateway
|
||
- **Kong** / Envoy / NGINX + gRPC Gateway
|
||
|
||
### Frontend
|
||
- **Framework**: React 18+ с TypeScript
|
||
- **UI Library**: Material-UI / Ant Design
|
||
- **State Management**: Redux Toolkit / Zustand
|
||
- **API Client**: gRPC-Web
|
||
|
||
### Infrastructure
|
||
- **Containerization**: Docker
|
||
- **Orchestration**: Kubernetes
|
||
- **CI/CD**: GitLab CI / GitHub Actions
|
||
- **Monitoring**: Prometheus + Grafana
|
||
- **Logging**: ELK Stack (Elasticsearch, Logstash, Kibana) / Loki
|
||
- **Tracing**: Jaeger / OpenTelemetry
|
||
|
||
### Development Tools
|
||
- **API Documentation**: OpenAPI (Swagger) для REST, Buf для gRPC
|
||
- **Code Quality**: Ruff, Black, MyPy
|
||
- **Testing**: Pytest, pytest-asyncio
|
||
|
||
---
|
||
|
||
## Следующие шаги
|
||
|
||
1. Детальная проработка gRPC контрактов (.proto файлы)
|
||
2. Проектирование REST API спецификации (OpenAPI)
|
||
3. Разработка примера адаптера (PMS Adapter)
|
||
4. Проектирование UI/UX для Web админки
|
||
5. Настройка CI/CD pipeline
|
||
6. Разработка Docker Compose для локальной разработки
|
||
7. Kubernetes манифесты для деплоя
|
||
|